summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am85
-rw-r--r--src/cairo-arc-private.h57
-rw-r--r--src/cairo-arc.c296
-rw-r--r--src/cairo-array.c139
-rw-r--r--src/cairo-atsui-font.c1215
-rw-r--r--src/cairo-atsui.h8
-rw-r--r--src/cairo-cache.c11
-rw-r--r--src/cairo-color.c120
-rw-r--r--src/cairo-features.h.in24
-rw-r--r--src/cairo-font.c954
-rw-r--r--src/cairo-ft-font.c962
-rw-r--r--src/cairo-ft-private.h4
-rw-r--r--src/cairo-ft.h24
-rw-r--r--src/cairo-glitz-surface.c1106
-rw-r--r--src/cairo-glitz.h9
-rw-r--r--src/cairo-gstate-private.h80
-rw-r--r--src/cairo-gstate.c2118
-rw-r--r--src/cairo-hash.c11
-rw-r--r--src/cairo-image-surface.c142
-rw-r--r--src/cairo-matrix.c461
-rw-r--r--src/cairo-output-stream.c285
-rw-r--r--src/cairo-path-bounds.c16
-rw-r--r--src/cairo-path-data-private.h55
-rw-r--r--src/cairo-path-data.c422
-rw-r--r--src/cairo-path-fill.c20
-rw-r--r--src/cairo-path-fixed-private.h74
-rw-r--r--src/cairo-path-stroke.c34
-rw-r--r--src/cairo-path.c389
-rw-r--r--src/cairo-pattern.c449
-rw-r--r--src/cairo-pdf-surface.c1139
-rw-r--r--src/cairo-pdf.h33
-rw-r--r--src/cairo-pen.c6
-rw-r--r--src/cairo-png.c465
-rw-r--r--src/cairo-private.h51
-rw-r--r--src/cairo-ps-surface.c323
-rw-r--r--src/cairo-ps.h32
-rw-r--r--src/cairo-quartz-surface.c403
-rw-r--r--src/cairo-quartz.h11
-rw-r--r--src/cairo-surface.c589
-rw-r--r--src/cairo-traps.c99
-rw-r--r--src/cairo-unicode.c28
-rw-r--r--src/cairo-wideint.h12
-rw-r--r--src/cairo-win32-font.c602
-rw-r--r--src/cairo-win32-surface.c239
-rw-r--r--src/cairo-win32.h26
-rw-r--r--src/cairo-xcb-surface.c613
-rw-r--r--src/cairo-xcb-xrender.h (renamed from src/cairo_fixed.c)67
-rw-r--r--src/cairo-xcb.h27
-rw-r--r--src/cairo-xlib-surface.c770
-rw-r--r--src/cairo-xlib-test.h (renamed from src/cairo-png.h)27
-rw-r--r--src/cairo-xlib-xrender.h (renamed from src/cairo_color.c)69
-rw-r--r--src/cairo-xlib.h43
-rw-r--r--src/cairo.c1426
-rw-r--r--src/cairo.h862
-rw-r--r--src/cairo_array.c134
-rw-r--r--src/cairo_atsui_font.c807
-rw-r--r--src/cairo_cache.c518
-rw-r--r--src/cairo_font.c476
-rw-r--r--src/cairo_ft_font.c1538
-rw-r--r--src/cairo_glitz_surface.c1317
-rw-r--r--src/cairo_gstate.c2566
-rw-r--r--src/cairo_hull.c202
-rw-r--r--src/cairo_image_surface.c675
-rw-r--r--src/cairo_matrix.c645
-rw-r--r--src/cairo_path.c495
-rw-r--r--src/cairo_path_bounds.c182
-rw-r--r--src/cairo_path_fill.c206
-rw-r--r--src/cairo_path_stroke.c848
-rw-r--r--src/cairo_pattern.c1325
-rw-r--r--src/cairo_pdf_surface.c2222
-rw-r--r--src/cairo_pen.c587
-rw-r--r--src/cairo_png_surface.c425
-rw-r--r--src/cairo_polygon.c172
-rw-r--r--src/cairo_ps_surface.c443
-rw-r--r--src/cairo_quartz_surface.c392
-rw-r--r--src/cairo_slope.c103
-rw-r--r--src/cairo_spline.c288
-rw-r--r--src/cairo_surface.c708
-rw-r--r--src/cairo_traps.c740
-rw-r--r--src/cairo_unicode.c340
-rw-r--r--src/cairo_wideint.c1024
-rw-r--r--src/cairo_win32_font.c1252
-rw-r--r--src/cairo_win32_surface.c931
-rw-r--r--src/cairo_xcb_surface.c978
-rw-r--r--src/cairo_xlib_surface.c1530
-rw-r--r--src/cairoint.h1054
86 files changed, 11760 insertions, 30895 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 3f76d2726..8c624f247 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,56 +1,55 @@
if CAIRO_HAS_PS_SURFACE
libcairo_ps_headers = cairo-ps.h
-libcairo_ps_sources = cairo_ps_surface.c
+libcairo_ps_sources = cairo-ps-surface.c
endif
if CAIRO_HAS_PDF_SURFACE
libcairo_pdf_headers = cairo-pdf.h
-libcairo_pdf_sources = cairo_pdf_surface.c
+libcairo_pdf_sources = cairo-pdf-surface.c
endif
-if CAIRO_HAS_PNG_SURFACE
-libcairo_png_headers = cairo-png.h
-libcairo_png_sources = cairo_png_surface.c
+if CAIRO_HAS_PNG_FUNCTIONS
+libcairo_png_sources = cairo-png.c
endif
if CAIRO_HAS_XLIB_SURFACE
-libcairo_xlib_headers = cairo-xlib.h
-libcairo_xlib_sources = cairo_xlib_surface.c
+libcairo_xlib_headers = cairo-xlib.h cairo-xlib-xrender.h
+libcairo_xlib_sources = cairo-xlib-surface.c cairo-xlib-test.h
endif
if CAIRO_HAS_QUARTZ_SURFACE
libcairo_quartz_headers = cairo-quartz.h
-libcairo_quartz_sources = cairo_quartz_surface.c
+libcairo_quartz_sources = cairo-quartz-surface.c
endif
if CAIRO_HAS_XCB_SURFACE
-libcairo_xcb_headers = cairo-xcb.h
-libcairo_xcb_sources = cairo_xcb_surface.c
+libcairo_xcb_headers = cairo-xcb.h cairo-xcb-xrender.h
+libcairo_xcb_sources = cairo-xcb-surface.c
endif
libcairo_win32_sources =
if CAIRO_HAS_WIN32_SURFACE
libcairo_win32_headers = cairo-win32.h
-libcairo_win32_sources += cairo_win32_surface.c cairo-win32-private.h
+libcairo_win32_sources += cairo-win32-surface.c cairo-win32-private.h
endif
if CAIRO_HAS_WIN32_FONT
-libcairo_win32_sources += cairo_win32_font.c
+libcairo_win32_sources += cairo-win32-font.c
endif
if CAIRO_HAS_GLITZ_SURFACE
libcairo_glitz_headers = cairo-glitz.h
-libcairo_glitz_sources = cairo_glitz_surface.c
+libcairo_glitz_sources = cairo-glitz-surface.c
endif
if CAIRO_HAS_ATSUI_FONT
libcairo_atsui_headers = cairo-atsui.h
-libcairo_atsui_sources = cairo_atsui_font.c
+libcairo_atsui_sources = cairo-atsui-font.c
endif
if CAIRO_HAS_FT_FONT
libcairo_ft_headers = cairo-ft.h
-libcairo_ft_sources = cairo_ft_font.c cairo-ft-private.h
+libcairo_ft_sources = cairo-ft-font.c cairo-ft-private.h
endif
# These names match automake style variable definition conventions so
@@ -68,7 +67,6 @@ cairoinclude_HEADERS = \
$(libcairo_ft_headers) \
$(libcairo_glitz_headers) \
$(libcairo_pdf_headers) \
- $(libcairo_png_headers) \
$(libcairo_ps_headers) \
$(libcairo_quartz_headers) \
$(libcairo_win32_headers) \
@@ -80,28 +78,36 @@ lib_LTLIBRARIES = libcairo.la
libcairo_la_SOURCES = \
cairo.c \
cairo.h \
- cairo_array.c \
- cairo_cache.c \
- cairo_color.c \
- cairo_fixed.c \
- cairo_font.c \
- cairo_gstate.c \
- cairo_hull.c \
- cairo_image_surface.c \
- cairo_matrix.c \
- cairo_path.c \
- cairo_path_bounds.c \
- cairo_path_fill.c \
- cairo_path_stroke.c \
- cairo_pen.c \
- cairo_polygon.c \
- cairo_slope.c \
- cairo_spline.c \
- cairo_surface.c \
- cairo_traps.c \
- cairo_pattern.c \
- cairo_unicode.c \
- cairo_wideint.c \
+ cairo-private.h \
+ cairo-arc.c \
+ cairo-arc-private.h \
+ cairo-array.c \
+ cairo-cache.c \
+ cairo-color.c \
+ cairo-fixed.c \
+ cairo-font.c \
+ cairo-gstate.c \
+ cairo-gstate-private.h \
+ cairo-hull.c \
+ cairo-image-surface.c \
+ cairo-matrix.c \
+ cairo-path.c \
+ cairo-path-bounds.c \
+ cairo-path-data.c \
+ cairo-path-data-private.h \
+ cairo-path-fill.c \
+ cairo-path-fixed-private.h \
+ cairo-path-stroke.c \
+ cairo-pen.c \
+ cairo-polygon.c \
+ cairo-slope.c \
+ cairo-spline.c \
+ cairo-surface.c \
+ cairo-traps.c \
+ cairo-pattern.c \
+ cairo-unicode.c \
+ cairo-output-stream.c \
+ cairo-wideint.c \
cairo-wideint.h \
$(libcairo_atsui_sources)\
$(libcairo_ft_sources)\
@@ -113,7 +119,6 @@ libcairo_la_SOURCES = \
$(libcairo_xcb_sources) \
$(libcairo_glitz_sources)\
$(libcairo_win32_sources)\
- $(libcairo_freetype_sources) \
cairoint.h
libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined
@@ -123,7 +128,7 @@ INCLUDES = -I$(srcdir) $(CAIRO_CFLAGS)
libcairo_la_LIBADD = $(CAIRO_LIBS)
install-data-local:
- @if test -f $(includedir)/cairo.h || test -f $(includedir)/cairo-features.h ; then \
+ @if test -f "$(DESTDIR)$(includedir)/cairo.h" || test -f "$(DESTDIR)$(includedir)/cairo-features.h" ; then \
echo "****************************************************************" ; \
echo "*** Error: Old headers found. You should remove the following" ; \
echo "*** files and then type 'make install' again." ; \
diff --git a/src/cairo-arc-private.h b/src/cairo-arc-private.h
new file mode 100644
index 000000000..1cd41cc15
--- /dev/null
+++ b/src/cairo-arc-private.h
@@ -0,0 +1,57 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@redhat.com>
+ */
+
+#ifndef CAIRO_ARC_PRIVATE_H
+#define CAIRO_ARC_PRIVATE_H
+
+#include "cairoint.h"
+
+void
+_cairo_arc_path (cairo_t *cr,
+ double xc,
+ double yc,
+ double radius,
+ double angle1,
+ double angle2);
+
+void
+_cairo_arc_path_negative (cairo_t *cr,
+ double xc,
+ double yc,
+ double radius,
+ double angle1,
+ double angle2);
+
+#endif /* CAIRO_ARC_PRIVATE_H */
diff --git a/src/cairo-arc.c b/src/cairo-arc.c
new file mode 100644
index 000000000..d3302cdd5
--- /dev/null
+++ b/src/cairo-arc.c
@@ -0,0 +1,296 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ */
+
+#include <math.h>
+
+#include "cairo-arc-private.h"
+
+/* Spline deviation from the circle in radius would be given by:
+
+ error = sqrt (x**2 + y**2) - 1
+
+ A simpler error function to work with is:
+
+ e = x**2 + y**2 - 1
+
+ From "Good approximation of circles by curvature-continuous Bezier
+ curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric
+ Design 8 (1990) 22-41, we learn:
+
+ abs (max(e)) = 4/27 * sin**6(angle/4) / cos**2(angle/4)
+
+ and
+ abs (error) =~ 1/2 * e
+
+ Of course, this error value applies only for the particular spline
+ approximation that is used in _cairo_gstate_arc_segment.
+*/
+static double
+_arc_error_normalized (double angle)
+{
+ return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
+}
+
+static double
+_arc_max_angle_for_tolerance_normalized (double tolerance)
+{
+ double angle, error;
+ int i;
+
+ /* Use table lookup to reduce search time in most cases. */
+ struct {
+ double angle;
+ double error;
+ } table[] = {
+ { M_PI / 1.0, 0.0185185185185185036127 },
+ { M_PI / 2.0, 0.000272567143730179811158 },
+ { M_PI / 3.0, 2.38647043651461047433e-05 },
+ { M_PI / 4.0, 4.2455377443222443279e-06 },
+ { M_PI / 5.0, 1.11281001494389081528e-06 },
+ { M_PI / 6.0, 3.72662000942734705475e-07 },
+ { M_PI / 7.0, 1.47783685574284411325e-07 },
+ { M_PI / 8.0, 6.63240432022601149057e-08 },
+ { M_PI / 9.0, 3.2715520137536980553e-08 },
+ { M_PI / 10.0, 1.73863223499021216974e-08 },
+ { M_PI / 11.0, 9.81410988043554039085e-09 },
+ };
+ int table_size = (sizeof (table) / sizeof (table[0]));
+
+ for (i = 0; i < table_size; i++)
+ if (table[i].error < tolerance)
+ return table[i].angle;
+
+ ++i;
+ do {
+ angle = M_PI / i++;
+ error = _arc_error_normalized (angle);
+ } while (error > tolerance);
+
+ return angle;
+}
+
+static int
+_arc_segments_needed (double angle,
+ double radius,
+ cairo_matrix_t *ctm,
+ double tolerance)
+{
+ double l1, l2, lmax;
+ double max_angle;
+
+ _cairo_matrix_compute_eigen_values (ctm, &l1, &l2);
+
+ l1 = fabs (l1);
+ l2 = fabs (l2);
+ if (l1 > l2)
+ lmax = l1;
+ else
+ lmax = l2;
+
+ max_angle = _arc_max_angle_for_tolerance_normalized (tolerance / (radius * lmax));
+
+ return (int) ceil (angle / max_angle);
+}
+
+/* We want to draw a single spline approximating a circular arc radius
+ R from angle A to angle B. Since we want a symmetric spline that
+ matches the endpoints of the arc in position and slope, we know
+ that the spline control points must be:
+
+ (R * cos(A), R * sin(A))
+ (R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
+ (R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
+ (R * cos(B), R * sin(B))
+
+ for some value of h.
+
+ "Approximation of circular arcs by cubic poynomials", Michael
+ Goldapp, Computer Aided Geometric Design 8 (1991) 227-238, provides
+ various values of h along with error analysis for each.
+
+ From that paper, a very practical value of h is:
+
+ h = 4/3 * tan(angle/4)
+
+ This value does not give the spline with minimal error, but it does
+ provide a very good approximation, (6th-order convergence), and the
+ error expression is quite simple, (see the comment for
+ _arc_error_normalized).
+*/
+static void
+_cairo_arc_segment (cairo_t *cr,
+ double xc,
+ double yc,
+ double radius,
+ double angle_A,
+ double angle_B)
+{
+ double r_sin_A, r_cos_A;
+ double r_sin_B, r_cos_B;
+ double h;
+
+ r_sin_A = radius * sin (angle_A);
+ r_cos_A = radius * cos (angle_A);
+ r_sin_B = radius * sin (angle_B);
+ r_cos_B = radius * cos (angle_B);
+
+ h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
+
+ cairo_curve_to (cr,
+ xc + r_cos_A - h * r_sin_A,
+ yc + r_sin_A + h * r_cos_A,
+ xc + r_cos_B + h * r_sin_B,
+ yc + r_sin_B - h * r_cos_B,
+ xc + r_cos_B,
+ yc + r_sin_B);
+}
+
+static void
+_cairo_arc_in_direction (cairo_t *cr,
+ double xc,
+ double yc,
+ double radius,
+ double angle_min,
+ double angle_max,
+ cairo_direction_t dir)
+{
+ while (angle_max - angle_min > 4 * M_PI)
+ angle_max -= 2 * M_PI;
+
+ /* Recurse if drawing arc larger than pi */
+ if (angle_max - angle_min > M_PI) {
+ double angle_mid = angle_min + (angle_max - angle_min) / 2.0;
+ /* XXX: Something tells me this block could be condensed. */
+ if (dir == CAIRO_DIRECTION_FORWARD) {
+ _cairo_arc_in_direction (cr, xc, yc, radius,
+ angle_min, angle_mid,
+ dir);
+
+ _cairo_arc_in_direction (cr, xc, yc, radius,
+ angle_mid, angle_max,
+ dir);
+ } else {
+ _cairo_arc_in_direction (cr, xc, yc, radius,
+ angle_mid, angle_max,
+ dir);
+
+ _cairo_arc_in_direction (cr, xc, yc, radius,
+ angle_min, angle_mid,
+ dir);
+ }
+ } else {
+ cairo_matrix_t ctm;
+ int i, segments;
+ double angle, angle_step;
+
+ cairo_get_matrix (cr, &ctm);
+ segments = _arc_segments_needed (angle_max - angle_min,
+ radius, &ctm,
+ cairo_get_tolerance (cr));
+ angle_step = (angle_max - angle_min) / (double) segments;
+
+ if (dir == CAIRO_DIRECTION_FORWARD) {
+ angle = angle_min;
+ } else {
+ angle = angle_max;
+ angle_step = - angle_step;
+ }
+
+ for (i = 0; i < segments; i++, angle += angle_step) {
+ _cairo_arc_segment (cr, xc, yc,
+ radius,
+ angle,
+ angle + angle_step);
+ }
+ }
+}
+
+/**
+ * _cairo_arc_path_negative:
+ * @cr: a cairo context
+ * @xc: X position of the center of the arc
+ * @yc: Y position of the center of the arc
+ * @radius: the radius of the arc
+ * @angle1: the start angle, in radians
+ * @angle2: the end angle, in radians
+ *
+ * Compute a path for the given arc and append it onto the current
+ * path within @cr. The arc will be accurate within the current
+ * tolerance and given the current transformation.
+ **/
+void
+_cairo_arc_path (cairo_t *cr,
+ double xc,
+ double yc,
+ double radius,
+ double angle1,
+ double angle2)
+{
+ _cairo_arc_in_direction (cr, xc, yc,
+ radius,
+ angle1, angle2,
+ CAIRO_DIRECTION_FORWARD);
+}
+
+/**
+ * _cairo_arc_path_negative:
+ * @xc: X position of the center of the arc
+ * @yc: Y position of the center of the arc
+ * @radius: the radius of the arc
+ * @angle1: the start angle, in radians
+ * @angle2: the end angle, in radians
+ * @ctm: the current transformation matrix
+ * @tolerance: the current tolerance value
+ * @path: the path onto which th earc will be appended
+ *
+ * Compute a path for the given arc (defined in the negative
+ * direction) and append it onto the current path within @cr. The arc
+ * will be accurate within the current tolerance and given the current
+ * transformation.
+ **/
+void
+_cairo_arc_path_negative (cairo_t *cr,
+ double xc,
+ double yc,
+ double radius,
+ double angle1,
+ double angle2)
+{
+ _cairo_arc_in_direction (cr, xc, yc,
+ radius,
+ angle2, angle1,
+ CAIRO_DIRECTION_REVERSE);
+}
diff --git a/src/cairo-array.c b/src/cairo-array.c
index 2b1cf9d61..a37ea9af5 100644
--- a/src/cairo-array.c
+++ b/src/cairo-array.c
@@ -132,3 +132,142 @@ _cairo_array_num_elements (cairo_array_t *array)
{
return array->num_elements;
}
+
+/* cairo_user_data_array_t */
+
+typedef struct {
+ const cairo_user_data_key_t *key;
+ void *user_data;
+ cairo_destroy_func_t destroy;
+} cairo_user_data_slot_t;
+
+/**
+ * _cairo_user_data_array_init:
+ * @array: a #cairo_user_data_array_t
+ *
+ * Initializes a #cairo_user_data_array_t structure for future
+ * use. After initialization, the array has no keys. Call
+ * _cairo_user_data_array_destroy() to free any allocated memory
+ * when done using the array.
+ **/
+void
+_cairo_user_data_array_init (cairo_user_data_array_t *array)
+{
+ _cairo_array_init (array, sizeof (cairo_user_data_slot_t));
+}
+
+/**
+ * _cairo_user_data_array_destroy:
+ * @array: a #cairo_user_data_array_t
+ *
+ * Destroys all current keys in the user data array and deallocates
+ * any memory allocated for the array itself.
+ **/
+void
+_cairo_user_data_array_destroy (cairo_user_data_array_t *array)
+{
+ int i, num_slots;
+ cairo_user_data_slot_t *slots;
+
+ num_slots = array->num_elements;
+ slots = (cairo_user_data_slot_t *) array->elements;
+ for (i = 0; i < num_slots; i++) {
+ if (slots[i].user_data != NULL && slots[i].destroy != NULL)
+ slots[i].destroy (slots[i].user_data);
+ }
+
+ _cairo_array_fini (array);
+}
+
+/**
+ * _cairo_user_data_array_get_data:
+ * @array: a #cairo_user_data_array_t
+ * @key: the address of the #cairo_user_data_key_t the user data was
+ * attached to
+ *
+ * Returns user data previously attached using the specified
+ * key. If no user data has been attached with the given key this
+ * function returns %NULL.
+ *
+ * Return value: the user data previously attached or %NULL.
+ **/
+void *
+_cairo_user_data_array_get_data (cairo_user_data_array_t *array,
+ const cairo_user_data_key_t *key)
+{
+ int i, num_slots;
+ cairo_user_data_slot_t *slots;
+
+ num_slots = array->num_elements;
+ slots = (cairo_user_data_slot_t *) array->elements;
+ for (i = 0; i < num_slots; i++) {
+ if (slots[i].key == key)
+ return slots[i].user_data;
+ }
+
+ return NULL;
+}
+
+/**
+ * _cairo_user_data_array_set_data:
+ * @array: a #cairo_user_data_array_t
+ * @key: the address of a #cairo_user_data_key_t to attach the user data to
+ * @user_data: the user data to attach
+ * @destroy: a #cairo_destroy_func_t which will be called when the
+ * user data array is destroyed or when new user data is attached using the
+ * same key.
+ *
+ * Attaches user data to a user data array. To remove user data,
+ * call this function with the key that was used to set it and %NULL
+ * for @data.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
+ * slot could not be allocated for the user data.
+ **/
+cairo_status_t
+_cairo_user_data_array_set_data (cairo_user_data_array_t *array,
+ const cairo_user_data_key_t *key,
+ void *user_data,
+ cairo_destroy_func_t destroy)
+{
+ int i, num_slots;
+ cairo_user_data_slot_t *slots, *s;
+
+ s = NULL;
+ num_slots = array->num_elements;
+ slots = (cairo_user_data_slot_t *) array->elements;
+ for (i = 0; i < num_slots; i++) {
+ if (slots[i].key == key) {
+ if (slots[i].user_data != NULL && slots[i].destroy != NULL)
+ slots[i].destroy (slots[i].user_data);
+ s = &slots[i];
+ break;
+ }
+ if (user_data && slots[i].user_data == NULL) {
+ s = &slots[i]; /* Have to keep searching for an exact match */
+ }
+ }
+
+ if (user_data == NULL) {
+ if (s != NULL) {
+ s->key = NULL;
+ s->user_data = NULL;
+ s->destroy = NULL;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+
+ } else {
+ if (s == NULL)
+ s = _cairo_array_append (array, NULL, 1);
+ if (s == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ s->key = key;
+ s->user_data = user_data;
+ s->destroy = destroy;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
diff --git a/src/cairo-atsui-font.c b/src/cairo-atsui-font.c
index cb4b1c5d7..a279956df 100644
--- a/src/cairo-atsui-font.c
+++ b/src/cairo-atsui-font.c
@@ -30,778 +30,661 @@
* The Initial Developer of the Original Code is Calum Robinson
*
* Contributor(s):
- * Calum Robinson <calumr@mac.com>
+ * Calum Robinson <calumr@mac.com>
*/
#include <stdlib.h>
#include <math.h>
-
#include "cairo-atsui.h"
#include "cairoint.h"
+#include "cairo.h"
+#include <iconv.h>
+typedef struct {
+ cairo_scaled_font_t base;
+ cairo_matrix_t scale;
+ ATSUStyle style;
+ ATSUStyle unscaled_style;
+ ATSUFontID fontID;
+} cairo_atsui_font_t;
+typedef struct cairo_ATSUI_glyph_path_callback_info_t {
+ cairo_path_fixed_t *path;
+ cairo_matrix_t scale;
+} cairo_ATSUI_glyph_path_callback_info_t;
+const cairo_scaled_font_backend_t cairo_atsui_scaled_font_backend;
-#pragma mark Types
+static CGAffineTransform
+CGAffineTransformMakeWithCairoFontScale(cairo_matrix_t *scale)
+{
+ return CGAffineTransformMake(scale->xx, scale->yx,
+ scale->xy, scale->yy,
+ 0, 0);
+}
+static ATSUStyle
+CreateSizedCopyOfStyle(ATSUStyle inStyle, cairo_matrix_t *scale)
+{
+ ATSUStyle style;
+ OSStatus err;
-typedef struct {
- cairo_unscaled_font_t base;
-
- ATSUStyle style;
- ATSUFontID fontID;
-} cairo_atsui_font_t;
+ // Set the style's size
+ CGAffineTransform theTransform =
+ CGAffineTransformMakeWithCairoFontScale(scale);
+ Fixed theSize =
+ FloatToFixed(CGSizeApplyAffineTransform
+ (CGSizeMake(1.0, 1.0), theTransform).height);
+ const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag };
+ const ByteCount theFontStyleSizes[] = { sizeof(Fixed) };
+ ATSUAttributeValuePtr theFontStyleValues[] = { &theSize };
+ err = ATSUCreateAndCopyStyle(inStyle, &style);
-typedef struct cairo_ATSUI_glyph_path_callback_info_t {
- cairo_path_t *path;
- cairo_matrix_t scale;
-} cairo_ATSUI_glyph_path_callback_info_t;
+ err = ATSUSetAttributes(style,
+ sizeof(theFontStyleTags) /
+ sizeof(ATSUAttributeTag), theFontStyleTags,
+ theFontStyleSizes, theFontStyleValues);
+ return style;
+}
+static cairo_status_t
+_cairo_atsui_font_create(const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ cairo_scaled_font_t **font_out)
+{
+ cairo_atsui_font_t *font = NULL;
+ ATSUStyle style;
+ ATSUFontID fontID;
+ OSStatus err;
+ Boolean isItalic, isBold;
+ cairo_matrix_t scale;
+
+ err = ATSUCreateStyle(&style);
+
+
+ switch (weight) {
+ case CAIRO_FONT_WEIGHT_BOLD:
+ isBold = true;
+ break;
+ case CAIRO_FONT_WEIGHT_NORMAL:
+ default:
+ isBold = false;
+ break;
+ }
+
+ switch (slant) {
+ case CAIRO_FONT_SLANT_ITALIC:
+ isItalic = true;
+ break;
+ case CAIRO_FONT_SLANT_OBLIQUE:
+ isItalic = false;
+ break;
+ case CAIRO_FONT_SLANT_NORMAL:
+ default:
+ isItalic = false;
+ break;
+ }
+
+ err = ATSUFindFontFromName(family, strlen(family),
+ kFontFamilyName,
+ kFontNoPlatformCode,
+ kFontRomanScript,
+ kFontNoLanguageCode, &fontID);
+
+ if (err != noErr) {
+ // couldn't get the font - remap css names and try again
+
+ if (!strcmp(family, "serif"))
+ family = "Times";
+ else if (!strcmp(family, "sans-serif"))
+ family = "Helvetica";
+ else if (!strcmp(family, "cursive"))
+ family = "Apple Chancery";
+ else if (!strcmp(family, "fantasy"))
+ family = "Gadget";
+ else if (!strcmp(family, "monospace"))
+ family = "Courier";
+ else // anything else - return error instead?
+ family = "Courier";
+
+ err = ATSUFindFontFromName(family, strlen(family),
+ kFontFamilyName,
+ kFontNoPlatformCode,
+ kFontRomanScript,
+ kFontNoLanguageCode, &fontID);
+ }
+
+
+ ATSUAttributeTag styleTags[] =
+ { kATSUQDItalicTag, kATSUQDBoldfaceTag, kATSUFontTag };
+ ATSUAttributeValuePtr styleValues[] = { &isItalic, &isBold, &fontID };
+ ByteCount styleSizes[] =
+ { sizeof(Boolean), sizeof(Boolean), sizeof(ATSUFontID) };
+
+
+ err = ATSUSetAttributes(style,
+ sizeof(styleTags) / sizeof(styleTags[0]),
+ styleTags, styleSizes, styleValues);
+
+ font = malloc(sizeof(cairo_atsui_font_t));
+
+ _cairo_scaled_font_init(&font->base, font_matrix, ctm,
+ &cairo_atsui_scaled_font_backend);
+
+ cairo_matrix_multiply(&scale, font_matrix, ctm);
+ font->style = CreateSizedCopyOfStyle(style, &scale);
+
+ Fixed theSize = FloatToFixed(1.0);
+ const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag };
+ const ByteCount theFontStyleSizes[] = { sizeof(Fixed) };
+ ATSUAttributeValuePtr theFontStyleValues[] = { &theSize };
+ err = ATSUSetAttributes(style,
+ sizeof(theFontStyleTags) /
+ sizeof(ATSUAttributeTag), theFontStyleTags,
+ theFontStyleSizes, theFontStyleValues);
+
+ font->unscaled_style = style;
+
+ font->fontID = fontID;
+ font->scale = scale;
+
+ *font_out = &font->base;
+
+ return CAIRO_STATUS_SUCCESS;
+}
-#pragma mark Private Functions
+static void
+_cairo_atsui_font_destroy_font(void *abstract_font)
+{
+ cairo_atsui_font_t *font = abstract_font;
+ if (font == NULL)
+ return;
+ if (font->style)
+ ATSUDisposeStyle(font->style);
+ if (font->unscaled_style)
+ ATSUDisposeStyle(font->unscaled_style);
+}
-static CGAffineTransform CGAffineTransformMakeWithCairoFontScale(cairo_font_scale_t scale)
+static void
+_cairo_atsui_font_get_glyph_cache_key(void *abstract_font,
+ cairo_glyph_cache_key_t *key)
{
- return CGAffineTransformMake( scale.matrix[0][0], scale.matrix[0][1],
- scale.matrix[1][0], scale.matrix[1][1],
- 0, 0);
}
-static ATSUStyle CreateSizedCopyOfStyle(ATSUStyle inStyle, cairo_font_scale_t *scale)
+static cairo_status_t
+_cairo_atsui_font_text_to_glyphs(void *abstract_font,
+ const char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs)
{
- ATSUStyle style;
- OSStatus err;
-
-
- // Set the style's size
- CGAffineTransform theTransform = CGAffineTransformMakeWithCairoFontScale(*scale);
- Fixed theSize = FloatToFixed(CGSizeApplyAffineTransform(CGSizeMake(1.0, 1.0), theTransform).height);
- const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag };
- const ByteCount theFontStyleSizes[] = { sizeof(Fixed) };
- ATSUAttributeValuePtr theFontStyleValues[] = { &theSize };
-
- err = ATSUCreateAndCopyStyle(inStyle, &style);
-
- err = ATSUSetAttributes( style,
- sizeof(theFontStyleTags) / sizeof(ATSUAttributeTag),
- theFontStyleTags, theFontStyleSizes, theFontStyleValues);
-
-
- return style;
-}
+ cairo_atsui_font_t *font = abstract_font;
+ size_t i;
+ OSStatus err;
+ ATSUTextLayout textLayout;
+ ATSLayoutRecord *layoutRecords;
+ ItemCount glyphCount, charCount;
+ UniChar *theText;
+ err = ATSUCreateTextLayout(&textLayout);
+#if 1
+ charCount = strlen(utf8);
+ // Set the text in the text layout object, so we can measure it
+ theText = (UniChar *) malloc(charCount * sizeof(UniChar));
+ for (i = 0; i < charCount; i++) {
+ theText[i] = utf8[i];
+ }
+#endif
-#pragma mark Public Functions
+#if 0
+ // Set the text in the text layout object, so we can measure it
+ charCount = strlen(utf8);
+ theText = (UniChar *) malloc(charCount * sizeof(UniChar));
+ size_t inBytes = charCount, outBytes = charCount;
+ iconv_t converter = iconv_open("UTF-8", "UTF-16");
+ charCount = iconv(converter, utf8, &inBytes, theText, &outBytes);
+#endif
+ err = ATSUSetTextPointerLocation(textLayout,
+ theText, 0, charCount, charCount);
+ // Set the style for all of the text
+ err = ATSUSetRunStyle(textLayout,
+ font->unscaled_style, kATSUFromTextBeginning, kATSUToTextEnd);
-static cairo_unscaled_font_t *
-_cairo_atsui_font_create( const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight)
-{
- cairo_atsui_font_t *font = NULL;
- ATSUStyle style;
- ATSUFontID fontID;
- OSStatus err;
- Boolean isItalic, isBold;
-
-
- err = ATSUCreateStyle(&style);
-
-
- switch (weight)
- {
- case CAIRO_FONT_WEIGHT_BOLD:
- isBold = true;
- break;
- case CAIRO_FONT_WEIGHT_NORMAL:
- default:
- isBold = false;
- break;
- }
-
- switch (slant)
- {
- case CAIRO_FONT_SLANT_ITALIC:
- isItalic = true;
- break;
- case CAIRO_FONT_SLANT_OBLIQUE:
- isItalic = false;
- break;
- case CAIRO_FONT_SLANT_NORMAL:
- default:
- isItalic = false;
- break;
- }
-
- err = ATSUFindFontFromName( family, strlen(family),
- kFontFamilyName,
- kFontNoPlatformCode,
- kFontRomanScript,
- kFontNoLanguageCode,
- &fontID);
-
-
- ATSUAttributeTag styleTags[] = {kATSUQDItalicTag, kATSUQDBoldfaceTag, kATSUFontTag};
- ATSUAttributeValuePtr styleValues[] = {&isItalic, &isBold, &fontID};
- ByteCount styleSizes[] = {sizeof(Boolean), sizeof(Boolean), sizeof(ATSUFontID)};
-
-
- err = ATSUSetAttributes( style,
- sizeof(styleTags) / sizeof(styleTags[0]),
- styleTags,
- styleSizes,
- styleValues);
-
-
-
- font = malloc(sizeof(cairo_atsui_font_t));
-
- if (_cairo_unscaled_font_init(&font->base, &cairo_atsui_font_backend) == CAIRO_STATUS_SUCCESS)
- {
- font->style = style;
- font->fontID = fontID;
-
-
- return &font->base;
- }
-
-
- free(font);
-
- return NULL;
-}
+ // Get the glyphs from the text layout object
+ err = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout,
+ 0,
+ kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
+ (void *)
+ &layoutRecords,
+ &glyphCount);
+ *num_glyphs = glyphCount - 1;
-static void
-_cairo_atsui_font_destroy(void *abstract_font)
-{
- cairo_atsui_font_t *font = abstract_font;
-
-
- if (font == NULL)
- return;
-
- if (font->style)
- ATSUDisposeStyle(font->style);
-
- free(font);
-}
+ *glyphs =
+ (cairo_glyph_t *) malloc(*num_glyphs * (sizeof(cairo_glyph_t)));
+ if (*glyphs == NULL) {
+ return CAIRO_STATUS_NO_MEMORY;
+ }
-static cairo_status_t
-_cairo_atsui_font_text_to_glyphs( void *abstract_font,
- cairo_font_scale_t *sc,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *nglyphs)
-{
- cairo_atsui_font_t *font = abstract_font;
- size_t i;
- OSStatus err;
- ATSUTextLayout textLayout;
- ATSLayoutRecord *layoutRecords;
- ItemCount glyphCount, charCount;
- UniChar *theText;
- ATSUStyle style;
-
-
- charCount = strlen(utf8);
-
-
- err = ATSUCreateTextLayout(&textLayout);
-
-
- // Set the text in the text layout object, so we can measure it
- theText = (UniChar *)malloc(charCount * sizeof(UniChar));
-
- for (i = 0; i < charCount; i++)
- {
- theText[i] = utf8[i];
- }
-
- err = ATSUSetTextPointerLocation( textLayout,
- theText,
- 0,
- charCount,
- charCount);
-
-
- style = CreateSizedCopyOfStyle(font->style, sc);
-
-
- // Set the style for all of the text
- err = ATSUSetRunStyle( textLayout,
- style,
- kATSUFromTextBeginning,
- kATSUToTextEnd);
-
-
-
- // Get the glyphs from the text layout object
- err = ATSUDirectGetLayoutDataArrayPtrFromTextLayout( textLayout,
- 0,
- kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
- (void *)&layoutRecords,
- &glyphCount);
-
- *nglyphs = glyphCount;
-
-
- *glyphs = (cairo_glyph_t *)malloc(glyphCount * (sizeof(cairo_glyph_t)));
- if (*glyphs == NULL)
- {
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- for (i = 0; i < glyphCount; i++)
- {
- (*glyphs)[i].index = layoutRecords[i].glyphID;
- (*glyphs)[i].x = FixedToFloat(layoutRecords[i].realPos);
- (*glyphs)[i].y = 0;
- }
-
-
- free(theText);
-
- ATSUDirectReleaseLayoutDataArrayPtr( NULL,
- kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
- (void *)&layoutRecords);
-
- ATSUDisposeTextLayout(textLayout);
-
- ATSUDisposeStyle(style);
-
-
- return CAIRO_STATUS_SUCCESS;
+ for (i = 0; i < *num_glyphs; i++) {
+ (*glyphs)[i].index = layoutRecords[i].glyphID;
+ (*glyphs)[i].x = FixedToFloat(layoutRecords[i].realPos);
+ (*glyphs)[i].y = 0;
+ }
+
+
+ free(theText);
+
+ ATSUDirectReleaseLayoutDataArrayPtr(NULL,
+ kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
+ (void *) &layoutRecords);
+
+ ATSUDisposeTextLayout(textLayout);
+
+ return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_atsui_font_font_extents( void *abstract_font,
- cairo_font_scale_t *sc,
- cairo_font_extents_t *extents)
+static cairo_status_t
+_cairo_atsui_font_font_extents(void *abstract_font,
+ cairo_font_extents_t * extents)
{
- cairo_atsui_font_t *font = abstract_font;
- ATSFontRef atsFont;
- ATSFontMetrics metrics;
- OSStatus err;
-
-
- // TODO - test this
-
- atsFont = FMGetATSFontRefFromFont(font->fontID);
-
- if (atsFont)
- {
- err = ATSFontGetHorizontalMetrics(atsFont, kATSOptionFlagsDefault, &metrics);
-
- if (err == noErr)
- {
- extents->ascent = metrics.ascent;
- extents->descent = metrics.descent;
- extents->height = metrics.capHeight;
- extents->max_x_advance = metrics.maxAdvanceWidth;
-
- // The FT backend doesn't handle max_y_advance either, so we'll ignore it for now.
- extents->max_y_advance = 0.0;
-
-
- return CAIRO_STATUS_SUCCESS;
- }
- }
-
-
- return CAIRO_STATUS_NULL_POINTER;
+ cairo_atsui_font_t *font = abstract_font;
+ ATSFontRef atsFont;
+ ATSFontMetrics metrics;
+ OSStatus err;
+
+ // TODO - test this
+
+ atsFont = FMGetATSFontRefFromFont(font->fontID);
+
+ if (atsFont) {
+ err =
+ ATSFontGetHorizontalMetrics(atsFont, kATSOptionFlagsDefault,
+ &metrics);
+
+ if (err == noErr) {
+ extents->ascent = metrics.ascent;
+ extents->descent = metrics.descent;
+ extents->height = metrics.capHeight;
+ extents->max_x_advance = metrics.maxAdvanceWidth;
+
+ // The FT backend doesn't handle max_y_advance either, so we'll ignore it for now.
+ extents->max_y_advance = 0.0;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
+
+ return CAIRO_STATUS_NULL_POINTER;
}
-static cairo_status_t
-_cairo_atsui_font_glyph_extents( void *abstract_font,
- cairo_font_scale_t *sc,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
+static cairo_status_t
+_cairo_atsui_font_glyph_extents(void *abstract_font,
+ cairo_glyph_t * glyphs,
+ int num_glyphs,
+ cairo_text_extents_t * extents)
{
- cairo_atsui_font_t *font = abstract_font;
- cairo_point_double_t origin;
- cairo_point_double_t glyph_min, glyph_max;
- cairo_point_double_t total_min, total_max;
- OSStatus err;
- ATSUStyle style;
- int i;
-
-
- if (num_glyphs == 0)
- {
- extents->x_bearing = 0.0;
- extents->y_bearing = 0.0;
- extents->width = 0.0;
- extents->height = 0.0;
- extents->x_advance = 0.0;
- extents->y_advance = 0.0;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- origin.x = glyphs[0].x;
- origin.y = glyphs[0].y;
-
-
- style = CreateSizedCopyOfStyle(font->style, sc);
-
-
- for (i = 0; i < num_glyphs; i++)
- {
- GlyphID theGlyph = glyphs[i].index;
- double minX, maxX, ascent, descent;
- ATSGlyphIdealMetrics metricsH, metricsV;
-
-
- err = ATSUGlyphGetIdealMetrics( style,
- 1,
- &theGlyph,
- 0,
- &metricsH);
-
-
- ATSUVerticalCharacterType verticalType = kATSUStronglyVertical;
- ATSUAttributeTag theTag = kATSUVerticalCharacterTag;
- ByteCount theSize = sizeof(ATSUVerticalCharacterType);
-
- err = ATSUSetAttributes(style, 1, &theTag, &theSize, (ATSUAttributeValuePtr)&verticalType);
-
- err = ATSUGlyphGetIdealMetrics( style,
- 1,
- &theGlyph,
- 0,
- &metricsV);
-
- minX = metricsH.otherSideBearing.x;
- maxX = metricsH.advance.x;
-
- ascent = metricsV.advance.x;
- descent = metricsV.otherSideBearing.x;
-
- glyph_min.x = glyphs[i].x + minX;
- glyph_min.y = glyphs[i].y + descent;
- glyph_max.x = glyphs[i].x + maxX;
- glyph_max.y = glyphs[i].y + ascent;
-
- if (i==0)
- {
- total_min = glyph_min;
- total_max = glyph_max;
- }
- else
- {
- if (glyph_min.x < total_min.x)
- total_min.x = glyph_min.x;
- if (glyph_min.y < total_min.y)
- total_min.y = glyph_min.y;
-
- if (glyph_max.x > total_max.x)
- total_max.x = glyph_max.x;
- if (glyph_max.y > total_max.y)
- total_max.y = glyph_max.y;
- }
- }
-
-
- extents->x_bearing = total_min.x - origin.x;
- extents->y_bearing = total_min.y - origin.y;
- extents->width = total_max.x - total_min.x;
- extents->height = total_max.y - total_min.y;
- extents->x_advance = glyphs[i-1].x - origin.x;
- extents->y_advance = glyphs[i-1].y - origin.y;
-
-
- return CAIRO_STATUS_SUCCESS;
+ cairo_atsui_font_t *font = abstract_font;
+ OSStatus err;
+
+ assert(num_glyphs == 1);
+
+ GlyphID theGlyph = glyphs[0].index;
+
+ ATSGlyphIdealMetrics metricsH, metricsV;
+ ATSUStyle style;
+
+ ATSUCreateAndCopyStyle(font->unscaled_style, &style);
+
+ err = ATSUGlyphGetIdealMetrics(style,
+ 1, &theGlyph, 0, &metricsH);
+
+ ATSUVerticalCharacterType verticalType = kATSUStronglyVertical;
+ const ATSUAttributeTag theTag[] = { kATSUVerticalCharacterTag };
+ const ByteCount theSizes[] = { sizeof(verticalType) };
+ ATSUAttributeValuePtr theValues[] = { &verticalType };
+
+ err = ATSUSetAttributes(style, 1, theTag, theSizes, theValues);
+
+ err = ATSUGlyphGetIdealMetrics(style,
+ 1, &theGlyph, 0, &metricsV);
+
+ extents->x_bearing = metricsH.sideBearing.x;
+ extents->y_bearing = metricsV.advance.y;
+ extents->width =
+ metricsH.advance.x - metricsH.sideBearing.x - metricsH.otherSideBearing.x;
+ extents->height =
+ -metricsV.advance.y - metricsV.sideBearing.y - metricsV.otherSideBearing.y;
+ extents->x_advance = metricsH.advance.x;
+ extents->y_advance = 0;
+
+ ATSUDisposeStyle(style);
+
+ return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_atsui_font_glyph_bbox( void *abstract_font,
- cairo_font_scale_t *sc,
- const cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox)
+static cairo_status_t
+_cairo_atsui_font_glyph_bbox(void *abstract_font,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs, cairo_box_t *bbox)
{
- cairo_atsui_font_t *font = abstract_font;
- cairo_fixed_t x1, y1, x2, y2;
- int i;
- OSStatus err;
- ATSUStyle style;
-
-
- bbox->p1.x = bbox->p1.y = CAIRO_MAXSHORT << 16;
- bbox->p2.x = bbox->p2.y = CAIRO_MINSHORT << 16;
-
-
- style = CreateSizedCopyOfStyle(font->style, sc);
-
-
- for (i = 0; i < num_glyphs; i++)
- {
- GlyphID theGlyph = glyphs[i].index;
- ATSGlyphIdealMetrics metrics;
-
-
- err = ATSUGlyphGetIdealMetrics( style,
- 1,
- &theGlyph,
- 0,
- &metrics);
-
- x1 = _cairo_fixed_from_double(glyphs[i].x);
- y1 = _cairo_fixed_from_double(glyphs[i].y);
- x2 = x1 + _cairo_fixed_from_double(metrics.advance.x);
- y2 = y1 + _cairo_fixed_from_double(metrics.advance.y);
-
- if (x1 < bbox->p1.x)
- bbox->p1.x = x1;
-
- if (y1 < bbox->p1.y)
- bbox->p1.y = y1;
-
- if (x2 > bbox->p2.x)
- bbox->p2.x = x2;
-
- if (y2 > bbox->p2.y)
- bbox->p2.y = y2;
- }
-
-
- ATSUDisposeStyle(style);
-
-
- return CAIRO_STATUS_SUCCESS;
+ cairo_atsui_font_t *font = abstract_font;
+ cairo_fixed_t x1, y1, x2, y2;
+ int i;
+
+ bbox->p1.x = bbox->p1.y = CAIRO_MAXSHORT << 16;
+ bbox->p2.x = bbox->p2.y = CAIRO_MINSHORT << 16;
+
+
+ for (i = 0; i < num_glyphs; i++) {
+ GlyphID theGlyph = glyphs[i].index;
+
+ ATSGlyphScreenMetrics metrics;
+ ATSUGlyphGetScreenMetrics(font->style,
+ 1, &theGlyph, 0, true, true, &metrics);
+
+ x1 = _cairo_fixed_from_double(glyphs[i].x + metrics.topLeft.x);
+ y1 = _cairo_fixed_from_double(glyphs[i].y - metrics.topLeft.y);
+ x2 = x1 + _cairo_fixed_from_double(metrics.height);
+ y2 = y1 + _cairo_fixed_from_double(metrics.width);
+
+ if (x1 < bbox->p1.x)
+ bbox->p1.x = x1;
+
+ if (y1 < bbox->p1.y)
+ bbox->p1.y = y1;
+
+ if (x2 > bbox->p2.x)
+ bbox->p2.x = x2;
+
+ if (y2 > bbox->p2.y)
+ bbox->p2.y = y2;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_atsui_font_show_glyphs( void *abstract_font,
- cairo_font_scale_t *sc,
- cairo_operator_t operator,
- cairo_surface_t *source,
- cairo_surface_t *surface,
- int source_x,
- int source_y,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
+static cairo_status_t
+_cairo_atsui_font_show_glyphs(void *abstract_font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *generic_surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
{
- cairo_atsui_font_t *font = abstract_font;
- CGContextRef myBitmapContext;
- CGColorSpaceRef colorSpace;
- cairo_image_surface_t *destImageSurface;
- int i;
-
-
- destImageSurface = _cairo_surface_get_image(surface);
-
-
- // Create a CGBitmapContext for the dest surface for drawing into
+ cairo_atsui_font_t *font = abstract_font;
+ CGContextRef myBitmapContext;
+ CGColorSpaceRef colorSpace;
+ cairo_image_surface_t *destImageSurface;
+ int i;
+
+ cairo_rectangle_t rect = {dest_x, dest_y, width, height};
+ _cairo_surface_acquire_dest_image(generic_surface,
+ &rect,
+ &destImageSurface,
+ &rect,
+ NULL);
+
+ // Create a CGBitmapContext for the dest surface for drawing into
colorSpace = CGColorSpaceCreateDeviceRGB();
-
- myBitmapContext = CGBitmapContextCreate( destImageSurface->data,
- destImageSurface->width,
- destImageSurface->height,
- destImageSurface->depth / 4,
- destImageSurface->stride,
- colorSpace,
- kCGImageAlphaPremultipliedFirst);
-
-
- ATSFontRef atsFont = FMGetATSFontRefFromFont(font->fontID);
- CGFontRef cgFont = CGFontCreateWithPlatformFont(&atsFont);
-
- CGContextSetFont(myBitmapContext, cgFont);
-
-
- CGAffineTransform textTransform = CGAffineTransformMakeWithCairoFontScale(*sc);
- CGSize textSize = CGSizeMake(1.0, 1.0);
-
- textSize = CGSizeApplyAffineTransform(textSize, textTransform);
-
- CGContextSetFontSize(myBitmapContext, textSize.width);
-
-
- // TODO - bold and italic text
- //
- // We could draw the text using ATSUI and get bold, italics
- // etc. for free, but ATSUI does a lot of text layout work
- // that we don't really need...
-
-
- for (i = 0; i < num_glyphs; i++)
- {
- CGGlyph theGlyph = glyphs[i].index;
-
- CGContextShowGlyphsAtPoint(myBitmapContext, source_x + glyphs[i].x, destImageSurface->height - (source_y + glyphs[i].y), &theGlyph, 1);
- }
-
-
- CGColorSpaceRelease(colorSpace);
- CGContextRelease(myBitmapContext);
-
-
- return CAIRO_STATUS_SUCCESS;
-}
+ myBitmapContext = CGBitmapContextCreate(destImageSurface->data,
+ destImageSurface->width,
+ destImageSurface->height,
+ destImageSurface->depth / 4,
+ destImageSurface->stride,
+ colorSpace,
+ kCGImageAlphaPremultipliedFirst);
+ CGContextTranslateCTM(myBitmapContext, 0, destImageSurface->height);
+ CGContextScaleCTM(myBitmapContext, 1.0f, -1.0f);
+
+ ATSFontRef atsFont = FMGetATSFontRefFromFont(font->fontID);
+ CGFontRef cgFont = CGFontCreateWithPlatformFont(&atsFont);
+
+ CGContextSetFont(myBitmapContext, cgFont);
+
+ CGAffineTransform textTransform =
+ CGAffineTransformMakeWithCairoFontScale(&font->scale);
+
+ textTransform = CGAffineTransformScale(textTransform, 1.0f, -1.0f);
+
+ CGContextSetFontSize(myBitmapContext, 1.0);
+ CGContextSetTextMatrix(myBitmapContext, textTransform);
+
+ if (pattern->type == CAIRO_PATTERN_SOLID &&
+ _cairo_pattern_is_opaque_solid(pattern)) {
+ cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *)pattern;
+ CGContextSetRGBFillColor(myBitmapContext,
+ solid->color.red,
+ solid->color.green,
+ solid->color.blue, 1.0f);
+ } else
+ CGContextSetRGBFillColor(myBitmapContext, 0.0f, 0.0f, 0.0f, 0.0f);
+
+ // TODO - bold and italic text
+ //
+ // We could draw the text using ATSUI and get bold, italics
+ // etc. for free, but ATSUI does a lot of text layout work
+ // that we don't really need...
+
+
+ for (i = 0; i < num_glyphs; i++) {
+ CGGlyph theGlyph = glyphs[i].index;
+
+ CGContextShowGlyphsAtPoint(myBitmapContext,
+ glyphs[i].x,
+ glyphs[i].y,
+ &theGlyph, 1);
+ }
+
+
+ CGColorSpaceRelease(colorSpace);
+ CGContextRelease(myBitmapContext);
-#pragma mark -
+ _cairo_surface_release_dest_image(generic_surface,
+ &rect,
+ destImageSurface,
+ &rect,
+ NULL);
+
+ return CAIRO_STATUS_SUCCESS;
+}
-static OSStatus MyATSCubicMoveToCallback(const Float32Point *pt, void *callBackDataPtr)
+static OSStatus MyATSCubicMoveToCallback(const Float32Point * pt,
+ void *callBackDataPtr)
{
- cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
- double scaledPt[2];
- cairo_point_t point;
-
-
- scaledPt[0] = pt->x;
- scaledPt[1] = pt->y;
-
- cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
-
- point.x = _cairo_fixed_from_double(scaledPt[0]);
- point.y = _cairo_fixed_from_double(scaledPt[1]);
-
- _cairo_path_move_to(info->path, &point);
-
-
+ cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
+ double scaledPt[2];
+ cairo_fixed_t x, y;
+
+ scaledPt[0] = pt->x;
+ scaledPt[1] = pt->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ x = _cairo_fixed_from_double(scaledPt[0]);
+ y = _cairo_fixed_from_double(scaledPt[1]);
+
+ _cairo_path_fixed_close_path(info->path);
+ _cairo_path_fixed_move_to(info->path, x, y);
+
return noErr;
}
-static OSStatus MyATSCubicLineToCallback(const Float32Point *pt, void *callBackDataPtr)
+static OSStatus MyATSCubicLineToCallback(const Float32Point * pt,
+ void *callBackDataPtr)
{
- cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
- cairo_point_t point;
- double scaledPt[2];
-
-
- scaledPt[0] = pt->x;
- scaledPt[1] = pt->y;
-
- cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
-
- point.x = _cairo_fixed_from_double(scaledPt[0]);
- point.y = _cairo_fixed_from_double(scaledPt[1]);
-
- _cairo_path_line_to(info->path, &point);
-
-
- return noErr;
+ cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
+ double scaledPt[2];
+ cairo_fixed_t x, y;
+
+ scaledPt[0] = pt->x;
+ scaledPt[1] = pt->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ x = _cairo_fixed_from_double(scaledPt[0]);
+ y = _cairo_fixed_from_double(scaledPt[1]);
+
+ _cairo_path_fixed_line_to(info->path, x, y);
+
+
+ return noErr;
}
-static OSStatus MyATSCubicCurveToCallback( const Float32Point *pt1,
- const Float32Point *pt2,
- const Float32Point *pt3,
- void *callBackDataPtr)
+static OSStatus MyATSCubicCurveToCallback(const Float32Point * pt1,
+ const Float32Point * pt2,
+ const Float32Point * pt3,
+ void *callBackDataPtr)
{
- cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
- cairo_point_t p0, p1, p2;
- double scaledPt[2];
-
-
- scaledPt[0] = pt1->x;
- scaledPt[1] = pt1->y;
-
- cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
-
- p0.x = _cairo_fixed_from_double(scaledPt[0]);
- p0.y = _cairo_fixed_from_double(scaledPt[1]);
-
+ cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
+ double scaledPt[2];
+ cairo_fixed_t x0, y0;
+ cairo_fixed_t x1, y1;
+ cairo_fixed_t x2, y2;
+
+
+ scaledPt[0] = pt1->x;
+ scaledPt[1] = pt1->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ x0 = _cairo_fixed_from_double(scaledPt[0]);
+ y0 = _cairo_fixed_from_double(scaledPt[1]);
+
scaledPt[0] = pt2->x;
- scaledPt[1] = pt2->y;
-
- cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+ scaledPt[1] = pt2->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ x1 = _cairo_fixed_from_double(scaledPt[0]);
+ y1 = _cairo_fixed_from_double(scaledPt[1]);
- p1.x = _cairo_fixed_from_double(scaledPt[0]);
- p1.y = _cairo_fixed_from_double(scaledPt[1]);
-
scaledPt[0] = pt3->x;
- scaledPt[1] = pt3->y;
-
- cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+ scaledPt[1] = pt3->y;
- p2.x = _cairo_fixed_from_double(scaledPt[0]);
- p2.y = _cairo_fixed_from_double(scaledPt[1]);
-
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
- _cairo_path_curve_to(info->path, &p0, &p1, &p2);
-
-
- return noErr;
-}
+ x2 = _cairo_fixed_from_double(scaledPt[0]);
+ y2 = _cairo_fixed_from_double(scaledPt[1]);
-static OSStatus MyCubicClosePathProc(void * callBackDataPtr)
-{
- cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
-
-
- _cairo_path_close_path(info->path);
-
-
- return noErr;
+ _cairo_path_fixed_curve_to(info->path, x0, y0, x1, y1, x2, y2);
+
+
+ return noErr;
}
-static cairo_status_t
-_cairo_atsui_font_glyph_path( void *abstract_font,
- cairo_font_scale_t *sc,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path)
+static OSStatus MyCubicClosePathProc(void *callBackDataPtr)
{
- int i;
- cairo_atsui_font_t *font = abstract_font;
- OSStatus err;
- cairo_ATSUI_glyph_path_callback_info_t info;
- ATSUStyle style;
-
-
- static ATSCubicMoveToUPP moveProc = NULL;
- static ATSCubicLineToUPP lineProc = NULL;
- static ATSCubicCurveToUPP curveProc = NULL;
- static ATSCubicClosePathUPP closePathProc = NULL;
-
-
- if (moveProc == NULL)
- {
- moveProc = NewATSCubicMoveToUPP(MyATSCubicMoveToCallback);
- lineProc = NewATSCubicLineToUPP(MyATSCubicLineToCallback);
- curveProc = NewATSCubicCurveToUPP(MyATSCubicCurveToCallback);
- closePathProc = NewATSCubicClosePathUPP(MyCubicClosePathProc);
- }
-
-
- info.path = path;
-
-
- style = CreateSizedCopyOfStyle(font->style, sc);
-
-
- for (i = 0; i < num_glyphs; i++)
- {
- GlyphID theGlyph = glyphs[i].index;
-
-
- cairo_matrix_set_affine( &info.scale,
- 1.0, 0.0,
- 0.0, 1.0,
- glyphs[i].x, glyphs[i].y);
-
-
- err = ATSUGlyphGetCubicPaths( style,
- theGlyph,
- moveProc,
- lineProc,
- curveProc,
- closePathProc,
- (void *)&info,
- &err);
- }
-
-
- err = ATSUDisposeStyle(style);
-
-
- return CAIRO_STATUS_SUCCESS;
-}
+ cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
-#pragma mark -
+ _cairo_path_fixed_close_path(info->path);
-static cairo_status_t
-_cairo_atsui_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
-{
- // TODO
- printf("_cairo_atsui_font_create_glyph is unimplemented\n");
-
- // I'm not sure if we need this, given that the ATSUI backend does no caching(?)
-
-
- return CAIRO_STATUS_SUCCESS;
+ return noErr;
}
-cairo_font_t *
-cairo_atsui_font_create(ATSUStyle style)
-{
- cairo_font_scale_t scale;
- cairo_font_t *scaled;
- cairo_atsui_font_t *f = NULL;
-
-
- scaled = malloc(sizeof(cairo_font_t));
- if (scaled == NULL)
- return NULL;
-
-
- f = malloc(sizeof(cairo_atsui_font_t));
- if (f)
- {
- if (_cairo_unscaled_font_init(&f->base, &cairo_atsui_font_backend) == CAIRO_STATUS_SUCCESS)
- {
- f->style = style;
-
- _cairo_font_init(scaled, &scale, &f->base);
-
- return scaled;
- }
- }
-
-
- free(scaled);
-
-
- return NULL;
-}
+static cairo_status_t
+_cairo_atsui_font_glyph_path(void *abstract_font,
+ cairo_glyph_t *glyphs, int num_glyphs,
+ cairo_path_fixed_t *path)
+{
+ int i;
+ cairo_atsui_font_t *font = abstract_font;
+ OSStatus err;
+ cairo_ATSUI_glyph_path_callback_info_t info;
+ static ATSCubicMoveToUPP moveProc = NULL;
+ static ATSCubicLineToUPP lineProc = NULL;
+ static ATSCubicCurveToUPP curveProc = NULL;
+ static ATSCubicClosePathUPP closePathProc = NULL;
+ if (moveProc == NULL) {
+ moveProc = NewATSCubicMoveToUPP(MyATSCubicMoveToCallback);
+ lineProc = NewATSCubicLineToUPP(MyATSCubicLineToCallback);
+ curveProc = NewATSCubicCurveToUPP(MyATSCubicCurveToCallback);
+ closePathProc = NewATSCubicClosePathUPP(MyCubicClosePathProc);
+ }
-#pragma mark Backend
+ info.path = path;
+ for (i = 0; i < num_glyphs; i++) {
+ GlyphID theGlyph = glyphs[i].index;
-const cairo_font_backend_t cairo_atsui_font_backend = {
- _cairo_atsui_font_create,
- _cairo_atsui_font_destroy,
- _cairo_atsui_font_font_extents,
- _cairo_atsui_font_text_to_glyphs,
- _cairo_atsui_font_glyph_extents,
- _cairo_atsui_font_glyph_bbox,
- _cairo_atsui_font_show_glyphs,
- _cairo_atsui_font_glyph_path,
- _cairo_atsui_font_create_glyph
+ cairo_matrix_init(&info.scale,
+ 1.0, 0.0,
+ 0.0, 1.0, glyphs[i].x, glyphs[i].y);
+
+
+ err = ATSUGlyphGetCubicPaths(font->style,
+ theGlyph,
+ moveProc,
+ lineProc,
+ curveProc,
+ closePathProc, (void *) &info, &err);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+const cairo_scaled_font_backend_t cairo_atsui_scaled_font_backend = {
+ _cairo_atsui_font_create,
+ _cairo_atsui_font_destroy_font,
+ _cairo_atsui_font_font_extents,
+ _cairo_atsui_font_text_to_glyphs,
+ _cairo_atsui_font_glyph_extents,
+ _cairo_atsui_font_glyph_bbox,
+ _cairo_atsui_font_show_glyphs,
+ _cairo_atsui_font_glyph_path,
+ _cairo_atsui_font_get_glyph_cache_key,
};
+
diff --git a/src/cairo-atsui.h b/src/cairo-atsui.h
index a5b7308f8..72e2d6d15 100644
--- a/src/cairo-atsui.h
+++ b/src/cairo-atsui.h
@@ -38,7 +38,7 @@
#include <cairo.h>
-#ifdef CAIRO_HAS_ATSUI_FONT
+#if CAIRO_HAS_ATSUI_FONT
/* ATSUI platform-specific font interface */
@@ -46,10 +46,10 @@
CAIRO_BEGIN_DECLS
-cairo_font_t *
-cairo_atsui_font_create(ATSUStyle style);
-
CAIRO_END_DECLS
+#else /* CAIRO_HAS_ATSUI_FONT */
+# error Cairo was not compiled with support for the atsui font backend
#endif /* CAIRO_HAS_ATSUI_FONT */
+
#endif /* CAIRO_ATSUI_H */
diff --git a/src/cairo-cache.c b/src/cairo-cache.c
index d1ad5a4e2..e95894960 100644
--- a/src/cairo-cache.c
+++ b/src/cairo-cache.c
@@ -113,7 +113,9 @@ static const cairo_cache_arrangement_t cache_arrangements [] = {
#define LIVE_ENTRY_P(cache, i) \
(!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i)))))
-#ifdef CAIRO_DO_SANITY_CHECKING
+#ifdef NDEBUG
+#define _cache_sane_state(c)
+#else
static void
_cache_sane_state (cairo_cache_t *cache)
{
@@ -125,8 +127,6 @@ _cache_sane_state (cairo_cache_t *cache)
/* assert (cache->used_memory <= cache->max_memory); */
assert (cache->live_entries <= cache->arrangement->size);
}
-#else
-#define _cache_sane_state(c)
#endif
static void
@@ -351,8 +351,9 @@ _cairo_cache_init (cairo_cache_t *cache,
#endif
cache->backend = backend;
- cache->entries = calloc (sizeof(cairo_cache_entry_base_t *),
- cache->arrangement->size);
+ cache->entries = calloc (cache->arrangement->size,
+ sizeof(cairo_cache_entry_base_t *));
+
if (cache->entries == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
diff --git a/src/cairo-color.c b/src/cairo-color.c
index f203d96cc..beb4a3474 100644
--- a/src/cairo-color.c
+++ b/src/cairo-color.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -36,62 +37,127 @@
#include "cairoint.h"
-static cairo_color_t const CAIRO_COLOR_WHITE = {
- 1.0, 1.0, 1.0, 1.0,
+static cairo_color_t const cairo_color_white = {
+ 1.0, 1.0, 1.0, 1.0,
0xffff, 0xffff, 0xffff, 0xffff
};
-static void
-_cairo_color_compute_shorts (cairo_color_t *color);
+static cairo_color_t const cairo_color_black = {
+ 0.0, 0.0, 0.0, 1.0,
+ 0x0, 0x0, 0x0, 0xffff
+};
+
+static cairo_color_t const cairo_color_transparent = {
+ 0.0, 0.0, 0.0, 0.0,
+ 0x0, 0x0, 0x0, 0x0
+};
+
+static cairo_color_t const cairo_color_magenta = {
+ 1.0, 0.0, 1.0, 1.0,
+ 0xffff, 0x0, 0xffff, 0xffff
+};
+
+const cairo_color_t *
+_cairo_stock_color (cairo_stock_t stock)
+{
+ switch (stock) {
+ case CAIRO_STOCK_WHITE:
+ return &cairo_color_white;
+ case CAIRO_STOCK_BLACK:
+ return &cairo_color_black;
+ case CAIRO_STOCK_TRANSPARENT:
+ return &cairo_color_transparent;
+ }
+
+ ASSERT_NOT_REACHED;
+
+ /* If the user can get here somehow, give a color that indicates a
+ * problem. */
+ return &cairo_color_magenta;
+}
void
_cairo_color_init (cairo_color_t *color)
{
- *color = CAIRO_COLOR_WHITE;
+ *color = cairo_color_white;
}
void
-_cairo_color_fini (cairo_color_t *color)
+_cairo_color_init_rgb (cairo_color_t *color,
+ double red, double green, double blue)
{
- /* Nothing to do here */
+ _cairo_color_init_rgba (color, red, green, blue, 1.0);
+}
+
+
+/* XXX: The calculation of:
+
+ channel * 0xffff
+
+ isn't really what we want since:
+
+ (1.0 - epsilon) * 0xffff = 0xfffe
+
+ In other words, given an input range of [0.0, 1.0], we have an
+ infinitely small range tha maps to the output value 0xffff,
+ (while having large, uniformly sized input ranges for all
+ other output values). This is undesirable, particularly when
+ we want to do optimizations for "opaque" colors specfied as
+ floating-point.
+*/
+static void
+_cairo_color_compute_shorts (cairo_color_t *color)
+{
+ color->red_short = color->red * color->alpha * 0xffff;
+ color->green_short = color->green * color->alpha * 0xffff;
+ color->blue_short = color->blue * color->alpha * 0xffff;
+ color->alpha_short = color->alpha * 0xffff;
}
void
-_cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blue)
+_cairo_color_init_rgba (cairo_color_t *color,
+ double red, double green, double blue,
+ double alpha)
{
color->red = red;
color->green = green;
color->blue = blue;
+ color->alpha = alpha;
_cairo_color_compute_shorts (color);
}
void
-_cairo_color_get_rgb (const cairo_color_t *color,
- double *red, double *green, double *blue)
+_cairo_color_multiply_alpha (cairo_color_t *color,
+ double alpha)
{
- if (red)
- *red = color->red;
- if (green)
- *green = color->green;
- if (blue)
- *blue = color->blue;
+ color->alpha *= alpha;
+
+ _cairo_color_compute_shorts (color);
}
void
-_cairo_color_set_alpha (cairo_color_t *color, double alpha)
+_cairo_color_get_rgba (cairo_color_t *color,
+ double *red,
+ double *green,
+ double *blue,
+ double *alpha)
{
- color->alpha = alpha;
-
- _cairo_color_compute_shorts (color);
+ *red = color->red;
+ *green = color->green;
+ *blue = color->blue;
+ *alpha = color->alpha;
}
-static void
-_cairo_color_compute_shorts (cairo_color_t *color)
+void
+_cairo_color_get_rgba_premultiplied (cairo_color_t *color,
+ double *red,
+ double *green,
+ double *blue,
+ double *alpha)
{
- color->red_short = (color->red * color->alpha) * 0xffff;
- color->green_short = (color->green * color->alpha) * 0xffff;
- color->blue_short = (color->blue * color->alpha) * 0xffff;
- color->alpha_short = color->alpha * 0xffff;
+ *red = color->red * color->alpha;
+ *green = color->green * color->alpha;
+ *blue = color->blue * color->alpha;
+ *alpha = color->alpha;
}
-
diff --git a/src/cairo-features.h.in b/src/cairo-features.h.in
index a13250d97..8065be352 100644
--- a/src/cairo-features.h.in
+++ b/src/cairo-features.h.in
@@ -37,28 +37,26 @@
#ifndef CAIRO_FEATURES_H
#define CAIRO_FEATURES_H
-#define @PS_SURFACE_FEATURE@
+@PS_SURFACE_FEATURE@
-#define @PDF_SURFACE_FEATURE@
+@PDF_SURFACE_FEATURE@
-#define @PNG_SURFACE_FEATURE@
+@XLIB_SURFACE_FEATURE@
-#define @XLIB_SURFACE_FEATURE@
+@QUARTZ_SURFACE_FEATURE@
-#define @QUARTZ_SURFACE_FEATURE@
+@XCB_SURFACE_FEATURE@
-#define @XCB_SURFACE_FEATURE@
+@WIN32_SURFACE_FEATURE@
-#define @WIN32_SURFACE_FEATURE@
+@GLITZ_SURFACE_FEATURE@
-#define @GLITZ_SURFACE_FEATURE@
+@FT_FONT_FEATURE@
-#define @FT_FONT_FEATURE@
+@WIN32_FONT_FEATURE@
-#define @WIN32_FONT_FEATURE@
+@ATSUI_FONT_FEATURE@
-#define @ATSUI_FONT_FEATURE@
-
-#define @SANITY_CHECKING_FEATURE@
+@PNG_FUNCTIONS_FEATURE@
#endif
diff --git a/src/cairo-font.c b/src/cairo-font.c
index 529c1c7c3..3bd1e0318 100644
--- a/src/cairo-font.c
+++ b/src/cairo-font.c
@@ -39,185 +39,906 @@
#include "cairoint.h"
-/* Now the internal "unscaled + scale" font API */
+/* cairo_font_face_t */
-cairo_private cairo_status_t
-_cairo_font_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight,
- cairo_font_scale_t *sc,
- cairo_font_t **font)
+void
+_cairo_font_face_init (cairo_font_face_t *font_face,
+ const cairo_font_face_backend_t *backend)
{
- const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
+ font_face->refcount = 1;
+ font_face->backend = backend;
- return backend->create (family, slant, weight, sc, font);
+ _cairo_user_data_array_init (&font_face->user_data);
}
+/**
+ * cairo_font_face_reference:
+ * @font_face: a #cairo_font_face_t
+ *
+ * Increases the reference count on @font_face by one. This prevents
+ * @font_face from being destroyed until a matching call to cairo_font_face_destroy()
+ * is made.
+ **/
void
-_cairo_font_init (cairo_font_t *font,
- cairo_font_scale_t *scale,
- const cairo_font_backend_t *backend)
+cairo_font_face_reference (cairo_font_face_t *font_face)
{
- font->scale = *scale;
- font->refcount = 1;
- font->backend = backend;
+ font_face->refcount++;
}
+/**
+ * cairo_font_face_destroy:
+ * @font_face: a #cairo_font_face_t
+ *
+ * Decreases the reference count on @font_face by one. If the result
+ * is zero, then @font_face and all associated resources are freed.
+ * See cairo_font_face_reference().
+ **/
void
-_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
- const cairo_font_backend_t *backend)
+cairo_font_face_destroy (cairo_font_face_t *font_face)
{
- font->refcount = 1;
- font->backend = backend;
+ if (--(font_face->refcount) > 0)
+ return;
+
+ font_face->backend->destroy (font_face);
+
+ /* We allow resurrection to deal with some memory management for the
+ * FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t
+ * need to effectively mutually reference each other
+ */
+ if (font_face->refcount > 0)
+ return;
+
+ _cairo_user_data_array_destroy (&font_face->user_data);
+
+ free (font_face);
}
+/**
+ * cairo_font_face_get_user_data:
+ * @font_face: a #cairo_font_face_t
+ * @key: the address of the #cairo_user_data_key_t the user data was
+ * attached to
+ *
+ * Return user data previously attached to @font_face using the specified
+ * key. If no user data has been attached with the given key this
+ * function returns %NULL.
+ *
+ * Return value: the user data previously attached or %NULL.
+ **/
+void *
+cairo_font_face_get_user_data (cairo_font_face_t *font_face,
+ const cairo_user_data_key_t *key)
+{
+ return _cairo_user_data_array_get_data (&font_face->user_data,
+ key);
+}
+
+/**
+ * cairo_font_face_set_user_data:
+ * @font_face: a #cairo_font_face_t
+ * @key: the address of a #cairo_user_data_key_t to attach the user data to
+ * @user_data: the user data to attach to the font face
+ * @destroy: a #cairo_destroy_func_t which will be called when the
+ * font face is destroyed or when new user data is attached using the
+ * same key.
+ *
+ * Attach user data to @font_face. To remove user data from a font face,
+ * call this function with the key that was used to set it and %NULL
+ * for @data.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
+ * slot could not be allocated for the user data.
+ **/
cairo_status_t
-_cairo_font_text_to_glyphs (cairo_font_t *font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs)
+cairo_font_face_set_user_data (cairo_font_face_t *font_face,
+ const cairo_user_data_key_t *key,
+ void *user_data,
+ cairo_destroy_func_t destroy)
+{
+ return _cairo_user_data_array_set_data (&font_face->user_data,
+ key, user_data, destroy);
+}
+
+/* cairo_simple_font_face_t - simple family/slant/weight font faces used for
+ * the built-in font API
+ */
+
+typedef struct _cairo_simple_font_face cairo_simple_font_face_t;
+
+struct _cairo_simple_font_face {
+ cairo_font_face_t base;
+ char *family;
+ cairo_font_slant_t slant;
+ cairo_font_weight_t weight;
+};
+
+static const cairo_font_face_backend_t _cairo_simple_font_face_backend;
+
+/* We maintain a global cache from family/weight/slant => cairo_font_face_t
+ * for cairo_simple_font_t. The primary purpose of this cache is to provide
+ * unique cairo_font_face_t values so that our cache from
+ * cairo_font_face_t => cairo_scaled_font_t works. For this reason, we don't need
+ * this cache to keep font faces alive; we just add them to the cache and
+ * remove them again when freed.
+ */
+
+typedef struct {
+ cairo_cache_entry_base_t base;
+ const char *family;
+ cairo_font_slant_t slant;
+ cairo_font_weight_t weight;
+} cairo_simple_cache_key_t;
+
+typedef struct {
+ cairo_simple_cache_key_t key;
+ cairo_simple_font_face_t *font_face;
+} cairo_simple_cache_entry_t;
+
+static const cairo_cache_backend_t _cairo_simple_font_cache_backend;
+
+static void
+_lock_global_simple_cache (void)
+{
+ /* FIXME: Perform locking here. */
+}
+
+static void
+_unlock_global_simple_cache (void)
{
- return font->backend->text_to_glyphs (font, utf8, glyphs, num_glyphs);
+ /* FIXME: Perform locking here. */
+}
+
+static cairo_cache_t *
+_get_global_simple_cache (void)
+{
+ static cairo_cache_t *global_simple_cache = NULL;
+
+ if (global_simple_cache == NULL)
+ {
+ global_simple_cache = malloc (sizeof (cairo_cache_t));
+ if (!global_simple_cache)
+ goto FAIL;
+
+ if (_cairo_cache_init (global_simple_cache,
+ &_cairo_simple_font_cache_backend,
+ 0)) /* No memory limit */
+ goto FAIL;
+ }
+ return global_simple_cache;
+
+ FAIL:
+ if (global_simple_cache)
+ free (global_simple_cache);
+ global_simple_cache = NULL;
+ return NULL;
+}
+
+static unsigned long
+_cairo_simple_font_cache_hash (void *cache, void *key)
+{
+ cairo_simple_cache_key_t *k = (cairo_simple_cache_key_t *) key;
+ unsigned long hash;
+
+ /* 1607 and 1451 are just a couple random primes. */
+ hash = _cairo_hash_string (k->family);
+ hash += ((unsigned long) k->slant) * 1607;
+ hash += ((unsigned long) k->weight) * 1451;
+
+ return hash;
+}
+
+static int
+_cairo_simple_font_cache_keys_equal (void *cache,
+ void *k1,
+ void *k2)
+{
+ cairo_simple_cache_key_t *a;
+ cairo_simple_cache_key_t *b;
+ a = (cairo_simple_cache_key_t *) k1;
+ b = (cairo_simple_cache_key_t *) k2;
+
+ return strcmp (a->family, b->family) == 0 &&
+ a->slant == b->slant &&
+ a->weight == b->weight;
+}
+
+static cairo_simple_font_face_t *
+_cairo_simple_font_face_create_from_cache_key (cairo_simple_cache_key_t *key)
+{
+ cairo_simple_font_face_t *simple_face;
+
+ simple_face = malloc (sizeof (cairo_simple_font_face_t));
+ if (!simple_face)
+ return NULL;
+
+ simple_face->family = strdup (key->family);
+ if (!simple_face->family) {
+ free (simple_face);
+ return NULL;
+ }
+
+ simple_face->slant = key->slant;
+ simple_face->weight = key->weight;
+
+ _cairo_font_face_init (&simple_face->base, &_cairo_simple_font_face_backend);
+
+ return simple_face;
+}
+
+static cairo_status_t
+_cairo_simple_font_cache_create_entry (void *cache,
+ void *key,
+ void **return_entry)
+{
+ cairo_simple_cache_key_t *k = (cairo_simple_cache_key_t *) key;
+ cairo_simple_cache_entry_t *entry;
+
+ entry = malloc (sizeof (cairo_simple_cache_entry_t));
+ if (entry == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ entry->font_face = _cairo_simple_font_face_create_from_cache_key (k);
+ if (!entry->font_face) {
+ free (entry);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ entry->key.base.memory = 0;
+ entry->key.family = entry->font_face->family;
+ entry->key.slant = entry->font_face->slant;
+ entry->key.weight = entry->font_face->weight;
+
+ *return_entry = entry;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Entries are never spontaneously destroyed; but only when
+ * we remove them from the cache specifically. We free entry->font_face
+ * in the code that removes the entry from the cache
+ */
+static void
+_cairo_simple_font_cache_destroy_entry (void *cache,
+ void *entry)
+{
+ cairo_simple_cache_entry_t *e = (cairo_simple_cache_entry_t *) entry;
+
+ free (e);
+}
+
+static void
+_cairo_simple_font_cache_destroy_cache (void *cache)
+{
+ free (cache);
+}
+
+static const cairo_cache_backend_t _cairo_simple_font_cache_backend = {
+ _cairo_simple_font_cache_hash,
+ _cairo_simple_font_cache_keys_equal,
+ _cairo_simple_font_cache_create_entry,
+ _cairo_simple_font_cache_destroy_entry,
+ _cairo_simple_font_cache_destroy_cache
+};
+
+static void
+_cairo_simple_font_face_destroy (void *abstract_face)
+{
+ cairo_simple_font_face_t *simple_face = abstract_face;
+ cairo_cache_t *cache;
+ cairo_simple_cache_key_t key;
+
+ _lock_global_simple_cache ();
+ cache = _get_global_simple_cache ();
+ assert (cache);
+
+ key.family = simple_face->family;
+ key.slant = simple_face->slant;
+ key.weight = simple_face->weight;
+
+ _cairo_cache_remove (cache, &key);
+
+ _unlock_global_simple_cache ();
+
+ free (simple_face->family);
+}
+
+static cairo_status_t
+_cairo_simple_font_face_create_font (void *abstract_face,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ cairo_scaled_font_t **scaled_font)
+{
+ const cairo_scaled_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
+ cairo_simple_font_face_t *simple_face = abstract_face;
+
+ return backend->create (simple_face->family, simple_face->slant, simple_face->weight,
+ font_matrix, ctm, scaled_font);
+}
+
+static const cairo_font_face_backend_t _cairo_simple_font_face_backend = {
+ _cairo_simple_font_face_destroy,
+ _cairo_simple_font_face_create_font,
+};
+
+/**
+ * _cairo_simple_font_face_create:
+ * @family: a font family name, encoded in UTF-8
+ * @slant: the slant for the font
+ * @weight: the weight for the font
+ *
+ * Creates a font face from a triplet of family, slant, and weight.
+ * These font faces are used in implementation of the the #cairo_t "toy"
+ * font API.
+ *
+ * Return value: a newly created #cairo_font_face_t, destroy with
+ * cairo_font_face_destroy()
+ **/
+cairo_private cairo_font_face_t *
+_cairo_simple_font_face_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight)
+{
+ cairo_simple_cache_entry_t *entry;
+ cairo_simple_cache_key_t key;
+ cairo_cache_t *cache;
+ cairo_status_t status;
+ cairo_bool_t created_entry;
+
+ key.family = family;
+ key.slant = slant;
+ key.weight = weight;
+
+ _lock_global_simple_cache ();
+ cache = _get_global_simple_cache ();
+ if (cache == NULL) {
+ _unlock_global_simple_cache ();
+ return NULL;
+ }
+ status = _cairo_cache_lookup (cache, &key, (void **) &entry, &created_entry);
+ if (CAIRO_OK (status) && !created_entry)
+ cairo_font_face_reference (&entry->font_face->base);
+
+ _unlock_global_simple_cache ();
+ if (status)
+ return NULL;
+
+ return &entry->font_face->base;
+}
+
+/* cairo_scaled_font_t */
+
+/* Here we keep a cache from cairo_font_face_t/matrix/ctm => cairo_scaled_font_t.
+ *
+ * The implementation is messy because we want
+ *
+ * - All otherwise referenced cairo_scaled_font_t's to be in the cache
+ * - Some number of not otherwise referenced cairo_scaled_font_t's
+ *
+ * For this reason, we actually use *two* caches ... a finite size
+ * cache that references the cairo_scaled_font_t as a first level (the outer
+ * cache), then an infinite size cache as the second level (the inner
+ * cache). A single cache could be used at the cost of complicating
+ * cairo-cache.c
+ */
+
+/* This defines the size of the outer cache ... that is, the number
+ * of scaled fonts we keep around even when not otherwise referenced
+ */
+#define MAX_CACHED_FONTS 24
+
+typedef struct {
+ cairo_cache_entry_base_t base;
+ cairo_font_face_t *font_face;
+ const cairo_matrix_t *font_matrix;
+ const cairo_matrix_t *ctm;
+} cairo_font_cache_key_t;
+
+typedef struct {
+ cairo_font_cache_key_t key;
+ cairo_scaled_font_t *scaled_font;
+} cairo_font_cache_entry_t;
+
+static const cairo_cache_backend_t _cairo_outer_font_cache_backend;
+static const cairo_cache_backend_t _cairo_inner_font_cache_backend;
+
+static void
+_lock_global_font_cache (void)
+{
+ /* FIXME: Perform locking here. */
+}
+
+static void
+_unlock_global_font_cache (void)
+{
+ /* FIXME: Perform locking here. */
+}
+
+static cairo_cache_t *
+_get_outer_font_cache (void)
+{
+ static cairo_cache_t *outer_font_cache = NULL;
+
+ if (outer_font_cache == NULL)
+ {
+ outer_font_cache = malloc (sizeof (cairo_cache_t));
+ if (!outer_font_cache)
+ goto FAIL;
+
+ if (_cairo_cache_init (outer_font_cache,
+ &_cairo_outer_font_cache_backend,
+ MAX_CACHED_FONTS))
+ goto FAIL;
+ }
+ return outer_font_cache;
+
+ FAIL:
+ if (outer_font_cache)
+ free (outer_font_cache);
+ outer_font_cache = NULL;
+ return NULL;
+}
+
+static cairo_cache_t *
+_get_inner_font_cache (void)
+{
+ static cairo_cache_t *inner_font_cache = NULL;
+
+ if (inner_font_cache == NULL)
+ {
+ inner_font_cache = malloc (sizeof (cairo_cache_t));
+ if (!inner_font_cache)
+ goto FAIL;
+
+ if (_cairo_cache_init (inner_font_cache,
+ &_cairo_inner_font_cache_backend,
+ MAX_CACHED_FONTS))
+ goto FAIL;
+ }
+ return inner_font_cache;
+
+ FAIL:
+ if (inner_font_cache)
+ free (inner_font_cache);
+ inner_font_cache = NULL;
+ return NULL;
+}
+
+
+/* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
+ *
+ * Not necessarily better than a lot of other hashes, but should be OK, and
+ * well tested with binary data.
+ */
+
+#define FNV_32_PRIME ((uint32_t)0x01000193)
+#define FNV1_32_INIT ((uint32_t)0x811c9dc5)
+
+static uint32_t
+_hash_bytes_fnv (unsigned char *buffer,
+ int len,
+ uint32_t hval)
+{
+ while (len--) {
+ hval *= FNV_32_PRIME;
+ hval ^= *buffer++;
+ }
+
+ return hval;
+}
+static unsigned long
+_cairo_font_cache_hash (void *cache, void *key)
+{
+ cairo_font_cache_key_t *k = (cairo_font_cache_key_t *) key;
+ uint32_t hash = FNV1_32_INIT;
+
+ /* We do a bytewise hash on the font matrices */
+ hash = _hash_bytes_fnv ((unsigned char *)(&k->font_matrix->xx),
+ sizeof(double) * 4,
+ hash);
+ hash = _hash_bytes_fnv ((unsigned char *)(&k->ctm->xx),
+ sizeof(double) * 4,
+ hash);
+
+ return hash ^ (unsigned long)k->font_face;
+}
+
+static int
+_cairo_font_cache_keys_equal (void *cache,
+ void *k1,
+ void *k2)
+{
+ cairo_font_cache_key_t *a;
+ cairo_font_cache_key_t *b;
+ a = (cairo_font_cache_key_t *) k1;
+ b = (cairo_font_cache_key_t *) k2;
+
+ return (a->font_face == b->font_face &&
+ memcmp ((unsigned char *)(&a->font_matrix->xx),
+ (unsigned char *)(&b->font_matrix->xx),
+ sizeof(double) * 4) == 0 &&
+ memcmp ((unsigned char *)(&a->ctm->xx),
+ (unsigned char *)(&b->ctm->xx),
+ sizeof(double) * 4) == 0);
+}
+
+/* The cache lookup failed in the outer cache, so we pull
+ * the font from the inner cache (if that in turns fails,
+ * it will create the font
+ */
+static cairo_status_t
+_cairo_outer_font_cache_create_entry (void *cache,
+ void *key,
+ void **return_entry)
+{
+ cairo_font_cache_entry_t *entry;
+ cairo_font_cache_entry_t *inner_entry;
+ cairo_bool_t created_entry;
+ cairo_status_t status;
+
+ entry = malloc (sizeof (cairo_font_cache_entry_t));
+ if (entry == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ cache = _get_inner_font_cache ();
+ if (cache == NULL) {
+ _unlock_global_font_cache ();
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ status = _cairo_cache_lookup (cache, key, (void **) &inner_entry, &created_entry);
+ if (!CAIRO_OK (status)) {
+ free (entry);
+ return status;
+ }
+
+ entry->scaled_font = inner_entry->scaled_font;
+ if (!created_entry)
+ cairo_scaled_font_reference (entry->scaled_font);
+
+ entry->key.base.memory = 1;
+ entry->key.font_face = entry->scaled_font->font_face;
+ entry->key.font_matrix = &entry->scaled_font->font_matrix;
+ entry->key.ctm = &entry->scaled_font->ctm;
+
+ *return_entry = entry;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_outer_font_cache_destroy_entry (void *cache,
+ void *entry)
+{
+ cairo_font_cache_entry_t *e = (cairo_font_cache_entry_t *) entry;
+
+ cairo_scaled_font_destroy (e->scaled_font);
+
+ free (e);
+}
+
+/* Called when the lookup fails in the inner cache as well; there
+ * is no existing font, so we have to create one.
+ */
+static cairo_status_t
+_cairo_inner_font_cache_create_entry (void *cache,
+ void *key,
+ void **return_entry)
+{
+ cairo_font_cache_key_t *k = (cairo_font_cache_key_t *) key;
+ cairo_font_cache_entry_t *entry;
+ cairo_status_t status;
+
+ entry = malloc (sizeof (cairo_font_cache_entry_t));
+ if (entry == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ status = k->font_face->backend->create_font (k->font_face,
+ k->font_matrix,
+ k->ctm,
+ &entry->scaled_font);
+ if (!CAIRO_OK (status)) {
+ free (entry);
+ return status;
+ }
+
+ entry->scaled_font->font_face = k->font_face;
+ cairo_font_face_reference (k->font_face);
+
+ entry->key.base.memory = 0;
+ entry->key.font_face = k->font_face;
+ entry->key.font_matrix = &entry->scaled_font->font_matrix;
+ entry->key.ctm = &entry->scaled_font->ctm;
+
+ *return_entry = entry;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Entries in the inner font cache are never spontaneously destroyed;
+ * but only when we remove them from the cache specifically. We free
+ * entry->scaled_font in the code that removes the entry from the cache
+ */
+static void
+_cairo_inner_font_cache_destroy_entry (void *cache,
+ void *entry)
+{
+ free (entry);
+}
+
+static void
+_cairo_font_cache_destroy_cache (void *cache)
+{
+ free (cache);
+}
+
+static const cairo_cache_backend_t _cairo_outer_font_cache_backend = {
+ _cairo_font_cache_hash,
+ _cairo_font_cache_keys_equal,
+ _cairo_outer_font_cache_create_entry,
+ _cairo_outer_font_cache_destroy_entry,
+ _cairo_font_cache_destroy_cache
+};
+
+static const cairo_cache_backend_t _cairo_inner_font_cache_backend = {
+ _cairo_font_cache_hash,
+ _cairo_font_cache_keys_equal,
+ _cairo_inner_font_cache_create_entry,
+ _cairo_inner_font_cache_destroy_entry,
+ _cairo_font_cache_destroy_cache
+};
+
+/**
+ * cairo_scaled_font_create:
+ * @font_face: a #cairo_font_face_t
+ * @font_matrix: font space to user space transformation matrix for the
+ * font. In the simplest case of a N point font, this matrix is
+ * just a scale by N, but it can also be used to shear the font
+ * or stretch it unequally along the two axes. See
+ * cairo_set_font_matrix().
+ * @ctm: user to device transformation matrix with which the font will
+ * be used.
+ *
+ * Creates a #cairo_scaled_font_t object from a font face and matrices that
+ * describe the size of the font and the environment in which it will
+ * be used.
+ *
+ * Return value: a newly created #cairo_scaled_font_t. Destroy with
+ * cairo_scaled_font_destroy()
+ **/
+cairo_scaled_font_t *
+cairo_scaled_font_create (cairo_font_face_t *font_face,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm)
+{
+ cairo_font_cache_entry_t *entry;
+ cairo_font_cache_key_t key;
+ cairo_cache_t *cache;
+ cairo_status_t status;
+
+ key.font_face = font_face;
+ key.font_matrix = font_matrix;
+ key.ctm = ctm;
+
+ _lock_global_font_cache ();
+ cache = _get_outer_font_cache ();
+ if (cache == NULL) {
+ _unlock_global_font_cache ();
+ return NULL;
+ }
+
+ status = _cairo_cache_lookup (cache, &key, (void **) &entry, NULL);
+ if (CAIRO_OK (status))
+ cairo_scaled_font_reference (entry->scaled_font);
+
+ _unlock_global_font_cache ();
+ if (!CAIRO_OK (status))
+ return NULL;
+
+ return entry->scaled_font;
+}
+
+void
+_cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ const cairo_scaled_font_backend_t *backend)
+{
+ scaled_font->font_matrix = *font_matrix;
+ scaled_font->ctm = *ctm;
+ cairo_matrix_multiply (&scaled_font->scale, &scaled_font->font_matrix, &scaled_font->ctm);
+
+ scaled_font->refcount = 1;
+ scaled_font->backend = backend;
}
cairo_status_t
-_cairo_font_glyph_extents (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
+_cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
+ const char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs)
{
- return font->backend->glyph_extents(font, glyphs, num_glyphs, extents);
+ return scaled_font->backend->text_to_glyphs (scaled_font, utf8, glyphs, num_glyphs);
+}
+
+cairo_status_t
+_cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
+{
+ return scaled_font->backend->glyph_extents (scaled_font, glyphs, num_glyphs, extents);
}
cairo_status_t
-_cairo_font_glyph_bbox (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox)
+_cairo_scaled_font_glyph_bbox (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
{
- return font->backend->glyph_bbox (font, glyphs, num_glyphs, bbox);
+ return scaled_font->backend->glyph_bbox (scaled_font, glyphs, num_glyphs, bbox);
}
cairo_status_t
-_cairo_font_show_glyphs (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- cairo_glyph_t *glyphs,
- int num_glyphs)
+_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_glyph_t *glyphs,
+ int num_glyphs)
{
cairo_status_t status;
- if (surface->backend->show_glyphs != NULL) {
- status = surface->backend->show_glyphs (font, operator, pattern,
- surface,
- source_x, source_y,
- dest_x, dest_y,
- width, height,
- glyphs, num_glyphs);
- if (status == CAIRO_STATUS_SUCCESS)
- return status;
- }
+
+ status = _cairo_surface_show_glyphs (scaled_font, operator, pattern,
+ surface,
+ source_x, source_y,
+ dest_x, dest_y,
+ width, height,
+ glyphs, num_glyphs);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
/* Surface display routine either does not exist or failed. */
- return font->backend->show_glyphs (font, operator, pattern,
- surface,
- source_x, source_y,
- dest_x, dest_y,
- width, height,
- glyphs, num_glyphs);
+ return scaled_font->backend->show_glyphs (scaled_font, operator, pattern,
+ surface,
+ source_x, source_y,
+ dest_x, dest_y,
+ width, height,
+ glyphs, num_glyphs);
}
cairo_status_t
-_cairo_font_glyph_path (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path)
+_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_fixed_t *path)
{
- return font->backend->glyph_path (font, glyphs, num_glyphs, path);
+ return scaled_font->backend->glyph_path (scaled_font, glyphs, num_glyphs, path);
}
void
-_cairo_font_get_glyph_cache_key (cairo_font_t *font,
- cairo_glyph_cache_key_t *key)
+_cairo_scaled_font_get_glyph_cache_key (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_cache_key_t *key)
{
- font->backend->get_glyph_cache_key (font, key);
+ scaled_font->backend->get_glyph_cache_key (scaled_font, key);
}
cairo_status_t
-_cairo_font_font_extents (cairo_font_t *font,
- cairo_font_extents_t *extents)
+_cairo_scaled_font_font_extents (cairo_scaled_font_t *scaled_font,
+ cairo_font_extents_t *extents)
{
- return font->backend->font_extents (font, extents);
+ return scaled_font->backend->font_extents (scaled_font, extents);
}
void
-_cairo_unscaled_font_reference (cairo_unscaled_font_t *font)
+_cairo_unscaled_font_init (cairo_unscaled_font_t *unscaled_font,
+ const cairo_unscaled_font_backend_t *backend)
{
- font->refcount++;
+ unscaled_font->refcount = 1;
+ unscaled_font->backend = backend;
}
void
-_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font)
+_cairo_unscaled_font_reference (cairo_unscaled_font_t *unscaled_font)
+{
+ unscaled_font->refcount++;
+}
+
+void
+_cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font)
{
- if (--(font->refcount) > 0)
+ if (--(unscaled_font->refcount) > 0)
return;
- font->backend->destroy_unscaled_font (font);
+ unscaled_font->backend->destroy (unscaled_font);
+
+ free (unscaled_font);
}
/* Public font API follows. */
+/**
+ * cairo_scaled_font_reference:
+ * @scaled_font: a #cairo_scaled_font_t
+ *
+ * Increases the reference count on @scaled_font by one. This prevents
+ * @scaled_font from being destroyed until a matching call to
+ * cairo_scaled_font_destroy() is made.
+ **/
void
-cairo_font_reference (cairo_font_t *font)
+cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font)
{
- font->refcount++;
+ scaled_font->refcount++;
}
+/**
+ * cairo_scaled_font_destroy:
+ * @scaled_font: a #cairo_scaled_font_t
+ *
+ * Decreases the reference count on @font by one. If the result
+ * is zero, then @font and all associated resources are freed.
+ * See cairo_scaled_font_reference().
+ **/
void
-cairo_font_destroy (cairo_font_t *font)
+cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
{
- if (--(font->refcount) > 0)
+ cairo_font_cache_key_t key;
+ cairo_cache_t *cache;
+
+ if (--(scaled_font->refcount) > 0)
return;
- font->backend->destroy_font (font);
+ if (scaled_font->font_face) {
+ _lock_global_font_cache ();
+ cache = _get_inner_font_cache ();
+ assert (cache);
+
+ key.font_face = scaled_font->font_face;
+ key.font_matrix = &scaled_font->font_matrix;
+ key.ctm = &scaled_font->ctm;
+
+ _cairo_cache_remove (cache, &key);
+ _unlock_global_font_cache ();
+
+ cairo_font_face_destroy (scaled_font->font_face);
+ }
+
+ scaled_font->backend->destroy (scaled_font);
+
+ free (scaled_font);
}
/**
- * cairo_font_extents:
- * @font: a #cairo_font_t
- * @font_matrix: the font transformation for which this font was
- * created. (See cairo_transform_font()). This is needed
- * properly convert the metrics from the font into user space.
+ * cairo_scaled_font_extents:
+ * @scaled_font: a #cairo_scaled_font_t
* @extents: a #cairo_font_extents_t which to store the retrieved extents.
*
- * Gets the metrics for a #cairo_font_t.
+ * Gets the metrics for a #cairo_scaled_font_t.
*
* Return value: %CAIRO_STATUS_SUCCESS on success. Otherwise, an
* error such as %CAIRO_STATUS_NO_MEMORY.
**/
cairo_status_t
-cairo_font_extents (cairo_font_t *font,
- cairo_matrix_t *font_matrix,
- cairo_font_extents_t *extents)
+cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font,
+ cairo_font_extents_t *extents)
{
cairo_int_status_t status;
double font_scale_x, font_scale_y;
- status = _cairo_font_font_extents (font, extents);
+ status = _cairo_scaled_font_font_extents (scaled_font, extents);
if (!CAIRO_OK (status))
return status;
- _cairo_matrix_compute_scale_factors (font_matrix,
+ _cairo_matrix_compute_scale_factors (&scaled_font->font_matrix,
&font_scale_x, &font_scale_y,
/* XXX */ 1);
@@ -237,10 +958,7 @@ cairo_font_extents (cairo_font_t *font,
/**
* cairo_font_glyph_extents:
- * @font: a #cairo_font_t
- * @font_matrix: the font transformation for which this font was
- * created. (See cairo_transform_font()). This is needed
- * properly convert the metrics from the font into user space.
+ * @scaled_font: a #cairo_scaled_font_t
* @glyphs: an array of glyph IDs with X and Y offsets.
* @num_glyphs: the number of glyphs in the @glyphs array
* @extents: a #cairo_text_extents_t which to store the retrieved extents.
@@ -249,11 +967,10 @@ cairo_font_extents (cairo_font_t *font,
* glyphs. The X and Y offsets in @glyphs are taken from an origin of 0,0.
**/
void
-cairo_font_glyph_extents (cairo_font_t *font,
- cairo_matrix_t *font_matrix,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
+cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_glyph_t origin_glyph;
@@ -283,9 +1000,9 @@ cairo_font_glyph_extents (cairo_font_t *font,
origin_glyph = glyphs[i];
origin_glyph.x = 0.0;
origin_glyph.y = 0.0;
- status = _cairo_font_glyph_extents (font,
- &origin_glyph, 1,
- &origin_extents);
+ status = _cairo_scaled_font_glyph_extents (scaled_font,
+ &origin_glyph, 1,
+ &origin_extents);
/*
* Transform font space metrics into user space metrics
@@ -294,7 +1011,7 @@ cairo_font_glyph_extents (cairo_font_t *font,
*/
x = origin_extents.x_bearing;
y = origin_extents.y_bearing;
- cairo_matrix_transform_point (font_matrix,
+ cairo_matrix_transform_point (&scaled_font->font_matrix,
&x, &y);
for (hm = 0.0; hm <= 1.0; hm += 1.0)
@@ -302,7 +1019,7 @@ cairo_font_glyph_extents (cairo_font_t *font,
{
x = origin_extents.x_bearing + origin_extents.width * wm;
y = origin_extents.y_bearing + origin_extents.height * hm;
- cairo_matrix_transform_point (font_matrix,
+ cairo_matrix_transform_point (&scaled_font->font_matrix,
&x, &y);
x += glyphs[i].x;
y += glyphs[i].y;
@@ -323,7 +1040,7 @@ cairo_font_glyph_extents (cairo_font_t *font,
x = origin_extents.x_advance;
y = origin_extents.y_advance;
- cairo_matrix_transform_point (font_matrix,
+ cairo_matrix_transform_point (&scaled_font->font_matrix,
&x, &y);
x_pos = glyphs[i].x + x;
y_pos = glyphs[i].y + y;
@@ -348,10 +1065,10 @@ _cairo_glyph_cache_hash (void *cache, void *key)
in = (cairo_glyph_cache_key_t *) key;
return
((unsigned long) in->unscaled)
- ^ ((unsigned long) in->scale.matrix[0][0])
- ^ ((unsigned long) in->scale.matrix[0][1])
- ^ ((unsigned long) in->scale.matrix[1][0])
- ^ ((unsigned long) in->scale.matrix[1][1])
+ ^ ((unsigned long) in->scale.xx)
+ ^ ((unsigned long) in->scale.yx)
+ ^ ((unsigned long) in->scale.xy)
+ ^ ((unsigned long) in->scale.yy)
^ (in->flags * 1451) /* 1451 is just an abitrary prime */
^ in->index;
}
@@ -367,10 +1084,10 @@ _cairo_glyph_cache_keys_equal (void *cache,
return (a->index == b->index)
&& (a->unscaled == b->unscaled)
&& (a->flags == b->flags)
- && (a->scale.matrix[0][0] == b->scale.matrix[0][0])
- && (a->scale.matrix[0][1] == b->scale.matrix[0][1])
- && (a->scale.matrix[1][0] == b->scale.matrix[1][0])
- && (a->scale.matrix[1][1] == b->scale.matrix[1][1]);
+ && (a->scale.xx == b->scale.xx)
+ && (a->scale.yx == b->scale.yx)
+ && (a->scale.xy == b->scale.xy)
+ && (a->scale.yy == b->scale.yy);
}
@@ -388,7 +1105,8 @@ _image_glyph_cache_create_entry (void *cache,
return CAIRO_STATUS_NO_MEMORY;
im->key = *k;
- status = im->key.unscaled->backend->create_glyph (im);
+ status = im->key.unscaled->backend->create_glyph (im->key.unscaled,
+ im);
if (status != CAIRO_STATUS_SUCCESS) {
free (im);
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 44e1b0e84..c02cd61e5 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -66,31 +66,42 @@ typedef struct {
/*
* We create an object that corresponds to a single font on the disk;
* (identified by a filename/id pair) these are shared between all
- * fonts using that file. For cairo_ft_font_create_for_ft_face(), we
+ * fonts using that file. For cairo_ft_scaled_font_create_for_ft_face(), we
* just create a one-off version with a permanent face value.
*/
+
+typedef struct _ft_font_face ft_font_face_t;
+
typedef struct {
cairo_unscaled_font_t base;
- int from_face; /* from cairo_ft_font_create_for_ft_face()? */
- FT_Face face; /* provided or cached face */
+ cairo_bool_t from_face; /* from cairo_ft_scaled_font_create_for_ft_face()? */
+ FT_Face face; /* provided or cached face */
/* only set if from_face is false */
- FT_Library library;
char *filename;
int id;
/* We temporarily scale the unscaled font as neede */
int have_scale;
- cairo_font_scale_t current_scale;
+ cairo_matrix_t current_scale;
double x_scale; /* Extracted X scale factor */
double y_scale; /* Extracted Y scale factor */
int lock; /* count of how many times this font has been locked */
+
+ ft_font_face_t *faces; /* Linked list of faces for this font */
} ft_unscaled_font_t;
-const cairo_font_backend_t cairo_ft_font_backend;
+struct _ft_font_face {
+ cairo_font_face_t base;
+ ft_unscaled_font_t *unscaled;
+ int load_flags;
+ ft_font_face_t *next_face;
+};
+
+const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend;
static ft_unscaled_font_t *
_ft_unscaled_font_create_from_face (FT_Face face)
@@ -102,21 +113,21 @@ _ft_unscaled_font_create_from_face (FT_Face face)
unscaled->from_face = 1;
unscaled->face = face;
- unscaled->library = NULL;
unscaled->filename = NULL;
unscaled->id = 0;
unscaled->have_scale = 0;
unscaled->lock = 0;
- _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled,
- &cairo_ft_font_backend);
+ unscaled->faces = NULL;
+
+ _cairo_unscaled_font_init (&unscaled->base,
+ &cairo_ft_unscaled_font_backend);
return unscaled;
}
static ft_unscaled_font_t *
-_ft_unscaled_font_create_from_filename (FT_Library library,
- const char *filename,
+_ft_unscaled_font_create_from_filename (const char *filename,
int id)
{
ft_unscaled_font_t *unscaled;
@@ -135,15 +146,16 @@ _ft_unscaled_font_create_from_filename (FT_Library library,
unscaled->from_face = 0;
unscaled->face = NULL;
- unscaled->library = library;
unscaled->filename = new_filename;
unscaled->id = id;
unscaled->have_scale = 0;
unscaled->lock = 0;
- _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled,
- &cairo_ft_font_backend);
+ unscaled->faces = NULL;
+
+ _cairo_unscaled_font_init (&unscaled->base,
+ &cairo_ft_unscaled_font_backend);
return unscaled;
}
@@ -204,7 +216,6 @@ _ft_font_cache_create_entry (void *cache,
void *key,
void **return_entry)
{
- ft_cache_t *ftcache = (ft_cache_t *) cache;
cairo_ft_cache_key_t *k = (cairo_ft_cache_key_t *) key;
cairo_ft_cache_entry_t *entry;
@@ -212,8 +223,7 @@ _ft_font_cache_create_entry (void *cache,
if (entry == NULL)
return CAIRO_STATUS_NO_MEMORY;
- entry->unscaled = _ft_unscaled_font_create_from_filename (ftcache->lib,
- k->filename,
+ entry->unscaled = _ft_unscaled_font_create_from_filename (k->filename,
k->id);
if (!entry->unscaled) {
free (entry);
@@ -327,13 +337,13 @@ _ft_unscaled_font_get_for_pattern (FcPattern *pattern)
}
status = _cairo_cache_lookup (cache, &key, (void **) &entry, &created_entry);
+ if (CAIRO_OK (status) && !created_entry)
+ _cairo_unscaled_font_reference (&entry->unscaled->base);
+
_unlock_global_ft_cache ();
- if (status)
+ if (!CAIRO_OK (status))
return NULL;
- if (!created_entry)
- _cairo_unscaled_font_reference ((cairo_unscaled_font_t *)entry->unscaled);
-
return entry->unscaled;
}
@@ -406,9 +416,9 @@ _ft_unscaled_font_unlock_face (ft_unscaled_font_t *unscaled)
static void
_compute_transform (ft_font_transform_t *sf,
- cairo_font_scale_t *sc)
+ cairo_matrix_t *scale)
{
- cairo_matrix_t normalized;
+ cairo_matrix_t normalized = *scale;
double tx, ty;
/* The font matrix has x and y "scale" components which we extract and
@@ -418,21 +428,14 @@ _compute_transform (ft_font_transform_t *sf,
* freetype's transformation.
*/
- cairo_matrix_set_affine (&normalized,
- sc->matrix[0][0],
- sc->matrix[0][1],
- sc->matrix[1][0],
- sc->matrix[1][1],
- 0, 0);
-
_cairo_matrix_compute_scale_factors (&normalized,
&sf->x_scale, &sf->y_scale,
/* XXX */ 1);
cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale);
- cairo_matrix_get_affine (&normalized,
- &sf->shape[0][0], &sf->shape[0][1],
- &sf->shape[1][0], &sf->shape[1][1],
- &tx, &ty);
+ _cairo_matrix_get_affine (&normalized,
+ &sf->shape[0][0], &sf->shape[0][1],
+ &sf->shape[1][0], &sf->shape[1][1],
+ &tx, &ty);
}
/* Temporarily scales an unscaled font to the give scale. We catch
@@ -440,7 +443,7 @@ _compute_transform (ft_font_transform_t *sf,
*/
static void
_ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled,
- cairo_font_scale_t *scale)
+ cairo_matrix_t *scale)
{
ft_font_transform_t sf;
FT_Matrix mat;
@@ -448,10 +451,10 @@ _ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled,
assert (unscaled->face != NULL);
if (unscaled->have_scale &&
- scale->matrix[0][0] == unscaled->current_scale.matrix[0][0] &&
- scale->matrix[0][1] == unscaled->current_scale.matrix[0][1] &&
- scale->matrix[1][0] == unscaled->current_scale.matrix[1][0] &&
- scale->matrix[1][1] == unscaled->current_scale.matrix[1][1])
+ scale->xx == unscaled->current_scale.xx &&
+ scale->yx == unscaled->current_scale.yx &&
+ scale->xy == unscaled->current_scale.xy &&
+ scale->yy == unscaled->current_scale.yy)
return;
unscaled->have_scale = 1;
@@ -474,14 +477,172 @@ _ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled,
(FT_UInt) sf.y_scale);
}
-/* implement the font backend interface */
+static void
+_cairo_ft_unscaled_font_destroy (void *abstract_font)
+{
+ ft_unscaled_font_t *unscaled = abstract_font;
+
+ if (unscaled->from_face) {
+ /* See comments in _ft_font_face_destroy about the "zombie" state
+ * for a _ft_font_face.
+ */
+ if (unscaled->faces && !unscaled->faces->unscaled)
+ cairo_font_face_destroy (&unscaled->faces->base);
+ } else {
+ cairo_cache_t *cache;
+ cairo_ft_cache_key_t key;
+
+ _lock_global_ft_cache ();
+ cache = _get_global_ft_cache ();
+ assert (cache);
+
+ key.filename = unscaled->filename;
+ key.id = unscaled->id;
+
+ _cairo_cache_remove (cache, &key);
+
+ _unlock_global_ft_cache ();
+
+ if (unscaled->filename)
+ free (unscaled->filename);
+
+ if (unscaled->face)
+ FT_Done_Face (unscaled->face);
+ }
+}
+
+static cairo_status_t
+_cairo_ft_unscaled_font_create_glyph (void *abstract_font,
+ cairo_image_glyph_cache_entry_t *val)
+{
+ ft_unscaled_font_t *unscaled = abstract_font;
+ FT_GlyphSlot glyphslot;
+ unsigned int width, height, stride;
+ FT_Face face;
+ FT_Outline *outline;
+ FT_BBox cbox;
+ FT_Bitmap bitmap;
+ FT_Glyph_Metrics *metrics;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ face = _ft_unscaled_font_lock_face (unscaled);
+ if (!face)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ glyphslot = face->glyph;
+ metrics = &glyphslot->metrics;
+
+ _ft_unscaled_font_set_scale (unscaled, &val->key.scale);
+
+ if (FT_Load_Glyph (face, val->key.index, val->key.flags) != 0) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
+ }
+
+ /*
+ * Note: the font's coordinate system is upside down from ours, so the
+ * Y coordinates of the bearing and advance need to be negated.
+ *
+ * Scale metrics back to glyph space from the scaled glyph space returned
+ * by FreeType
+ */
+
+ val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / unscaled->x_scale;
+ val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / unscaled->y_scale;
+
+ val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / unscaled->x_scale;
+ val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / unscaled->y_scale;
+
+ /*
+ * use untransformed advance values
+ * XXX uses horizontal advance only at present;
+ should provide FT_LOAD_VERTICAL_LAYOUT
+ */
+
+ val->extents.x_advance = DOUBLE_FROM_26_6 (face->glyph->metrics.horiAdvance) / unscaled->x_scale;
+ val->extents.y_advance = 0 / unscaled->y_scale;
+
+ outline = &glyphslot->outline;
+
+ FT_Outline_Get_CBox (outline, &cbox);
+
+ cbox.xMin &= -64;
+ cbox.yMin &= -64;
+ cbox.xMax = (cbox.xMax + 63) & -64;
+ cbox.yMax = (cbox.yMax + 63) & -64;
+
+ width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6);
+ height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6);
+ stride = (width + 3) & -4;
+
+ if (width * height == 0)
+ val->image = NULL;
+ else
+ {
+
+ bitmap.pixel_mode = ft_pixel_mode_grays;
+ bitmap.num_grays = 256;
+ bitmap.width = width;
+ bitmap.rows = height;
+ bitmap.pitch = stride;
+ bitmap.buffer = calloc (1, stride * height);
+
+ if (bitmap.buffer == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
+ }
+
+ FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin);
+
+ if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) {
+ free (bitmap.buffer);
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
+ }
+
+ val->image = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data (bitmap.buffer,
+ CAIRO_FORMAT_A8,
+ width, height, stride);
+ if (val->image == NULL) {
+ free (bitmap.buffer);
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
+ }
+
+ _cairo_image_surface_assume_ownership_of_data (val->image);
+ }
+
+ /*
+ * Note: the font's coordinate system is upside down from ours, so the
+ * Y coordinate of the control box needs to be negated.
+ */
+
+ val->size.width = (unsigned short) width;
+ val->size.height = (unsigned short) height;
+ val->size.x = (short) (cbox.xMin >> 6);
+ val->size.y = - (short) (cbox.yMax >> 6);
+
+ FAIL:
+ _ft_unscaled_font_unlock_face (unscaled);
+
+ return status;
+}
+
+const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend = {
+ _cairo_ft_unscaled_font_destroy,
+ _cairo_ft_unscaled_font_create_glyph
+};
+
+/* cairo_ft_scaled_font_t */
typedef struct {
- cairo_font_t base;
- FcPattern *pattern;
+ cairo_scaled_font_t base;
int load_flags;
ft_unscaled_font_t *unscaled;
-} cairo_ft_font_t;
+} cairo_ft_scaled_font_t;
+
+const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend;
/* for compatibility with older freetype versions */
#ifndef FT_LOAD_TARGET_MONO
@@ -547,51 +708,43 @@ _get_load_flags (FcPattern *pattern)
return load_flags;
}
-/* Like the public cairo_ft_font_create, but takes a cairo_font_scale_t,
- * rather than a cairo_font_t
- */
-static cairo_font_t *
-_ft_font_create (FcPattern *pattern,
- cairo_font_scale_t *scale)
+static cairo_scaled_font_t *
+_ft_scaled_font_create (ft_unscaled_font_t *unscaled,
+ int load_flags,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm)
{
- cairo_ft_font_t *f = NULL;
- ft_unscaled_font_t *unscaled = NULL;
+ cairo_ft_scaled_font_t *f = NULL;
- unscaled = _ft_unscaled_font_get_for_pattern (pattern);
- if (unscaled == NULL)
- return NULL;
-
- f = malloc (sizeof(cairo_ft_font_t));
+ f = malloc (sizeof(cairo_ft_scaled_font_t));
if (f == NULL)
- goto FREE_UNSCALED;
+ return NULL;
f->unscaled = unscaled;
- f->pattern = pattern;
- FcPatternReference (pattern);
- f->load_flags = _get_load_flags (pattern);
-
- _cairo_font_init ((cairo_font_t *)f, scale, &cairo_ft_font_backend);
-
- return (cairo_font_t *)f;
+ _cairo_unscaled_font_reference (&unscaled->base);
+
+ f->load_flags = load_flags;
- FREE_UNSCALED:
- _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled);
+ _cairo_scaled_font_init (&f->base, font_matrix, ctm, &cairo_ft_scaled_font_backend);
- return NULL;
+ return (cairo_scaled_font_t *)f;
}
static cairo_status_t
-_cairo_ft_font_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight,
- cairo_font_scale_t *scale,
- cairo_font_t **font)
+_cairo_ft_scaled_font_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ cairo_scaled_font_t **font)
{
FcPattern *pattern, *resolved;
- cairo_font_t *new_font;
+ ft_unscaled_font_t *unscaled;
+ cairo_scaled_font_t *new_font;
FcResult result;
int fcslant;
int fcweight;
+ cairo_matrix_t scale;
ft_font_transform_t sf;
pattern = FcPatternCreate ();
@@ -623,14 +776,15 @@ _cairo_ft_font_create (const char *family,
break;
}
- if (!FcPatternAddString (pattern, FC_FAMILY, family))
+ if (!FcPatternAddString (pattern, FC_FAMILY, (unsigned char *) family))
goto FREE_PATTERN;
if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant))
goto FREE_PATTERN;
if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight))
goto FREE_PATTERN;
- _compute_transform (&sf, scale);
+ cairo_matrix_multiply (&scale, font_matrix, ctm);
+ _compute_transform (&sf, &scale);
FcPatternAddInteger (pattern, FC_PIXEL_SIZE, sf.y_scale);
@@ -641,7 +795,13 @@ _cairo_ft_font_create (const char *family,
if (!resolved)
goto FREE_PATTERN;
- new_font = _ft_font_create (resolved, scale);
+ unscaled = _ft_unscaled_font_get_for_pattern (resolved);
+ if (!unscaled)
+ goto FREE_RESOLVED;
+
+ new_font = _ft_scaled_font_create (unscaled, _get_load_flags (pattern),
+ font_matrix, ctm);
+ _cairo_unscaled_font_destroy (&unscaled->base);
FcPatternDestroy (resolved);
FcPatternDestroy (pattern);
@@ -653,6 +813,9 @@ _cairo_ft_font_create (const char *family,
return CAIRO_STATUS_NO_MEMORY; /* A guess */
}
+ FREE_RESOLVED:
+ FcPatternDestroy (resolved);
+
FREE_PATTERN:
FcPatternDestroy (pattern);
@@ -660,88 +823,50 @@ _cairo_ft_font_create (const char *family,
}
static void
-_cairo_ft_font_destroy_font (void *abstract_font)
+_cairo_ft_scaled_font_destroy (void *abstract_font)
{
- cairo_ft_font_t * font = abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = abstract_font;
- if (font == NULL)
+ if (scaled_font == NULL)
return;
- if (font->pattern != NULL)
- FcPatternDestroy (font->pattern);
-
- _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)font->unscaled);
-
- free (font);
-}
-
-static void
-_cairo_ft_font_destroy_unscaled_font (void *abstract_font)
-{
- ft_unscaled_font_t *unscaled = abstract_font;
-
- if (!unscaled->from_face) {
- cairo_cache_t *cache;
- cairo_ft_cache_key_t key;
-
- _lock_global_ft_cache ();
- cache = _get_global_ft_cache ();
- assert (cache);
-
- key.filename = unscaled->filename;
- key.id = unscaled->id;
-
- _cairo_cache_remove (cache, &key);
-
- _unlock_global_ft_cache ();
- }
-
- if (unscaled == NULL)
- return;
-
- if (!unscaled->from_face && unscaled->face)
- FT_Done_Face (unscaled->face);
-
- if (unscaled->filename)
- free (unscaled->filename);
-
- free (unscaled);
+ _cairo_unscaled_font_destroy (&scaled_font->unscaled->base);
}
static void
-_cairo_ft_font_get_glyph_cache_key (void *abstract_font,
- cairo_glyph_cache_key_t *key)
+_cairo_ft_scaled_font_get_glyph_cache_key (void *abstract_font,
+ cairo_glyph_cache_key_t *key)
{
- cairo_ft_font_t *font = abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = abstract_font;
- key->unscaled = (cairo_unscaled_font_t *)font->unscaled;
- key->scale = font->base.scale;
- key->flags = font->load_flags;
+ key->unscaled = &scaled_font->unscaled->base;
+ key->scale = scaled_font->base.scale;
+ key->flags = scaled_font->load_flags;
}
static cairo_status_t
-_cairo_ft_font_text_to_glyphs (void *abstract_font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *nglyphs)
+_cairo_ft_scaled_font_text_to_glyphs (void *abstract_font,
+ const char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs)
{
double x = 0., y = 0.;
size_t i;
uint32_t *ucs4 = NULL;
- cairo_ft_font_t *font = abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = abstract_font;
FT_Face face;
cairo_glyph_cache_key_t key;
cairo_image_glyph_cache_entry_t *val;
cairo_cache_t *cache = NULL;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
- _cairo_ft_font_get_glyph_cache_key (font, &key);
+ _cairo_ft_scaled_font_get_glyph_cache_key (scaled_font, &key);
- status = _cairo_utf8_to_ucs4 (utf8, -1, &ucs4, nglyphs);
+ status = _cairo_utf8_to_ucs4 ((unsigned char*)utf8, -1, &ucs4, num_glyphs);
if (!CAIRO_OK (status))
return status;
- face = cairo_ft_font_lock_face ((cairo_font_t *)font);
+ face = cairo_ft_scaled_font_lock_face (&scaled_font->base);
if (!face) {
status = CAIRO_STATUS_NO_MEMORY;
goto FAIL1;
@@ -754,13 +879,13 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
goto FAIL2;
}
- *glyphs = (cairo_glyph_t *) malloc ((*nglyphs) * (sizeof (cairo_glyph_t)));
+ *glyphs = (cairo_glyph_t *) malloc ((*num_glyphs) * (sizeof (cairo_glyph_t)));
if (*glyphs == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto FAIL2;
}
- for (i = 0; i < *nglyphs; i++)
+ for (i = 0; i < *num_glyphs; i++)
{
(*glyphs)[i].index = FT_Get_Char_Index (face, ucs4[i]);
(*glyphs)[i].x = x;
@@ -781,7 +906,7 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
if (cache)
_cairo_unlock_global_image_glyph_cache ();
- cairo_ft_font_unlock_face ((cairo_font_t *)font);
+ cairo_ft_scaled_font_unlock_face (&scaled_font->base);
FAIL1:
free (ucs4);
@@ -791,49 +916,50 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
static cairo_status_t
-_cairo_ft_font_font_extents (void *abstract_font,
- cairo_font_extents_t *extents)
+_cairo_ft_scaled_font_font_extents (void *abstract_font,
+ cairo_font_extents_t *extents)
{
- cairo_ft_font_t *font = abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = abstract_font;
FT_Face face;
FT_Size_Metrics *metrics;
- face = _ft_unscaled_font_lock_face (font->unscaled);
+ face = _ft_unscaled_font_lock_face (scaled_font->unscaled);
if (!face)
return CAIRO_STATUS_NO_MEMORY;
metrics = &face->size->metrics;
- _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale);
+ _ft_unscaled_font_set_scale (scaled_font->unscaled, &scaled_font->base.scale);
/*
* Get to unscaled metrics so that the upper level can get back to
* user space
*/
- extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / font->unscaled->y_scale;
- extents->descent = DOUBLE_FROM_26_6(metrics->descender) / font->unscaled->y_scale;
- extents->height = DOUBLE_FROM_26_6(metrics->height) / font->unscaled->y_scale;
- extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / font->unscaled->x_scale;
+ extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / scaled_font->unscaled->y_scale;
+ extents->descent = DOUBLE_FROM_26_6(- metrics->descender) / scaled_font->unscaled->y_scale;
+ extents->height = DOUBLE_FROM_26_6(metrics->height) / scaled_font->unscaled->y_scale;
+ extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / scaled_font->unscaled->x_scale;
/* FIXME: this doesn't do vertical layout atm. */
extents->max_y_advance = 0.0;
- _ft_unscaled_font_unlock_face (font->unscaled);
+ _ft_unscaled_font_unlock_face (scaled_font->unscaled);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_ft_font_glyph_extents (void *abstract_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
+_cairo_ft_scaled_font_glyph_extents (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
{
int i;
- cairo_ft_font_t *font = abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = abstract_font;
cairo_point_double_t origin;
cairo_point_double_t glyph_min, glyph_max;
- cairo_point_double_t total_min, total_max;
+ /* Initialize just to squelch anti-helpful compiler warning. */
+ cairo_point_double_t total_min = { 0, 0}, total_max = {0,0};
cairo_image_glyph_cache_entry_t *img = NULL;
cairo_cache_t *cache;
@@ -861,7 +987,7 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
return CAIRO_STATUS_NO_MEMORY;
}
- _cairo_ft_font_get_glyph_cache_key (font, &key);
+ _cairo_ft_scaled_font_get_glyph_cache_key (scaled_font, &key);
for (i = 0; i < num_glyphs; i++)
{
@@ -874,7 +1000,7 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
/* XXX: Need to add code here to check the font's FcPattern
for FC_VERTICAL_LAYOUT and if set get vertBearingX/Y
instead. This will require that
- cairo_ft_font_create_for_ft_face accept an
+ cairo_ft_scaled_font_create_for_ft_face accept an
FcPattern. */
glyph_min.x = glyphs[i].x + img->extents.x_bearing;
glyph_min.y = glyphs[i].y + img->extents.y_bearing;
@@ -910,15 +1036,15 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
static cairo_status_t
-_cairo_ft_font_glyph_bbox (void *abstract_font,
- const cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox)
+_cairo_ft_scaled_font_glyph_bbox (void *abstract_font,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
{
cairo_image_glyph_cache_entry_t *img;
cairo_cache_t *cache;
cairo_glyph_cache_key_t key;
- cairo_ft_font_t *font = abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = abstract_font;
cairo_fixed_t x1, y1, x2, y2;
int i;
@@ -930,13 +1056,13 @@ _cairo_ft_font_glyph_bbox (void *abstract_font,
cache = _cairo_get_global_image_glyph_cache();
if (cache == NULL
- || font == NULL
+ || scaled_font == NULL
|| glyphs == NULL) {
_cairo_unlock_global_image_glyph_cache ();
return CAIRO_STATUS_NO_MEMORY;
}
- _cairo_ft_font_get_glyph_cache_key (font, &key);
+ _cairo_ft_scaled_font_get_glyph_cache_key (scaled_font, &key);
for (i = 0; i < num_glyphs; i++)
{
@@ -972,23 +1098,23 @@ _cairo_ft_font_glyph_bbox (void *abstract_font,
static cairo_status_t
-_cairo_ft_font_show_glyphs (void *abstract_font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
+_cairo_ft_scaled_font_show_glyphs (void *abstract_font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
{
cairo_image_glyph_cache_entry_t *img;
cairo_cache_t *cache;
cairo_glyph_cache_key_t key;
- cairo_ft_font_t *font = abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = abstract_font;
cairo_surface_pattern_t glyph_pattern;
cairo_status_t status;
int x, y;
@@ -998,7 +1124,7 @@ _cairo_ft_font_show_glyphs (void *abstract_font,
cache = _cairo_get_global_image_glyph_cache();
if (cache == NULL
- || font == NULL
+ || scaled_font == NULL
|| pattern == NULL
|| surface == NULL
|| glyphs == NULL) {
@@ -1006,9 +1132,9 @@ _cairo_ft_font_show_glyphs (void *abstract_font,
return CAIRO_STATUS_NO_MEMORY;
}
- key.unscaled = (cairo_unscaled_font_t *)font->unscaled;
- key.scale = font->base.scale;
- key.flags = font->load_flags;
+ key.unscaled = &scaled_font->unscaled->base;
+ key.scale = scaled_font->base.scale;
+ key.flags = scaled_font->load_flags;
for (i = 0; i < num_glyphs; i++)
{
@@ -1054,14 +1180,14 @@ _cairo_ft_font_show_glyphs (void *abstract_font,
static int
_move_to (FT_Vector *to, void *closure)
{
- cairo_path_t *path = closure;
- cairo_point_t point;
+ cairo_path_fixed_t *path = closure;
+ cairo_fixed_t x, y;
- point.x = _cairo_fixed_from_26_6 (to->x);
- point.y = _cairo_fixed_from_26_6 (to->y);
+ x = _cairo_fixed_from_26_6 (to->x);
+ y = _cairo_fixed_from_26_6 (to->y);
- _cairo_path_close_path (path);
- _cairo_path_move_to (path, &point);
+ _cairo_path_fixed_close_path (path);
+ _cairo_path_fixed_move_to (path, x, y);
return 0;
}
@@ -1069,13 +1195,13 @@ _move_to (FT_Vector *to, void *closure)
static int
_line_to (FT_Vector *to, void *closure)
{
- cairo_path_t *path = closure;
- cairo_point_t point;
+ cairo_path_fixed_t *path = closure;
+ cairo_fixed_t x, y;
- point.x = _cairo_fixed_from_26_6 (to->x);
- point.y = _cairo_fixed_from_26_6 (to->y);
+ x = _cairo_fixed_from_26_6 (to->x);
+ y = _cairo_fixed_from_26_6 (to->y);
- _cairo_path_line_to (path, &point);
+ _cairo_path_fixed_line_to (path, x, y);
return 0;
}
@@ -1083,27 +1209,32 @@ _line_to (FT_Vector *to, void *closure)
static int
_conic_to (FT_Vector *control, FT_Vector *to, void *closure)
{
- cairo_path_t *path = closure;
+ cairo_path_fixed_t *path = closure;
- cairo_point_t p0, p1, p2, p3;
+ cairo_fixed_t x0, y0;
+ cairo_fixed_t x1, y1;
+ cairo_fixed_t x2, y2;
+ cairo_fixed_t x3, y3;
cairo_point_t conic;
- _cairo_path_current_point (path, &p0);
+ _cairo_path_fixed_get_current_point (path, &x0, &y0);
conic.x = _cairo_fixed_from_26_6 (control->x);
conic.y = _cairo_fixed_from_26_6 (control->y);
- p3.x = _cairo_fixed_from_26_6 (to->x);
- p3.y = _cairo_fixed_from_26_6 (to->y);
+ x3 = _cairo_fixed_from_26_6 (to->x);
+ y3 = _cairo_fixed_from_26_6 (to->y);
- p1.x = p0.x + 2.0/3.0 * (conic.x - p0.x);
- p1.y = p0.y + 2.0/3.0 * (conic.y - p0.y);
+ x1 = x0 + 2.0/3.0 * (conic.x - x0);
+ y1 = y0 + 2.0/3.0 * (conic.y - y0);
- p2.x = p3.x + 2.0/3.0 * (conic.x - p3.x);
- p2.y = p3.y + 2.0/3.0 * (conic.y - p3.y);
+ x2 = x3 + 2.0/3.0 * (conic.x - x3);
+ y2 = y3 + 2.0/3.0 * (conic.y - y3);
- _cairo_path_curve_to (path,
- &p1, &p2, &p3);
+ _cairo_path_fixed_curve_to (path,
+ x1, y1,
+ x2, y2,
+ x3, y3);
return 0;
}
@@ -1111,31 +1242,36 @@ _conic_to (FT_Vector *control, FT_Vector *to, void *closure)
static int
_cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closure)
{
- cairo_path_t *path = closure;
- cairo_point_t p0, p1, p2;
+ cairo_path_fixed_t *path = closure;
+ cairo_fixed_t x0, y0;
+ cairo_fixed_t x1, y1;
+ cairo_fixed_t x2, y2;
- p0.x = _cairo_fixed_from_26_6 (control1->x);
- p0.y = _cairo_fixed_from_26_6 (control1->y);
+ x0 = _cairo_fixed_from_26_6 (control1->x);
+ y0 = _cairo_fixed_from_26_6 (control1->y);
- p1.x = _cairo_fixed_from_26_6 (control2->x);
- p1.y = _cairo_fixed_from_26_6 (control2->y);
+ x1 = _cairo_fixed_from_26_6 (control2->x);
+ y1 = _cairo_fixed_from_26_6 (control2->y);
- p2.x = _cairo_fixed_from_26_6 (to->x);
- p2.y = _cairo_fixed_from_26_6 (to->y);
+ x2 = _cairo_fixed_from_26_6 (to->x);
+ y2 = _cairo_fixed_from_26_6 (to->y);
- _cairo_path_curve_to (path, &p0, &p1, &p2);
+ _cairo_path_fixed_curve_to (path,
+ x0, y0,
+ x1, y1,
+ x2, y2);
return 0;
}
static cairo_status_t
-_cairo_ft_font_glyph_path (void *abstract_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path)
+_cairo_ft_scaled_font_glyph_path (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_fixed_t *path)
{
int i;
- cairo_ft_font_t *font = abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = abstract_font;
FT_GlyphSlot glyph;
FT_Face face;
FT_Error error;
@@ -1148,7 +1284,7 @@ _cairo_ft_font_glyph_path (void *abstract_font,
0, /* delta */
};
- face = cairo_ft_font_lock_face (abstract_font);
+ face = cairo_ft_scaled_font_lock_face (abstract_font);
if (!face)
return CAIRO_STATUS_NO_MEMORY;
@@ -1161,7 +1297,7 @@ _cairo_ft_font_glyph_path (void *abstract_font,
0, DOUBLE_TO_16_16 (-1.0),
};
- error = FT_Load_Glyph (font->unscaled->face, glyphs[i].index, font->load_flags | FT_LOAD_NO_BITMAP);
+ error = FT_Load_Glyph (scaled_font->unscaled->face, glyphs[i].index, scaled_font->load_flags | FT_LOAD_NO_BITMAP);
/* XXX: What to do in this error case? */
if (error)
continue;
@@ -1176,148 +1312,136 @@ _cairo_ft_font_glyph_path (void *abstract_font,
DOUBLE_TO_26_6(glyphs[i].y));
FT_Outline_Decompose (&glyph->outline, &outline_funcs, path);
}
- _cairo_path_close_path (path);
+ _cairo_path_fixed_close_path (path);
- cairo_ft_font_unlock_face (abstract_font);
+ cairo_ft_scaled_font_unlock_face (abstract_font);
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_ft_font_create_glyph (cairo_image_glyph_cache_entry_t *val)
-{
- ft_unscaled_font_t *unscaled = (ft_unscaled_font_t *)val->key.unscaled;
- FT_GlyphSlot glyphslot;
- unsigned int width, height, stride;
- FT_Face face;
- FT_Outline *outline;
- FT_BBox cbox;
- FT_Bitmap bitmap;
- FT_Glyph_Metrics *metrics;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
- glyphslot = unscaled->face->glyph;
- metrics = &glyphslot->metrics;
+const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend = {
+ _cairo_ft_scaled_font_create,
+ _cairo_ft_scaled_font_destroy,
+ _cairo_ft_scaled_font_font_extents,
+ _cairo_ft_scaled_font_text_to_glyphs,
+ _cairo_ft_scaled_font_glyph_extents,
+ _cairo_ft_scaled_font_glyph_bbox,
+ _cairo_ft_scaled_font_show_glyphs,
+ _cairo_ft_scaled_font_glyph_path,
+ _cairo_ft_scaled_font_get_glyph_cache_key,
+};
- face = _ft_unscaled_font_lock_face (unscaled);
- if (!face)
- return CAIRO_STATUS_NO_MEMORY;
+/* ft_font_face_t */
- _ft_unscaled_font_set_scale (unscaled, &val->key.scale);
-
- if (FT_Load_Glyph (face, val->key.index, val->key.flags) != 0) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
+static void
+_ft_font_face_destroy (void *abstract_face)
+{
+ ft_font_face_t *font_face = abstract_face;
+
+ ft_font_face_t *tmp_face = NULL;
+ ft_font_face_t *last_face = NULL;
- /*
- * Note: the font's coordinate system is upside down from ours, so the
- * Y coordinates of the bearing and advance need to be negated.
+ /* When destroying the face created by cairo_ft_font_face_create_for_ft_face,
+ * we have a special "zombie" state for the face when the unscaled font
+ * is still alive but there are no public references to the font face.
*
- * Scale metrics back to glyph space from the scaled glyph space returned
- * by FreeType
+ * We go from:
+ *
+ * font_face ------> unscaled
+ * <-....weak....../
+ *
+ * To:
+ *
+ * font_face <------- unscaled
*/
- val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / unscaled->x_scale;
- val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / unscaled->y_scale;
+ if (font_face->unscaled &&
+ font_face->unscaled->from_face &&
+ font_face->unscaled->base.refcount > 1) {
+ cairo_font_face_reference (&font_face->base);
+
+ _cairo_unscaled_font_destroy (&font_face->unscaled->base);
+ font_face->unscaled = NULL;
+
+ return;
+ }
+
+ if (font_face->unscaled) {
+ /* Remove face from linked list */
+ for (tmp_face = font_face->unscaled->faces; tmp_face; tmp_face = tmp_face->next_face) {
+ if (tmp_face == font_face) {
+ if (last_face)
+ last_face->next_face = tmp_face->next_face;
+ else
+ font_face->unscaled->faces = tmp_face->next_face;
+ }
+
+ last_face = tmp_face;
+ }
- val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / unscaled->x_scale;
- val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / unscaled->y_scale;
+ _cairo_unscaled_font_destroy (&font_face->unscaled->base);
+ font_face->unscaled = NULL;
+ }
+}
- /*
- * use untransformed advance values
- * XXX uses horizontal advance only at present;
- should provide FT_LOAD_VERTICAL_LAYOUT
- */
+static cairo_status_t
+_ft_font_face_create_font (void *abstract_face,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ cairo_scaled_font_t **scaled_font)
+{
+ ft_font_face_t *font_face = abstract_face;
- val->extents.x_advance = DOUBLE_FROM_26_6 (face->glyph->metrics.horiAdvance) / unscaled->x_scale;
- val->extents.y_advance = 0 / unscaled->y_scale;
-
- outline = &glyphslot->outline;
+ *scaled_font = _ft_scaled_font_create (font_face->unscaled,
+ font_face->load_flags,
+ font_matrix, ctm);
+ if (*scaled_font)
+ return CAIRO_STATUS_SUCCESS;
+ else
+ return CAIRO_STATUS_NO_MEMORY;
+}
- FT_Outline_Get_CBox (outline, &cbox);
+static const cairo_font_face_backend_t _ft_font_face_backend = {
+ _ft_font_face_destroy,
+ _ft_font_face_create_font,
+};
- cbox.xMin &= -64;
- cbox.yMin &= -64;
- cbox.xMax = (cbox.xMax + 63) & -64;
- cbox.yMax = (cbox.yMax + 63) & -64;
-
- width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6);
- height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6);
- stride = (width + 3) & -4;
-
- if (width * height == 0)
- val->image = NULL;
- else
- {
+static cairo_font_face_t *
+_ft_font_face_create (ft_unscaled_font_t *unscaled,
+ int load_flags)
+{
+ ft_font_face_t *font_face;
- bitmap.pixel_mode = ft_pixel_mode_grays;
- bitmap.num_grays = 256;
- bitmap.width = width;
- bitmap.rows = height;
- bitmap.pitch = stride;
- bitmap.buffer = calloc (1, stride * height);
-
- if (bitmap.buffer == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
+ /* Looked for an existing matching font face */
+ for (font_face = unscaled->faces; font_face; font_face = font_face->next_face) {
+ if (font_face->load_flags == load_flags) {
+ cairo_font_face_reference (&font_face->base);
+ return &font_face->base;
}
-
- FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin);
-
- if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) {
- free (bitmap.buffer);
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
-
- val->image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data ((char *) bitmap.buffer,
- CAIRO_FORMAT_A8,
- width, height, stride);
- if (val->image == NULL) {
- free (bitmap.buffer);
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
-
- _cairo_image_surface_assume_ownership_of_data (val->image);
}
- /*
- * Note: the font's coordinate system is upside down from ours, so the
- * Y coordinate of the control box needs to be negated.
- */
-
- val->size.width = (unsigned short) width;
- val->size.height = (unsigned short) height;
- val->size.x = (short) (cbox.xMin >> 6);
- val->size.y = - (short) (cbox.yMax >> 6);
+ /* No match found, create a new one */
+ font_face = malloc (sizeof (ft_font_face_t));
+ if (!font_face)
+ return NULL;
- FAIL:
- _ft_unscaled_font_unlock_face (unscaled);
+ font_face->unscaled = unscaled;
+ _cairo_unscaled_font_reference (&unscaled->base);
- return status;
-}
+ font_face->load_flags = load_flags;
-const cairo_font_backend_t cairo_ft_font_backend = {
- _cairo_ft_font_create,
- _cairo_ft_font_destroy_font,
- _cairo_ft_font_destroy_unscaled_font,
- _cairo_ft_font_font_extents,
- _cairo_ft_font_text_to_glyphs,
- _cairo_ft_font_glyph_extents,
- _cairo_ft_font_glyph_bbox,
- _cairo_ft_font_show_glyphs,
- _cairo_ft_font_glyph_path,
- _cairo_ft_font_get_glyph_cache_key,
- _cairo_ft_font_create_glyph
-};
+ font_face->next_face = unscaled->faces;
+ unscaled->faces = font_face;
+
+ _cairo_font_face_init (&font_face->base, &_ft_font_face_backend);
+
+ return &font_face->base;
+}
/* implement the platform-specific interface */
/**
- * cairo_ft_font_create:
+ * cairo_ft_font_face_create_for_pattern:
* @pattern: A fully resolved fontconfig
* pattern. A pattern can be resolved, by, among other things, calling
* FcConfigSubstitute(), FcDefaultSubstitute(), then
@@ -1325,112 +1449,83 @@ const cairo_font_backend_t cairo_ft_font_backend = {
* pattern, so you should not further modify the pattern, but you can
* release your reference to the pattern with FcPatternDestroy() if
* you no longer need to access it.
- * @scale: The scale at which this font will be used. The
- * scale is given by multiplying the font matrix (see
- * cairo_transform_font()) by the current transformation matrix.
- * The translation elements of the resulting matrix are ignored.
*
- * Creates a new font for the FreeType font backend based on a
+ * Creates a new font face for the FreeType font backend based on a
* fontconfig pattern. This font can then be used with
- * cairo_set_font(), cairo_font_glyph_extents(), or FreeType backend
- * specific functions like cairo_ft_font_lock_face().
+ * cairo_set_font_face() or cairo_font_create(). The #cairo_scaled_font_t
+ * returned from cairo_font_create() is also for the FreeType backend
+ * and can be used with functions such as cairo_ft_font_lock_face().
*
- * Return value: a newly created #cairo_font_t. Free with
- * cairo_font_destroy() when you are done using it.
+ * Return value: a newly created #cairo_font_face_t. Free with
+ * cairo_font_face_destroy() when you are done using it.
**/
-cairo_font_t *
-cairo_ft_font_create (FcPattern *pattern,
- cairo_matrix_t *scale)
-{
- cairo_font_scale_t sc;
- double tx, ty;
+cairo_font_face_t *
+cairo_ft_font_face_create_for_pattern (FcPattern *pattern)
+{
+ ft_unscaled_font_t *unscaled;
+ cairo_font_face_t *font_face;
- cairo_matrix_get_affine (scale,
- &sc.matrix[0][0], &sc.matrix[0][1],
- &sc.matrix[1][0], &sc.matrix[1][1],
- &tx, &ty);
+ unscaled = _ft_unscaled_font_get_for_pattern (pattern);
+ if (unscaled == NULL)
+ return NULL;
- return _ft_font_create (pattern, &sc);
+ font_face = _ft_font_face_create (unscaled, _get_load_flags (pattern));
+ _cairo_unscaled_font_destroy (&unscaled->base);
+
+ return font_face;
}
/**
* cairo_ft_font_create_for_ft_face:
* @face: A FreeType face object, already opened. This must
- * be kept around until the font object's refcount drops to
- * zero and it is freed. The font object can be kept alive by
- * internal caching, so it's safest to keep the face object
- * around forever.
+ * be kept around until the face's refcount drops to
+ * zero and it is freed. Since the face may be referenced
+ * internally to Cairo, the best way to determine when it
+ * is safe to free the face is to pass a
+ * #cairo_destroy_func_t to cairo_font_face_set_user_data()
* @load_flags: The flags to pass to FT_Load_Glyph when loading
* glyphs from the font. These flags control aspects of
* rendering such as hinting and antialiasing. See the FreeType
* docs for full information.
- * @scale: The scale at which this font will be used. The
- * scale is given by multiplying the font matrix (see
- * cairo_transform_font()) by the current transformation matrix.
- * The translation elements of the resulting matrix are ignored.
*
- * Creates a new font forthe FreeType font backend from a pre-opened
- * FreeType face. This font can then be used with cairo_set_font(),
- * cairo_font_glyph_extents(), or FreeType backend specific
- * functions like cairo_ft_font_lock_face() Cairo will determine the
- * pixel size and transformation from the @scale parameter and call
- * FT_Set_Transform() and FT_Set_Pixel_Sizes().
+ * Creates a new font face for the FreeType font backend from a pre-opened
+ * FreeType face. This font can then be used with
+ * cairo_set_font_face() or cairo_font_create(). The #cairo_scaled_font_t
+ * returned from cairo_font_create() is also for the FreeType backend
+ * and can be used with functions such as cairo_ft_font_lock_face().
*
- * Return value: a newly created #cairo_font_t. Free with
- * cairo_font_destroy() when you are done using it.
+ * Return value: a newly created #cairo_font_face_t. Free with
+ * cairo_font_face_destroy() when you are done using it.
**/
-cairo_font_t *
-cairo_ft_font_create_for_ft_face (FT_Face face,
- int load_flags,
- cairo_matrix_t *scale)
+cairo_font_face_t *
+cairo_ft_font_face_create_for_ft_face (FT_Face face,
+ int load_flags)
{
- cairo_ft_font_t *f = NULL;
- ft_unscaled_font_t *unscaled = NULL;
- cairo_font_scale_t sc;
- double tx, ty;
+ ft_unscaled_font_t *unscaled;
+ cairo_font_face_t *font_face;
unscaled = _ft_unscaled_font_create_from_face (face);
if (unscaled == NULL)
return NULL;
- f = malloc (sizeof(cairo_ft_font_t));
- if (f == NULL)
- goto FREE_UNSCALED;
-
- f->unscaled = unscaled;
- f->pattern = NULL;
- f->load_flags = load_flags;
-
- cairo_matrix_get_affine (scale,
- &sc.matrix[0][0], &sc.matrix[0][1],
- &sc.matrix[1][0], &sc.matrix[1][1],
- &tx, &ty);
-
- _cairo_font_init ((cairo_font_t *)f, &sc, &cairo_ft_font_backend);
-
- return (cairo_font_t *)f;
-
- FREE_UNSCALED:
- _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled);
+ font_face = _ft_font_face_create (unscaled, load_flags);
+ _cairo_unscaled_font_destroy (&unscaled->base);
- return NULL;
+ return font_face;
}
-
/**
- * cairo_ft_font_lock_face:
- * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
- * object can be created with cairo_ft_font_create() or
- * cairo_ft_font_create_for_ft_face(). On some platforms the font from
- * cairo_current_font() will also be a FreeType font, but using this
- * functionality with fonts you don't create yourself is not
- * recommended.
+ * cairo_ft_scaled_font_lock_face:
+ * @scaled_font: A #cairo_scaled_font_t from the FreeType font backend. Such an
+ * object can be created by calling cairo_scaled_font_create() on a
+ * FreeType backend font face (see cairo_ft_font_face_create_for_pattern(),
+ * cairo_ft_font_face_create_for_face()).
*
* cairo_ft_font_lock_face() gets the #FT_Face object from a FreeType
* backend font and scales it appropriately for the font. You must
* release the face with cairo_ft_font_unlock_face()
* when you are done using it. Since the #FT_Face object can be
- * shared between multiple #cairo_font_t objects, you must not
+ * shared between multiple #cairo_scaled_font_t objects, you must not
* lock any other font objects until you unlock this one. A count is
* kept of the number of times cairo_ft_font_lock_face() is
* called. cairo_ft_font_unlock_face() must be called the same number
@@ -1447,67 +1542,36 @@ cairo_ft_font_create_for_ft_face (FT_Face face,
* Return value: The #FT_Face object for @font, scaled appropriately.
**/
FT_Face
-cairo_ft_font_lock_face (cairo_font_t *abstract_font)
+cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font)
{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font;
FT_Face face;
- face = _ft_unscaled_font_lock_face (font->unscaled);
+ face = _ft_unscaled_font_lock_face (scaled_font->unscaled);
if (!face)
return NULL;
- _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale);
+ _ft_unscaled_font_set_scale (scaled_font->unscaled, &scaled_font->base.scale);
return face;
}
/**
- * cairo_ft_font_unlock_face:
- * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
- * object can be created with cairo_ft_font_create() or
- * cairo_ft_font_create_for_ft_face(). On some platforms the font from
- * cairo_current_font() will also be a FreeType font, but using this
- * functionality with fonts you don't create yourself is not
- * recommended.
+ * cairo_ft_scaled_font_unlock_face:
+ * @scaled_font: A #cairo_scaled_font_t from the FreeType font backend. Such an
+ * object can be created by calling cairo_scaled_font_create() on a
+ * FreeType backend font face (see cairo_ft_font_face_create_for_pattern(),
+ * cairo_ft_font_face_create_for_face()).
*
* Releases a face obtained with cairo_ft_font_lock_face(). See the
* documentation for that function for full details.
**/
void
-cairo_ft_font_unlock_face (cairo_font_t *abstract_font)
-{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
-
- _ft_unscaled_font_unlock_face (font->unscaled);
-}
-
-/**
- * cairo_ft_font_get_pattern:
- * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
- * object can be created with cairo_ft_font_create() or
- * cairo_ft_font_create_for_ft_face(). On some platforms the font from
- * cairo_current_font() will also be a FreeType font, but using this
- * functionality with fonts you don't create yourself is not
- * recommended.
- *
- * cairo_ft_font_get_pattern() gets the #FcPattern for a FreeType
- * backend font.
-
- * Return value: The #FcPattenr for @font. The return value is owned
- * by the font, so you must not modify it, and must call
- * FcPatternReference() to keep a persistant reference to the
- * pattern. If the font was created with cairo_ft_font_create_for_ft_face()
- * returns %NULL.
- **/
-FcPattern *
-cairo_ft_font_get_pattern (cairo_font_t *abstract_font)
+cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *abstract_font)
{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
-
- if (font == NULL)
- return NULL;
+ cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font;
- return font->pattern;
+ _ft_unscaled_font_unlock_face (scaled_font->unscaled);
}
/* We expose our unscaled font implementation internally for the the
@@ -1515,11 +1579,11 @@ cairo_ft_font_get_pattern (cairo_font_t *abstract_font)
* fonts-on-disk used by a document, so it can embed them.
*/
cairo_unscaled_font_t *
-_cairo_ft_font_get_unscaled_font (cairo_font_t *abstract_font)
+_cairo_ft_scaled_font_get_unscaled_font (cairo_scaled_font_t *abstract_font)
{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font;
- return (cairo_unscaled_font_t *)font->unscaled;
+ return &scaled_font->unscaled->base;
}
/* This differs from _cairo_ft_scaled_font_lock_face in that it doesn't
diff --git a/src/cairo-ft-private.h b/src/cairo-ft-private.h
index 37a6feecc..494d8369a 100644
--- a/src/cairo-ft-private.h
+++ b/src/cairo-ft-private.h
@@ -40,7 +40,7 @@
#include <cairo-ft.h>
#include <cairoint.h>
-#ifdef CAIRO_HAS_FT_FONT
+#if CAIRO_HAS_FT_FONT
CAIRO_BEGIN_DECLS
@@ -48,7 +48,7 @@ CAIRO_BEGIN_DECLS
* the different fonts-on-disk used by a document, so it can embed them
*/
cairo_private cairo_unscaled_font_t *
-_cairo_ft_font_get_unscaled_font (cairo_font_t *font);
+_cairo_ft_scaled_font_get_unscaled_font (cairo_scaled_font_t *scaled_font);
cairo_private FT_Face
_cairo_ft_unscaled_font_lock_face (cairo_unscaled_font_t *unscaled_font);
diff --git a/src/cairo-ft.h b/src/cairo-ft.h
index f10c67d80..4e8b8bcdb 100644
--- a/src/cairo-ft.h
+++ b/src/cairo-ft.h
@@ -39,7 +39,7 @@
#include <cairo.h>
-#ifdef CAIRO_HAS_FT_FONT
+#if CAIRO_HAS_FT_FONT
/* Fontconfig/Freetype platform-specific font interface */
@@ -49,25 +49,23 @@
CAIRO_BEGIN_DECLS
-cairo_font_t *
-cairo_ft_font_create (FcPattern *pattern,
- cairo_matrix_t *scale);
+cairo_font_face_t *
+cairo_ft_font_face_create_for_pattern (FcPattern *pattern);
-cairo_font_t *
-cairo_ft_font_create_for_ft_face (FT_Face face,
- int load_flags,
- cairo_matrix_t *scale);
+cairo_font_face_t *
+cairo_ft_font_face_create_for_ft_face (FT_Face face,
+ int load_flags);
FT_Face
-cairo_ft_font_lock_face (cairo_font_t *ft_font);
+cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *scaled_font);
void
-cairo_ft_font_unlock_face (cairo_font_t *ft_font);
-
-FcPattern *
-cairo_ft_font_get_pattern (cairo_font_t *ft_font);
+cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *scaled_font);
CAIRO_END_DECLS
+#else /* CAIRO_HAS_FT_FONT */
+# error Cairo was not compiled with support for the freetype font backend
#endif /* CAIRO_HAS_FT_FONT */
+
#endif /* CAIRO_FT_H */
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index ee664e1cc..673b972c3 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -27,25 +27,6 @@
#include "cairoint.h"
#include "cairo-glitz.h"
-void
-cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface)
-{
- cairo_surface_t *crsurface;
-
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
-
- crsurface = cairo_glitz_surface_create (surface);
- if (crsurface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface (cr, crsurface);
-
- cairo_surface_destroy (crsurface);
-}
-
typedef struct _cairo_glitz_surface {
cairo_surface_t base;
@@ -54,8 +35,8 @@ typedef struct _cairo_glitz_surface {
pixman_region16_t *clip;
} cairo_glitz_surface_t;
-static void
-_cairo_glitz_surface_destroy (void *abstract_surface)
+static cairo_status_t
+_cairo_glitz_surface_finish (void *abstract_surface)
{
cairo_glitz_surface_t *surface = abstract_surface;
@@ -66,7 +47,8 @@ _cairo_glitz_surface_destroy (void *abstract_surface)
}
glitz_surface_destroy (surface->surface);
- free (surface);
+
+ return CAIRO_STATUS_SUCCESS;
}
static glitz_format_name_t
@@ -115,12 +97,6 @@ _cairo_glitz_surface_create_similar (void *abstract_src,
return crsurface;
}
-static double
-_cairo_glitz_surface_pixels_per_inch (void *abstract_surface)
-{
- return 96.0;
-}
-
static cairo_status_t
_cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
cairo_rectangle_t *interest,
@@ -130,7 +106,7 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
cairo_image_surface_t *image;
int x1, y1, x2, y2;
int width, height;
- char *pixels;
+ unsigned char *pixels;
cairo_format_masks_t format;
glitz_buffer_t *buffer;
glitz_pixel_format_t pf;
@@ -402,17 +378,17 @@ _cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *surface,
{
glitz_transform_t transform;
- transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
- transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
- transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
+ transform.matrix[0][0] = _cairo_fixed_from_double (matrix->xx);
+ transform.matrix[0][1] = _cairo_fixed_from_double (matrix->xy);
+ transform.matrix[0][2] = _cairo_fixed_from_double (matrix->x0);
- transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
- transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
- transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
+ transform.matrix[1][0] = _cairo_fixed_from_double (matrix->yx);
+ transform.matrix[1][1] = _cairo_fixed_from_double (matrix->yy);
+ transform.matrix[1][2] = _cairo_fixed_from_double (matrix->y0);
transform.matrix[2][0] = 0;
transform.matrix[2][1] = 0;
- transform.matrix[2][2] = 1 << 16;
+ transform.matrix[2][2] = _cairo_fixed_from_double (1);
glitz_surface_set_transform (surface->surface, &transform);
}
@@ -423,32 +399,49 @@ _glitz_operator (cairo_operator_t op)
switch (op) {
case CAIRO_OPERATOR_CLEAR:
return GLITZ_OPERATOR_CLEAR;
- case CAIRO_OPERATOR_SRC:
+
+ case CAIRO_OPERATOR_SOURCE:
return GLITZ_OPERATOR_SRC;
- case CAIRO_OPERATOR_DST:
- return GLITZ_OPERATOR_DST;
- case CAIRO_OPERATOR_OVER_REVERSE:
- return GLITZ_OPERATOR_OVER_REVERSE;
+ case CAIRO_OPERATOR_OVER:
+ return GLITZ_OPERATOR_OVER;
case CAIRO_OPERATOR_IN:
return GLITZ_OPERATOR_IN;
- case CAIRO_OPERATOR_IN_REVERSE:
- return GLITZ_OPERATOR_IN_REVERSE;
case CAIRO_OPERATOR_OUT:
return GLITZ_OPERATOR_OUT;
- case CAIRO_OPERATOR_OUT_REVERSE:
- return GLITZ_OPERATOR_OUT_REVERSE;
case CAIRO_OPERATOR_ATOP:
return GLITZ_OPERATOR_ATOP;
- case CAIRO_OPERATOR_ATOP_REVERSE:
+
+ case CAIRO_OPERATOR_DEST:
+ return GLITZ_OPERATOR_DST;
+ case CAIRO_OPERATOR_DEST_OVER:
+ return GLITZ_OPERATOR_OVER_REVERSE;
+ case CAIRO_OPERATOR_DEST_IN:
+ return GLITZ_OPERATOR_IN_REVERSE;
+ case CAIRO_OPERATOR_DEST_OUT:
+ return GLITZ_OPERATOR_OUT_REVERSE;
+ case CAIRO_OPERATOR_DEST_ATOP:
return GLITZ_OPERATOR_ATOP_REVERSE;
+
case CAIRO_OPERATOR_XOR:
return GLITZ_OPERATOR_XOR;
case CAIRO_OPERATOR_ADD:
return GLITZ_OPERATOR_ADD;
- case CAIRO_OPERATOR_OVER:
- default:
+ case CAIRO_OPERATOR_SATURATE:
+ /* XXX: OVER is definitely not the right thing here, (but it
+ * is what the original glitz backend code has always
+ * done). Cairo's SATURATE operator is the native GL
+ * compositing mode, (from my understanding). So why isn't
+ * there a GLITZ_OPERATOR_SATURATE for us to use here? */
return GLITZ_OPERATOR_OVER;
}
+
+ ASSERT_NOT_REACHED;
+
+ /* Something's very broken if this line of code can be reached, so
+ we want to return something that would give a noticeably
+ incorrect result. The XOR operator seems so rearely desired
+ that it should fit the bill here. */
+ return CAIRO_OPERATOR_XOR;
}
static glitz_status_t
@@ -586,12 +579,12 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern,
pattern->filter != CAIRO_FILTER_BEST)
break;
- alpha = (gradient->stops[0].color.alpha * pattern->alpha) * 0xffff;
+ alpha = (gradient->stops[0].color.alpha) * 0xffff;
for (i = 1; i < gradient->n_stops; i++)
{
unsigned short a;
- a = (gradient->stops[i].color.alpha * pattern->alpha) * 0xffff;
+ a = (gradient->stops[i].color.alpha) * 0xffff;
if (a != alpha)
break;
}
@@ -733,7 +726,7 @@ _cairo_glitz_pattern_release_surface (cairo_glitz_surface_t *dst,
_cairo_pattern_release_surface (&dst->base, &surface->base,
&attr->base);
else
- _cairo_glitz_surface_destroy (surface);
+ cairo_surface_destroy (&surface->base);
}
static cairo_int_status_t
@@ -753,50 +746,30 @@ _cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src,
{
cairo_int_status_t status;
cairo_pattern_union_t tmp;
- cairo_bool_t src_opaque, mask_opaque;
- double src_alpha, mask_alpha;
- src_opaque = _cairo_pattern_is_opaque (src);
- mask_opaque = !mask || _cairo_pattern_is_opaque (mask);
-
- /* For surface patterns, we move any translucency from src->alpha
- * to mask->alpha so we can use the source unchanged. Otherwise we
- * move the translucency from mask->alpha to src->alpha so that
- * we can drop the mask if possible.
- */
- if (src->type == CAIRO_PATTERN_SURFACE)
- {
- if (mask) {
- mask_opaque = mask_opaque && src_opaque;
- mask_alpha = mask->alpha * src->alpha;
- } else {
- mask_opaque = src_opaque;
- mask_alpha = src->alpha;
- }
-
- src_alpha = 1.0;
- src_opaque = TRUE;
- }
- else
+ /* If src and mask are both solid, then the mask alpha can be
+ * combined into src and mask can be ignored. */
+
+ /* XXX: This optimization assumes that there is no color
+ * information in mask, so this will need to change when we
+ * support RENDER-style 4-channel masks. */
+
+ if (src->type == CAIRO_PATTERN_SOLID &&
+ mask->type == CAIRO_PATTERN_SOLID)
{
- if (mask)
- {
- src_opaque = mask_opaque && src_opaque;
- src_alpha = mask->alpha * src->alpha;
- /* FIXME: This needs changing when we support RENDER
- * style 4-channel masks.
- */
- if (mask->type == CAIRO_PATTERN_SOLID)
- mask = NULL;
- } else
- src_alpha = src->alpha;
+ cairo_color_t combined;
+ cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
+ cairo_solid_pattern_t *mask_solid = (cairo_solid_pattern_t *) mask;
- mask_alpha = 1.0;
- mask_opaque = TRUE;
- }
+ combined = src_solid->color;
+ _cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
- _cairo_pattern_init_copy (&tmp.base, src);
- _cairo_pattern_set_alpha (&tmp.base, src_alpha);
+ _cairo_pattern_init_solid (&tmp.solid, &combined);
+
+ mask = NULL;
+ } else {
+ _cairo_pattern_init_copy (&tmp.base, src);
+ }
status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
src_x, src_y,
@@ -808,14 +781,9 @@ _cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src,
if (status)
return status;
- if (mask || !mask_opaque)
+ if (mask)
{
- if (mask)
- _cairo_pattern_init_copy (&tmp.base, mask);
- else
- _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0);
-
- _cairo_pattern_set_alpha (&tmp.base, mask_alpha);
+ _cairo_pattern_init_copy (&tmp.base, mask);
status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
mask_x, mask_y,
@@ -937,7 +905,7 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
{
cairo_glitz_surface_t *dst = abstract_dst;
- if (op == CAIRO_OPERATOR_SRC)
+ if (op == CAIRO_OPERATOR_SOURCE)
{
glitz_color_t glitz_color;
@@ -969,6 +937,8 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
(cairo_color_t *) color);
if (!src)
return CAIRO_STATUS_NO_MEMORY;
+
+ glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT);
while (n_rects--)
{
@@ -1025,7 +995,6 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
cairo_pattern_union_t tmp;
_cairo_pattern_init_copy (&tmp.base, pattern);
- _cairo_pattern_set_alpha (&tmp.base, 1.0);
status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
src_x, src_y,
@@ -1033,8 +1002,6 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
&src, &attributes);
_cairo_pattern_fini (&tmp.base);
-
- alpha = pattern->alpha * 0xffff;
}
else
{
@@ -1042,8 +1009,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
src_x, src_y,
width, height,
&src, &attributes);
- alpha = 0xffff;
}
+ alpha = 0xffff;
if (status)
return status;
@@ -1076,7 +1043,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- color.red = color.green = color.blue = color.alpha = alpha;
+ color.red = color.green = color.blue = color.alpha = 0xffff;
glitz_set_rectangle (mask->surface, &clear_black, 0, 0, 1, 1);
glitz_set_rectangle (mask->surface, &color, 1, 0, 1, 1);
@@ -1135,7 +1102,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
else
{
cairo_image_surface_t *image;
- char *ptr;
+ unsigned char *ptr;
int stride;
stride = (width + 3) & -4;
@@ -1149,7 +1116,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
memset (data, 0, stride * height);
/* using negative stride */
- ptr = (char *) data + stride * (height - 1);
+ ptr = (unsigned char *) data + stride * (height - 1);
image = (cairo_image_surface_t *)
cairo_image_surface_create_for_data (ptr,
@@ -1166,18 +1133,6 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y,
(pixman_trapezoid_t *) traps, n_traps);
- if (alpha != 0xffff)
- {
- pixman_color_t color;
-
- color.red = color.green = color.blue = color.alpha = alpha;
-
- pixman_fill_rectangle (PIXMAN_OPERATOR_IN,
- image->pixman_image,
- &color,
- 0, 0, width, height);
- }
-
mask = (cairo_glitz_surface_t *)
_cairo_surface_create_similar_scratch (&dst->base,
CAIRO_FORMAT_A8, 0,
@@ -1228,18 +1183,6 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
}
static cairo_int_status_t
-_cairo_glitz_surface_copy_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_glitz_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
_cairo_glitz_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
@@ -1275,10 +1218,902 @@ _cairo_glitz_surface_set_clip_region (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
+static cairo_int_status_t
+_cairo_glitz_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t *rectangle)
+{
+ cairo_glitz_surface_t *surface = abstract_surface;
+
+ rectangle->x = 0;
+ rectangle->y = 0;
+ rectangle->width = glitz_surface_get_width (surface->surface);
+ rectangle->height = glitz_surface_get_height (surface->surface);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+#define CAIRO_GLITZ_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
+
+#define CAIRO_GLITZ_AREA_AVAILABLE 0
+#define CAIRO_GLITZ_AREA_DIVIDED 1
+#define CAIRO_GLITZ_AREA_OCCUPIED 2
+
+typedef struct _cairo_glitz_root_area cairo_glitz_root_area_t;
+
+typedef struct _cairo_glitz_area {
+ int state;
+ int level;
+ int x, y;
+ int width, height;
+ struct _cairo_glitz_area *area[4];
+ cairo_glitz_root_area_t *root;
+ void *closure;
+} cairo_glitz_area_t;
+
+static cairo_glitz_area_t _empty_area = {
+ 0, 0, 0, 0, 0, 0,
+ { NULL, NULL, NULL, NULL },
+ NULL,
+ NULL
+};
+
+typedef struct _cairo_glitz_area_funcs {
+ cairo_status_t (*move_in) (cairo_glitz_area_t *area,
+ void *closure);
+
+ void (*move_out) (cairo_glitz_area_t *area,
+ void *closure);
+
+ int (*compare_score) (cairo_glitz_area_t *area,
+ void *closure1,
+ void *closure2);
+} cairo_glitz_area_funcs_t;
+
+struct _cairo_glitz_root_area {
+ int max_level;
+ int width, height;
+ cairo_glitz_area_t *area;
+ const cairo_glitz_area_funcs_t *funcs;
+};
+
+static cairo_status_t
+_cairo_glitz_area_move_in (cairo_glitz_area_t *area,
+ void *closure)
+{
+ area->closure = closure;
+ area->state = CAIRO_GLITZ_AREA_OCCUPIED;
+
+ return (*area->root->funcs->move_in) (area, area->closure);
+}
+
+static void
+_cairo_glitz_area_move_out (cairo_glitz_area_t *area)
+{
+ (*area->root->funcs->move_out) (area, area->closure);
+
+ area->closure = NULL;
+ area->state = CAIRO_GLITZ_AREA_AVAILABLE;
+}
+
+static cairo_glitz_area_t *
+_cairo_glitz_area_create (cairo_glitz_root_area_t *root,
+ int level,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ cairo_glitz_area_t *area;
+ int n = 4;
+
+ area = malloc (sizeof (cairo_glitz_area_t));
+ if (!area)
+ return NULL;
+
+ area->level = level;
+ area->x = x;
+ area->y = y;
+ area->width = width;
+ area->height = height;
+ area->root = root;
+ area->closure = NULL;
+ area->state = CAIRO_GLITZ_AREA_AVAILABLE;
+
+ while (n--)
+ area->area[n] = NULL;
+
+ return area;
+}
+
+static void
+_cairo_glitz_area_destroy (cairo_glitz_area_t *area)
+{
+ if (!area)
+ return;
+
+ if (area->state == CAIRO_GLITZ_AREA_OCCUPIED)
+ {
+ _cairo_glitz_area_move_out (area);
+ }
+ else
+ {
+ int n = 4;
+
+ while (n--)
+ _cairo_glitz_area_destroy (area->area[n]);
+ }
+
+ free (area);
+}
+
+static cairo_glitz_area_t *
+_cairo_glitz_area_get_top_scored_sub_area (cairo_glitz_area_t *area)
+{
+ if (!area)
+ return NULL;
+
+ switch (area->state) {
+ case CAIRO_GLITZ_AREA_OCCUPIED:
+ return area;
+ case CAIRO_GLITZ_AREA_AVAILABLE:
+ break;
+ case CAIRO_GLITZ_AREA_DIVIDED: {
+ cairo_glitz_area_t *tmp, *top = NULL;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ tmp = _cairo_glitz_area_get_top_scored_sub_area (area->area[i]);
+ if (tmp && top)
+ {
+ if ((*area->root->funcs->compare_score) (tmp,
+ tmp->closure,
+ top->closure) > 0)
+ top = tmp;
+ }
+ else if (tmp)
+ {
+ top = tmp;
+ }
+ }
+ return top;
+ }
+ }
+
+ return NULL;
+}
+
+static cairo_int_status_t
+_cairo_glitz_area_find (cairo_glitz_area_t *area,
+ int width,
+ int height,
+ cairo_bool_t kick_out,
+ void *closure)
+{
+ if (area->width < width || area->height < height)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ switch (area->state) {
+ case CAIRO_GLITZ_AREA_OCCUPIED:
+ if (kick_out)
+ {
+ if ((*area->root->funcs->compare_score) (area,
+ area->closure,
+ closure) >= 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ _cairo_glitz_area_move_out (area);
+ } else
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* fall-through */
+ case CAIRO_GLITZ_AREA_AVAILABLE: {
+ if (area->level == area->root->max_level ||
+ (area->width == width && area->height == height))
+ {
+ return _cairo_glitz_area_move_in (area, closure);
+ }
+ else
+ {
+ int dx[4], dy[4], w[4], h[4], i;
+
+ dx[0] = dx[2] = dy[0] = dy[1] = 0;
+
+ w[0] = w[2] = dx[1] = dx[3] = width;
+ h[0] = h[1] = dy[2] = dy[3] = height;
+
+ w[1] = w[3] = area->width - width;
+ h[2] = h[3] = area->height - height;
+
+ for (i = 0; i < 2; i++)
+ {
+ if (w[i])
+ area->area[i] =
+ _cairo_glitz_area_create (area->root,
+ area->level + 1,
+ area->x + dx[i],
+ area->y + dy[i],
+ w[i], h[i]);
+ }
+
+ for (; i < 4; i++)
+ {
+ if (w[i] && h[i])
+ area->area[i] =
+ _cairo_glitz_area_create (area->root,
+ area->level + 1,
+ area->x + dx[i],
+ area->y + dy[i],
+ w[i], h[i]);
+ }
+
+ area->state = CAIRO_GLITZ_AREA_DIVIDED;
+
+ if (CAIRO_OK (_cairo_glitz_area_find (area->area[0],
+ width, height,
+ kick_out, closure)))
+ return CAIRO_STATUS_SUCCESS;
+ }
+ } break;
+ case CAIRO_GLITZ_AREA_DIVIDED: {
+ cairo_glitz_area_t *to_area;
+ int i, rejected = FALSE;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (area->area[i])
+ {
+ if (area->area[i]->width >= width &&
+ area->area[i]->height >= height)
+ {
+ if (CAIRO_OK (_cairo_glitz_area_find (area->area[i],
+ width, height,
+ kick_out, closure)))
+ return CAIRO_STATUS_SUCCESS;
+
+ rejected = TRUE;
+ }
+ }
+ }
+
+ if (rejected)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ to_area = _cairo_glitz_area_get_top_scored_sub_area (area);
+ if (to_area)
+ {
+ if (kick_out)
+ {
+ if ((*area->root->funcs->compare_score) (to_area,
+ to_area->closure,
+ closure) >= 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ } else
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ _cairo_glitz_area_destroy (area->area[i]);
+ area->area[i] = NULL;
+ }
+
+ area->closure = NULL;
+ area->state = CAIRO_GLITZ_AREA_AVAILABLE;
+ if (CAIRO_OK (_cairo_glitz_area_find (area, width, height,
+ TRUE, closure)))
+ return CAIRO_STATUS_SUCCESS;
+
+ } break;
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_status_t
+_cairo_glitz_root_area_init (cairo_glitz_root_area_t *root,
+ int max_level,
+ int width,
+ int height,
+ const cairo_glitz_area_funcs_t *funcs)
+{
+ root->max_level = max_level;
+ root->funcs = funcs;
+
+ root->area = _cairo_glitz_area_create (root, 0, 0, 0, width, height);
+ if (!root->area)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_glitz_root_area_fini (cairo_glitz_root_area_t *root)
+{
+ _cairo_glitz_area_destroy (root->area);
+}
+
+#define GLYPH_CACHE_TEXTURE_SIZE 512
+#define GLYPH_CACHE_MAX_LEVEL 64
+#define GLYPH_CACHE_MAX_HEIGHT 72
+#define GLYPH_CACHE_MAX_WIDTH 72
+
+#define WRITE_VEC2(ptr, _x, _y) \
+ *(ptr)++ = (_x); \
+ *(ptr)++ = (_y)
+
+#define WRITE_BOX(ptr, _vx1, _vy1, _vx2, _vy2, p1, p2) \
+ WRITE_VEC2 (ptr, _vx1, _vy1); \
+ WRITE_VEC2 (ptr, (p1)->x, (p2)->y); \
+ WRITE_VEC2 (ptr, _vx2, _vy1); \
+ WRITE_VEC2 (ptr, (p2)->x, (p2)->y); \
+ WRITE_VEC2 (ptr, _vx2, _vy2); \
+ WRITE_VEC2 (ptr, (p2)->x, (p1)->y); \
+ WRITE_VEC2 (ptr, _vx1, _vy2); \
+ WRITE_VEC2 (ptr, (p1)->x, (p1)->y)
+
+typedef struct _cairo_glitz_glyph_cache {
+ cairo_cache_t base;
+ cairo_glitz_root_area_t root;
+ glitz_surface_t *surface;
+} cairo_glitz_glyph_cache_t;
+
+typedef struct {
+ cairo_glyph_cache_key_t key;
+ int refcount;
+ cairo_glyph_size_t size;
+ cairo_glitz_area_t *area;
+ cairo_bool_t locked;
+ cairo_point_double_t p1, p2;
+} cairo_glitz_glyph_cache_entry_t;
+
+static cairo_status_t
+_cairo_glitz_glyph_move_in (cairo_glitz_area_t *area,
+ void *closure)
+{
+ cairo_glitz_glyph_cache_entry_t *entry = closure;
+
+ entry->area = area;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_glitz_glyph_move_out (cairo_glitz_area_t *area,
+ void *closure)
+{
+ cairo_glitz_glyph_cache_entry_t *entry = closure;
+
+ entry->area = NULL;
+}
+
+static int
+_cairo_glitz_glyph_compare (cairo_glitz_area_t *area,
+ void *closure1,
+ void *closure2)
+{
+ cairo_glitz_glyph_cache_entry_t *entry = closure1;
+
+ if (entry->locked)
+ return 1;
+
+ return -1;
+}
+
+static const cairo_glitz_area_funcs_t _cairo_glitz_area_funcs = {
+ _cairo_glitz_glyph_move_in,
+ _cairo_glitz_glyph_move_out,
+ _cairo_glitz_glyph_compare
+};
+
+static cairo_status_t
+_cairo_glitz_glyph_cache_entry_create (void *abstract_cache,
+ void *abstract_key,
+ void **return_entry)
+{
+ cairo_glitz_glyph_cache_entry_t *entry;
+ cairo_glyph_cache_key_t *key = abstract_key;
+
+ entry = malloc (sizeof (cairo_glitz_glyph_cache_entry_t));
+ if (!entry)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ entry->refcount = 1;
+ entry->key = *key;
+ entry->area = NULL;
+ entry->locked = FALSE;
+
+ _cairo_unscaled_font_reference (entry->key.unscaled);
+
+ *return_entry = entry;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_glitz_glyph_cache_entry_destroy (void *abstract_cache,
+ void *abstract_entry)
+{
+ cairo_glitz_glyph_cache_entry_t *entry = abstract_entry;
+
+ entry->refcount--;
+ if (entry->refcount)
+ return;
+
+ if (entry->area)
+ _cairo_glitz_area_move_out (entry->area);
+
+ _cairo_unscaled_font_destroy (entry->key.unscaled);
+
+ free (entry);
+}
+
+static void
+_cairo_glitz_glyph_cache_entry_reference (void *abstract_entry)
+{
+ cairo_glitz_glyph_cache_entry_t *entry = abstract_entry;
+
+ entry->refcount++;
+}
+
+static void
+_cairo_glitz_glyph_cache_destroy (void *abstract_cache)
+{
+ cairo_glitz_glyph_cache_t *cache = abstract_cache;
+
+ _cairo_glitz_root_area_fini (&cache->root);
+
+ glitz_surface_destroy (cache->surface);
+}
+
+static const cairo_cache_backend_t _cairo_glitz_glyph_cache_backend = {
+ _cairo_glyph_cache_hash,
+ _cairo_glyph_cache_keys_equal,
+ _cairo_glitz_glyph_cache_entry_create,
+ _cairo_glitz_glyph_cache_entry_destroy,
+ _cairo_glitz_glyph_cache_destroy
+};
+
+static cairo_glitz_glyph_cache_t *_cairo_glitz_glyph_caches = NULL;
+
+static cairo_glitz_glyph_cache_t *
+_cairo_glitz_get_glyph_cache (cairo_glitz_surface_t *surface)
+{
+ cairo_glitz_glyph_cache_t *cache;
+ glitz_drawable_t *drawable;
+ glitz_format_t *format;
+
+ /*
+ * FIXME: caches should be thread specific, display specific and screen
+ * specific.
+ */
+
+ if (_cairo_glitz_glyph_caches)
+ return _cairo_glitz_glyph_caches;
+
+ drawable = glitz_surface_get_drawable (surface->surface);
+
+ format = glitz_find_standard_format (drawable, GLITZ_STANDARD_A8);
+ if (!format)
+ return NULL;
+
+ cache = malloc (sizeof (cairo_glitz_glyph_cache_t));
+ if (!cache)
+ return NULL;
+
+ cache->surface =
+ glitz_surface_create (drawable, format,
+ GLYPH_CACHE_TEXTURE_SIZE,
+ GLYPH_CACHE_TEXTURE_SIZE,
+ 0, NULL);
+ if (!cache->surface)
+ {
+ free (cache);
+ return NULL;
+ }
+
+ if (_cairo_glitz_root_area_init (&cache->root,
+ GLYPH_CACHE_MAX_LEVEL,
+ GLYPH_CACHE_TEXTURE_SIZE,
+ GLYPH_CACHE_TEXTURE_SIZE,
+ &_cairo_glitz_area_funcs))
+ {
+ glitz_surface_destroy (cache->surface);
+ free (cache);
+ return NULL;
+ }
+
+ if (_cairo_cache_init (&cache->base,
+ &_cairo_glitz_glyph_cache_backend,
+ CAIRO_GLITZ_GLYPH_CACHE_MEMORY_DEFAULT))
+ {
+ _cairo_glitz_root_area_fini (&cache->root);
+ glitz_surface_destroy (cache->surface);
+ free (cache);
+ return NULL;
+ }
+
+ _cairo_glitz_glyph_caches = cache;
+
+ return cache;
+}
+
+#define FIXED_TO_FLOAT(f) (((glitz_float_t) (f)) / 65536)
+
+static cairo_status_t
+_cairo_glitz_cache_glyph (cairo_glitz_glyph_cache_t *cache,
+ cairo_glitz_glyph_cache_entry_t *entry,
+ cairo_image_glyph_cache_entry_t *image_entry)
+{
+ glitz_point_fixed_t p1, p2;
+ glitz_pixel_format_t pf;
+ glitz_buffer_t *buffer;
+ pixman_format_t *format;
+ int am, rm, gm, bm;
+
+ entry->size = image_entry->size;
+
+ if (entry->size.width > GLYPH_CACHE_MAX_WIDTH ||
+ entry->size.height > GLYPH_CACHE_MAX_HEIGHT)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (!image_entry->image)
+ {
+ entry->area = &_empty_area;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ format = pixman_image_get_format (image_entry->image->pixman_image);
+ if (!format)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ if (_cairo_glitz_area_find (cache->root.area,
+ entry->size.width,
+ entry->size.height,
+ FALSE, entry))
+ {
+ if (_cairo_glitz_area_find (cache->root.area,
+ entry->size.width,
+ entry->size.height,
+ TRUE, entry))
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ buffer = glitz_buffer_create_for_data (image_entry->image->data);
+ if (!buffer)
+ {
+ _cairo_glitz_area_move_out (entry->area);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ pixman_format_get_masks (format, &pf.masks.bpp, &am, &rm, &gm, &bm);
+
+ pf.masks.alpha_mask = am;
+ pf.masks.red_mask = rm;
+ pf.masks.green_mask = gm;
+ pf.masks.blue_mask = bm;
+
+ pf.bytes_per_line = image_entry->image->stride;
+ pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP;
+ pf.xoffset = 0;
+ pf.skip_lines = 0;
+
+ glitz_set_pixels (cache->surface,
+ entry->area->x,
+ entry->area->y,
+ entry->size.width,
+ entry->size.height,
+ &pf, buffer);
+
+ glitz_buffer_destroy (buffer);
+
+ p1.x = entry->area->x << 16;
+ p1.y = entry->area->y << 16;
+ p2.x = (entry->area->x + entry->size.width) << 16;
+ p2.y = (entry->area->y + entry->size.height) << 16;
+
+ glitz_surface_translate_point (cache->surface, &p1, &p1);
+ glitz_surface_translate_point (cache->surface, &p2, &p2);
+
+ entry->p1.x = FIXED_TO_FLOAT (p1.x);
+ entry->p1.y = FIXED_TO_FLOAT (p1.y);
+ entry->p2.x = FIXED_TO_FLOAT (p2.x);
+ entry->p2.y = FIXED_TO_FLOAT (p2.y);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+#define N_STACK_BUF 256
+
+static cairo_int_status_t
+_cairo_glitz_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
+ cairo_operator_t op,
+ cairo_pattern_t *pattern,
+ void *abstract_surface,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ cairo_glitz_surface_attributes_t attributes;
+ cairo_glitz_surface_t *dst = abstract_surface;
+ cairo_glitz_surface_t *src;
+ cairo_glitz_glyph_cache_t *cache;
+ cairo_glitz_glyph_cache_entry_t *stack_entries[N_STACK_BUF];
+ cairo_glitz_glyph_cache_entry_t **entries;
+ cairo_glyph_cache_key_t key;
+ glitz_float_t stack_vertices[N_STACK_BUF * 16];
+ glitz_float_t *vertices;
+ glitz_buffer_t *buffer;
+ cairo_int_status_t status;
+ int i, cached_glyphs = 0;
+ int remaining_glyps = num_glyphs;
+ glitz_float_t x1, y1, x2, y2;
+ static glitz_vertex_format_t format = {
+ GLITZ_PRIMITIVE_QUADS,
+ GLITZ_DATA_TYPE_FLOAT,
+ sizeof (glitz_float_t) * 4,
+ GLITZ_VERTEX_ATTRIBUTE_MASK_COORD_MASK,
+ { 0 },
+ {
+ GLITZ_DATA_TYPE_FLOAT,
+ GLITZ_COORDINATE_SIZE_XY,
+ sizeof (glitz_float_t) * 2,
+ }
+ };
+
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (_glitz_ensure_target (dst->surface))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_glitz_pattern_acquire_surface (pattern, dst,
+ src_x, src_y,
+ width, height,
+ &src, &attributes);
+ if (status)
+ return status;
+
+ _cairo_glitz_surface_set_attributes (src, &attributes);
+
+ if (num_glyphs > N_STACK_BUF)
+ {
+ char *data;
+
+ data = malloc (num_glyphs * sizeof (void *) +
+ num_glyphs * sizeof (glitz_float_t) * 16);
+ if (!data)
+ goto FAIL1;
+
+ entries = (cairo_glitz_glyph_cache_entry_t **) data;
+ vertices = (glitz_float_t *) (data + num_glyphs * sizeof (void *));
+ }
+ else
+ {
+ entries = stack_entries;
+ vertices = stack_vertices;
+ }
+
+ buffer = glitz_buffer_create_for_data (vertices);
+ if (!buffer)
+ goto FAIL2;
+
+ cache = _cairo_glitz_get_glyph_cache (dst);
+ if (!cache)
+ {
+ num_glyphs = 0;
+ goto UNLOCK;
+ }
+
+ _cairo_scaled_font_get_glyph_cache_key (scaled_font, &key);
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ key.index = glyphs[i].index;
+
+ status = _cairo_cache_lookup (&cache->base,
+ &key,
+ (void **) &entries[i],
+ NULL);
+ if (status)
+ {
+ num_glyphs = i;
+ goto UNLOCK;
+ }
+
+ _cairo_glitz_glyph_cache_entry_reference (entries[i]);
+
+ if (entries[i]->area)
+ {
+ remaining_glyps--;
+
+ if (entries[i]->area->width)
+ {
+ x1 = floor (glyphs[i].x + 0.5) + entries[i]->size.x;
+ y1 = floor (glyphs[i].y + 0.5) + entries[i]->size.y;
+ x2 = x1 + entries[i]->size.width;
+ y2 = y1 + entries[i]->size.height;
+
+ WRITE_BOX (vertices, x1, y1, x2, y2,
+ &entries[i]->p1, &entries[i]->p2);
+
+ entries[i]->locked = TRUE;
+ cached_glyphs++;
+ }
+ }
+ }
+
+ if (remaining_glyps)
+ {
+ cairo_cache_t *image_cache;
+ cairo_image_glyph_cache_entry_t *image_entry;
+ cairo_surface_t *image;
+ cairo_glitz_surface_t *clone;
+
+ _cairo_lock_global_image_glyph_cache ();
+
+ image_cache = _cairo_get_global_image_glyph_cache ();
+ if (!image_cache)
+ {
+ _cairo_unlock_global_image_glyph_cache ();
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto UNLOCK;
+ }
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ if (!entries[i]->area)
+ {
+ key.index = glyphs[i].index;
+
+ status = _cairo_cache_lookup (image_cache,
+ &key,
+ (void **) &image_entry,
+ NULL);
+ if (status)
+ {
+ _cairo_unlock_global_image_glyph_cache ();
+ goto UNLOCK;
+ }
+
+ status = _cairo_glitz_cache_glyph (cache,
+ entries[i],
+ image_entry);
+ if (status)
+ {
+ _cairo_unlock_global_image_glyph_cache ();
+ goto UNLOCK;
+ }
+ }
+
+ x1 = floor (glyphs[i].x + 0.5);
+ y1 = floor (glyphs[i].y + 0.5);
+
+ if (entries[i]->area)
+ {
+ if (entries[i]->area->width)
+ {
+ x1 += entries[i]->size.x;
+ y1 += entries[i]->size.y;
+ x2 = x1 + entries[i]->size.width;
+ y2 = y1 + entries[i]->size.height;
+
+ WRITE_BOX (vertices, x1, y1, x2, y2,
+ &entries[i]->p1, &entries[i]->p2);
+
+ entries[i]->locked = TRUE;
+ cached_glyphs++;
+ }
+ }
+ else
+ {
+ x1 += image_entry->size.x;
+ y1 += image_entry->size.y;
+
+ if (!image_entry->image)
+ continue;
+
+ image = &image_entry->image->base;
+ status =
+ _cairo_glitz_surface_clone_similar (abstract_surface,
+ image,
+ (cairo_surface_t **)
+ &clone);
+ if (status)
+ {
+ _cairo_unlock_global_image_glyph_cache ();
+ goto UNLOCK;
+ }
+
+ glitz_composite (_glitz_operator (op),
+ src->surface,
+ clone->surface,
+ dst->surface,
+ src_x + attributes.base.x_offset + x1,
+ src_y + attributes.base.y_offset + y1,
+ 0, 0,
+ x1, y1,
+ image_entry->size.width,
+ image_entry->size.height);
+
+ cairo_surface_destroy (&clone->base);
+
+ if (glitz_surface_get_status (dst->surface) ==
+ GLITZ_STATUS_NOT_SUPPORTED)
+ {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ _cairo_unlock_global_image_glyph_cache ();
+ goto UNLOCK;
+ }
+ }
+ }
+
+ _cairo_unlock_global_image_glyph_cache ();
+ }
+
+ if (cached_glyphs)
+ {
+ glitz_set_geometry (dst->surface,
+ GLITZ_GEOMETRY_TYPE_VERTEX,
+ (glitz_geometry_format_t *) &format,
+ buffer);
+
+ glitz_set_array (dst->surface, 0, 4, cached_glyphs * 4, 0, 0);
+
+ glitz_composite (_glitz_operator (op),
+ src->surface,
+ cache->surface,
+ dst->surface,
+ src_x + attributes.base.x_offset,
+ src_y + attributes.base.y_offset,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+
+ glitz_set_geometry (dst->surface,
+ GLITZ_GEOMETRY_TYPE_NONE,
+ NULL, NULL);
+ }
+
+UNLOCK:
+ if (cached_glyphs)
+ {
+ for (i = 0; i < num_glyphs; i++)
+ entries[i]->locked = FALSE;
+ }
+
+ for (i = 0; i < num_glyphs; i++)
+ _cairo_glitz_glyph_cache_entry_destroy (cache, entries[i]);
+
+ glitz_buffer_destroy (buffer);
+
+ FAIL2:
+ if (num_glyphs > N_STACK_BUF)
+ free (entries);
+
+ FAIL1:
+ if (attributes.n_params)
+ free (attributes.params);
+
+ _cairo_glitz_pattern_release_surface (dst, src, &attributes);
+
+ if (status)
+ return status;
+
+ if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static const cairo_surface_backend_t cairo_glitz_surface_backend = {
_cairo_glitz_surface_create_similar,
- _cairo_glitz_surface_destroy,
- _cairo_glitz_surface_pixels_per_inch,
+ _cairo_glitz_surface_finish,
_cairo_glitz_surface_acquire_source_image,
_cairo_glitz_surface_release_source_image,
_cairo_glitz_surface_acquire_dest_image,
@@ -1287,10 +2122,11 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = {
_cairo_glitz_surface_composite,
_cairo_glitz_surface_fill_rectangles,
_cairo_glitz_surface_composite_trapezoids,
- _cairo_glitz_surface_copy_page,
- _cairo_glitz_surface_show_page,
+ NULL, /* copy_page */
+ NULL, /* show_page */
_cairo_glitz_surface_set_clip_region,
- NULL /* show_glyphs */
+ _cairo_glitz_surface_get_extents,
+ _cairo_glitz_surface_show_glyphs
};
cairo_surface_t *
diff --git a/src/cairo-glitz.h b/src/cairo-glitz.h
index f1917eb28..f5b4f2815 100644
--- a/src/cairo-glitz.h
+++ b/src/cairo-glitz.h
@@ -39,20 +39,19 @@
#include <cairo.h>
-#ifdef CAIRO_HAS_GLITZ_SURFACE
+#if CAIRO_HAS_GLITZ_SURFACE
#include <glitz.h>
CAIRO_BEGIN_DECLS
-void
-cairo_set_target_glitz (cairo_t *cr,
- glitz_surface_t *surface);
-
cairo_surface_t *
cairo_glitz_surface_create (glitz_surface_t *surface);
CAIRO_END_DECLS
+#else /* CAIRO_HAS_GLITZ_SURFACE */
+# error Cairo was not compiled with support for the glitz backend
#endif /* CAIRO_HAS_GLITZ_SURFACE */
+
#endif /* CAIRO_GLITZ_H */
diff --git a/src/cairo-gstate-private.h b/src/cairo-gstate-private.h
new file mode 100644
index 000000000..eeb35b83e
--- /dev/null
+++ b/src/cairo-gstate-private.h
@@ -0,0 +1,80 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@redhat.com>
+ */
+
+#ifndef CAIRO_GSTATE_PRIVATE_H
+#define CAIRO_GSTATE_PRIVATE_H
+
+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;
+
+ char *font_family; /* NULL means CAIRO_FONT_FAMILY_DEFAULT; */
+ cairo_font_slant_t font_slant;
+ cairo_font_weight_t font_weight;
+
+ cairo_font_face_t *font_face;
+ cairo_scaled_font_t *scaled_font; /* Specific to the current CTM */
+
+ cairo_surface_t *surface;
+ int surface_level; /* Used to detect bad nested use */
+
+ cairo_pattern_t *source;
+
+ cairo_clip_rec_t clip;
+
+ cairo_matrix_t font_matrix;
+
+ cairo_matrix_t ctm;
+ cairo_matrix_t ctm_inverse;
+
+ cairo_pen_t pen_regular;
+
+ struct _cairo_gstate *next;
+};
+
+#endif /* CAIRO_GSTATE_PRIVATE_H */
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index d6db560a3..45c729fc9 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -35,10 +36,15 @@
*/
#include <stdlib.h>
-#include <math.h>
#include "cairoint.h"
+#include "cairo-gstate-private.h"
+
+static cairo_status_t
+_cairo_gstate_set_target_surface (cairo_gstate_t *gstate,
+ cairo_surface_t *surface);
+
static cairo_status_t
_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
cairo_pattern_t *src,
@@ -49,11 +55,14 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
static cairo_status_t
_cairo_gstate_ensure_font (cairo_gstate_t *gstate);
+static cairo_status_t
+_cairo_gstate_ensure_font_face (cairo_gstate_t *gstate);
+
static void
_cairo_gstate_unset_font (cairo_gstate_t *gstate);
cairo_gstate_t *
-_cairo_gstate_create ()
+_cairo_gstate_create (cairo_surface_t *target)
{
cairo_status_t status;
cairo_gstate_t *gstate;
@@ -62,7 +71,7 @@ _cairo_gstate_create ()
if (gstate)
{
- status = _cairo_gstate_init (gstate);
+ status = _cairo_gstate_init (gstate, target);
if (status) {
free (gstate);
return NULL;
@@ -73,8 +82,11 @@ _cairo_gstate_create ()
}
cairo_status_t
-_cairo_gstate_init (cairo_gstate_t *gstate)
+_cairo_gstate_init (cairo_gstate_t *gstate,
+ cairo_surface_t *target)
{
+ cairo_status_t status;
+
gstate->operator = CAIRO_GSTATE_OPERATOR_DEFAULT;
gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT;
@@ -90,32 +102,33 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
gstate->num_dashes = 0;
gstate->dash_offset = 0.0;
- gstate->font_family = NULL;
- gstate->font_slant = CAIRO_FONT_SLANT_DEFAULT;
- gstate->font_weight = CAIRO_FONT_WEIGHT_DEFAULT;
-
- gstate->font = NULL;
+ gstate->scaled_font = NULL;
+ gstate->font_face = NULL;
+ cairo_matrix_init_scale (&gstate->font_matrix,
+ CAIRO_GSTATE_DEFAULT_FONT_SIZE,
+ CAIRO_GSTATE_DEFAULT_FONT_SIZE);
+
gstate->surface = NULL;
+ gstate->surface_level = 0;
gstate->clip.region = NULL;
gstate->clip.surface = NULL;
-
- gstate->pattern = _cairo_pattern_create_solid (0.0, 0.0, 0.0);
- if (!gstate->pattern)
- return CAIRO_STATUS_NO_MEMORY;
- gstate->alpha = 1.0;
-
- gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT;
- _cairo_gstate_default_matrix (gstate);
+ gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK);
+ if (!gstate->source)
+ return CAIRO_STATUS_NO_MEMORY;
- _cairo_path_init (&gstate->path);
+ _cairo_gstate_identity_matrix (gstate);
_cairo_pen_init_empty (&gstate->pen_regular);
gstate->next = NULL;
+ status = _cairo_gstate_set_target_surface (gstate, target);
+ if (status)
+ return status;
+
return CAIRO_STATUS_SUCCESS;
}
@@ -138,51 +151,41 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double));
}
- if (other->font_family) {
- gstate->font_family = strdup (other->font_family);
- if (!gstate->font_family)
- goto CLEANUP_DASH;
- }
-
- if (other->font) {
- gstate->font = other->font;
- cairo_font_reference (gstate->font);
- }
-
if (other->clip.region)
{
gstate->clip.region = pixman_region_create ();
pixman_region_copy (gstate->clip.region, other->clip.region);
}
+ if (gstate->font_face)
+ cairo_font_face_reference (gstate->font_face);
+
+ if (gstate->scaled_font)
+ cairo_scaled_font_reference (gstate->scaled_font);
+
cairo_surface_reference (gstate->surface);
cairo_surface_reference (gstate->clip.surface);
- cairo_pattern_reference (gstate->pattern);
+ cairo_pattern_reference (gstate->source);
- status = _cairo_path_init_copy (&gstate->path, &other->path);
+ status = _cairo_pen_init_copy (&gstate->pen_regular, &other->pen_regular);
if (status)
goto CLEANUP_FONT;
- status = _cairo_pen_init_copy (&gstate->pen_regular, &other->pen_regular);
+ status = _cairo_surface_begin (gstate->surface);
if (status)
- goto CLEANUP_PATH;
+ goto CLEANUP_PEN;
+ gstate->surface_level = gstate->surface->level;
return status;
- CLEANUP_PATH:
- _cairo_path_fini (&gstate->path);
+ CLEANUP_PEN:
+ _cairo_pen_fini (&gstate->pen_regular);
CLEANUP_FONT:
- cairo_font_destroy (gstate->font);
- gstate->font = NULL;
+ cairo_scaled_font_destroy (gstate->scaled_font);
+ gstate->scaled_font = NULL;
- if (gstate->font_family) {
- free (gstate->font_family);
- gstate->font_family = NULL;
- }
-
- CLEANUP_DASH:
free (gstate->dash);
gstate->dash = NULL;
@@ -192,15 +195,17 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
void
_cairo_gstate_fini (cairo_gstate_t *gstate)
{
- if (gstate->font_family)
- free (gstate->font_family);
+ if (gstate->font_face)
+ cairo_font_face_destroy (gstate->font_face);
- if (gstate->font)
- cairo_font_destroy (gstate->font);
+ if (gstate->scaled_font)
+ cairo_scaled_font_destroy (gstate->scaled_font);
- if (gstate->surface)
+ if (gstate->surface) {
+ _cairo_surface_end (gstate->surface);
cairo_surface_destroy (gstate->surface);
- gstate->surface = NULL;
+ gstate->surface = NULL;
+ }
if (gstate->clip.surface)
cairo_surface_destroy (gstate->clip.surface);
@@ -210,14 +215,7 @@ _cairo_gstate_fini (cairo_gstate_t *gstate)
pixman_region_destroy (gstate->clip.region);
gstate->clip.region = NULL;
- cairo_pattern_destroy (gstate->pattern);
-
- _cairo_matrix_fini (&gstate->font_matrix);
-
- _cairo_matrix_fini (&gstate->ctm);
- _cairo_matrix_fini (&gstate->ctm_inverse);
-
- _cairo_path_fini (&gstate->path);
+ cairo_pattern_destroy (gstate->source);
_cairo_pen_fini (&gstate->pen_regular);
@@ -253,28 +251,12 @@ _cairo_gstate_clone (cairo_gstate_t *gstate)
return clone;
}
-cairo_status_t
-_cairo_gstate_copy (cairo_gstate_t *dest, cairo_gstate_t *src)
-{
- cairo_status_t status;
- cairo_gstate_t *next;
-
- /* Preserve next pointer over fini/init */
- next = dest->next;
- _cairo_gstate_fini (dest);
- status = _cairo_gstate_init_copy (dest, src);
- dest->next = next;
-
- return status;
-}
-
/* Push rendering off to an off-screen group. */
/* XXX: Rethinking this API
cairo_status_t
_cairo_gstate_begin_group (cairo_gstate_t *gstate)
{
Pixmap pix;
- cairo_color_t clear;
unsigned int width, height;
gstate->parent_surface = gstate->surface;
@@ -295,12 +277,9 @@ _cairo_gstate_begin_group (cairo_gstate_t *gstate)
_cairo_surface_set_drawableWH (gstate->surface, pix, width, height);
- _cairo_color_init (&clear);
- _cairo_color_set_alpha (&clear, 0);
-
status = _cairo_surface_fill_rectangle (gstate->surface,
- CAIRO_OPERATOR_SRC,
- &clear,
+ CAIRO_OPERATOR_SOURCE,
+ &CAIRO_COLOR_TRANSPARENT,
0, 0,
_cairo_surface_get_width (gstate->surface),
_cairo_surface_get_height (gstate->surface));
@@ -325,7 +304,6 @@ _cairo_gstate_end_group (cairo_gstate_t *gstate)
_cairo_surface_init (&mask, gstate->dpy);
_cairo_color_init (&mask_color);
- _cairo_color_set_alpha (&mask_color, gstate->alpha);
_cairo_surface_set_solid_color (&mask, &mask_color);
@@ -355,73 +333,93 @@ _cairo_gstate_end_group (cairo_gstate_t *gstate)
}
*/
-cairo_status_t
+static cairo_status_t
_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface)
{
- double scale;
+ cairo_status_t status;
+
+ if (gstate->surface == surface)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (surface) {
+ status = _cairo_surface_begin_reset_clip (surface);
+ if (!CAIRO_OK (status))
+ return status;
+ }
_cairo_gstate_unset_font (gstate);
- if (gstate->surface)
+ if (gstate->surface) {
+ _cairo_surface_end (gstate->surface);
cairo_surface_destroy (gstate->surface);
+ }
gstate->surface = surface;
/* Sometimes the user wants to return to having no target surface,
* (just like after cairo_create). This can be useful for forcing
* the old surface to be destroyed. */
- if (surface == NULL)
+ if (surface == NULL) {
+ gstate->surface_level = 0;
return CAIRO_STATUS_SUCCESS;
+ }
cairo_surface_reference (gstate->surface);
+ gstate->surface_level = surface->level;
- scale = _cairo_surface_pixels_per_inch (surface) / gstate->pixels_per_inch;
- _cairo_gstate_scale (gstate, scale, scale);
- gstate->pixels_per_inch = _cairo_surface_pixels_per_inch (surface);
+ _cairo_gstate_identity_matrix (gstate);
return CAIRO_STATUS_SUCCESS;
}
-/* XXX: Need to decide the memory mangement semantics of this
- function. Should it reference the surface again? */
cairo_surface_t *
-_cairo_gstate_current_target_surface (cairo_gstate_t *gstate)
+_cairo_gstate_get_target (cairo_gstate_t *gstate)
{
if (gstate == NULL)
return NULL;
-/* XXX: Do we want this?
- if (gstate->surface)
- _cairo_surface_reference (gstate->surface);
-*/
-
return gstate->surface;
}
cairo_status_t
-_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern)
+_cairo_gstate_set_source (cairo_gstate_t *gstate,
+ cairo_pattern_t *source)
{
- if (pattern == NULL)
+ if (source == NULL)
return CAIRO_STATUS_NULL_POINTER;
- cairo_pattern_reference (pattern);
- cairo_pattern_destroy (gstate->pattern);
- gstate->pattern = pattern;
+ cairo_pattern_reference (source);
+ cairo_pattern_destroy (gstate->source);
+ gstate->source = source;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_gstate_set_source_solid (cairo_gstate_t *gstate,
+ const cairo_color_t *color)
+{
+ cairo_status_t status;
+ cairo_pattern_t *source;
+
+ source = _cairo_pattern_create_solid (color);
+ if (!source)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ status = _cairo_gstate_set_source (gstate, source);
+
+ cairo_pattern_destroy (source);
return CAIRO_STATUS_SUCCESS;
}
cairo_pattern_t *
-_cairo_gstate_current_pattern (cairo_gstate_t *gstate)
+_cairo_gstate_get_source (cairo_gstate_t *gstate)
{
if (gstate == NULL)
return NULL;
-/* XXX: Do we want this?
- cairo_pattern_reference (gstate->pattern);
-*/
-
- return gstate->pattern;
+ return gstate->source;
}
cairo_status_t
@@ -433,30 +431,12 @@ _cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator)
}
cairo_operator_t
-_cairo_gstate_current_operator (cairo_gstate_t *gstate)
+_cairo_gstate_get_operator (cairo_gstate_t *gstate)
{
return gstate->operator;
}
cairo_status_t
-_cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, double blue)
-{
- cairo_pattern_destroy (gstate->pattern);
-
- gstate->pattern = _cairo_pattern_create_solid (red, green, blue);
- if (!gstate->pattern)
- return CAIRO_STATUS_NO_MEMORY;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_current_rgb_color (cairo_gstate_t *gstate, double *red, double *green, double *blue)
-{
- return _cairo_pattern_get_rgb (gstate->pattern, red, green, blue);
-}
-
-cairo_status_t
_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance)
{
gstate->tolerance = tolerance;
@@ -465,26 +445,12 @@ _cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance)
}
double
-_cairo_gstate_current_tolerance (cairo_gstate_t *gstate)
+_cairo_gstate_get_tolerance (cairo_gstate_t *gstate)
{
return gstate->tolerance;
}
cairo_status_t
-_cairo_gstate_set_alpha (cairo_gstate_t *gstate, double alpha)
-{
- gstate->alpha = alpha;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-double
-_cairo_gstate_current_alpha (cairo_gstate_t *gstate)
-{
- return gstate->alpha;
-}
-
-cairo_status_t
_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule)
{
gstate->fill_rule = fill_rule;
@@ -493,7 +459,7 @@ _cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule
}
cairo_fill_rule_t
-_cairo_gstate_current_fill_rule (cairo_gstate_t *gstate)
+_cairo_gstate_get_fill_rule (cairo_gstate_t *gstate)
{
return gstate->fill_rule;
}
@@ -507,7 +473,7 @@ _cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width)
}
double
-_cairo_gstate_current_line_width (cairo_gstate_t *gstate)
+_cairo_gstate_get_line_width (cairo_gstate_t *gstate)
{
return gstate->line_width;
}
@@ -521,7 +487,7 @@ _cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap)
}
cairo_line_cap_t
-_cairo_gstate_current_line_cap (cairo_gstate_t *gstate)
+_cairo_gstate_get_line_cap (cairo_gstate_t *gstate)
{
return gstate->line_cap;
}
@@ -535,7 +501,7 @@ _cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join
}
cairo_line_join_t
-_cairo_gstate_current_line_join (cairo_gstate_t *gstate)
+_cairo_gstate_get_line_join (cairo_gstate_t *gstate)
{
return gstate->line_join;
}
@@ -572,15 +538,15 @@ _cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit)
}
double
-_cairo_gstate_current_miter_limit (cairo_gstate_t *gstate)
+_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate)
{
return gstate->miter_limit;
}
void
-_cairo_gstate_current_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix)
+_cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix)
{
- cairo_matrix_copy (matrix, &gstate->ctm);
+ *matrix = gstate->ctm;
}
cairo_status_t
@@ -590,10 +556,10 @@ _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
_cairo_gstate_unset_font (gstate);
- _cairo_matrix_set_translate (&tmp, tx, ty);
+ cairo_matrix_init_translate (&tmp, tx, ty);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
- _cairo_matrix_set_translate (&tmp, -tx, -ty);
+ cairo_matrix_init_translate (&tmp, -tx, -ty);
cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
return CAIRO_STATUS_SUCCESS;
@@ -609,10 +575,10 @@ _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
_cairo_gstate_unset_font (gstate);
- _cairo_matrix_set_scale (&tmp, sx, sy);
+ cairo_matrix_init_scale (&tmp, sx, sy);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
- _cairo_matrix_set_scale (&tmp, 1/sx, 1/sy);
+ cairo_matrix_init_scale (&tmp, 1/sx, 1/sy);
cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
return CAIRO_STATUS_SUCCESS;
@@ -625,24 +591,24 @@ _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
_cairo_gstate_unset_font (gstate);
- _cairo_matrix_set_rotate (&tmp, angle);
+ cairo_matrix_init_rotate (&tmp, angle);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
- _cairo_matrix_set_rotate (&tmp, -angle);
+ cairo_matrix_init_rotate (&tmp, -angle);
cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gstate_concat_matrix (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
+_cairo_gstate_transform (cairo_gstate_t *gstate,
+ const cairo_matrix_t *matrix)
{
cairo_matrix_t tmp;
_cairo_gstate_unset_font (gstate);
- cairo_matrix_copy (&tmp, matrix);
+ tmp = *matrix;
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
cairo_matrix_invert (&tmp);
@@ -652,16 +618,16 @@ _cairo_gstate_concat_matrix (cairo_gstate_t *gstate,
}
cairo_status_t
-_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
+_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
+ const cairo_matrix_t *matrix)
{
cairo_status_t status;
_cairo_gstate_unset_font (gstate);
- cairo_matrix_copy (&gstate->ctm, matrix);
+ gstate->ctm = *matrix;
- cairo_matrix_copy (&gstate->ctm_inverse, matrix);
+ gstate->ctm_inverse = *matrix;
status = cairo_matrix_invert (&gstate->ctm_inverse);
if (status)
return status;
@@ -670,37 +636,18 @@ _cairo_gstate_set_matrix (cairo_gstate_t *gstate,
}
cairo_status_t
-_cairo_gstate_default_matrix (cairo_gstate_t *gstate)
-{
- int scale = gstate->pixels_per_inch / CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT + 0.5;
- if (scale == 0)
- scale = 1;
-
- _cairo_gstate_unset_font (gstate);
-
- cairo_matrix_set_identity (&gstate->font_matrix);
-
- cairo_matrix_set_identity (&gstate->ctm);
- cairo_matrix_scale (&gstate->ctm, scale, scale);
- cairo_matrix_copy (&gstate->ctm_inverse, &gstate->ctm);
- cairo_matrix_invert (&gstate->ctm_inverse);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
_cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
{
_cairo_gstate_unset_font (gstate);
- cairo_matrix_set_identity (&gstate->ctm);
- cairo_matrix_set_identity (&gstate->ctm_inverse);
+ cairo_matrix_init_identity (&gstate->ctm);
+ cairo_matrix_init_identity (&gstate->ctm_inverse);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gstate_transform_point (cairo_gstate_t *gstate, double *x, double *y)
+_cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y)
{
cairo_matrix_transform_point (&gstate->ctm, x, y);
@@ -708,7 +655,8 @@ _cairo_gstate_transform_point (cairo_gstate_t *gstate, double *x, double *y)
}
cairo_status_t
-_cairo_gstate_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy)
+_cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate,
+ double *dx, double *dy)
{
cairo_matrix_transform_distance (&gstate->ctm, dx, dy);
@@ -716,7 +664,7 @@ _cairo_gstate_transform_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_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y)
{
cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
@@ -724,610 +672,297 @@ _cairo_gstate_inverse_transform_point (cairo_gstate_t *gstate, double *x, double
}
cairo_status_t
-_cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy)
+_cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate,
+ double *dx, double *dy)
{
cairo_matrix_transform_distance (&gstate->ctm_inverse, dx, dy);
return CAIRO_STATUS_SUCCESS;
}
-cairo_status_t
-_cairo_gstate_new_path (cairo_gstate_t *gstate)
-{
- _cairo_path_fini (&gstate->path);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y)
+void
+_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
{
- cairo_point_t point;
-
- cairo_matrix_transform_point (&gstate->ctm, &x, &y);
-
- point.x = _cairo_fixed_from_double (x);
- point.y = _cairo_fixed_from_double (y);
-
- return _cairo_path_move_to (&gstate->path, &point);
+ cairo_matrix_transform_point (&gstate->ctm, x, y);
+ if (gstate->surface) {
+ *x += gstate->surface->device_x_offset;
+ *y += gstate->surface->device_y_offset;
+ }
}
-cairo_status_t
-_cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y)
+void
+_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
{
- cairo_point_t point;
-
- cairo_matrix_transform_point (&gstate->ctm, &x, &y);
-
- point.x = _cairo_fixed_from_double (x);
- point.y = _cairo_fixed_from_double (y);
-
- return _cairo_path_line_to (&gstate->path, &point);
+ if (gstate->surface) {
+ *x -= gstate->surface->device_x_offset;
+ *y -= gstate->surface->device_y_offset;
+ }
+ cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
}
+/* XXX: NYI
cairo_status_t
-_cairo_gstate_curve_to (cairo_gstate_t *gstate,
- double x0, double y0,
- double x1, double y1,
- double x2, double y2)
-{
- cairo_point_t p0, p1, p2;
-
- cairo_matrix_transform_point (&gstate->ctm, &x0, &y0);
- cairo_matrix_transform_point (&gstate->ctm, &x1, &y1);
- cairo_matrix_transform_point (&gstate->ctm, &x2, &y2);
-
- p0.x = _cairo_fixed_from_double (x0);
- p0.y = _cairo_fixed_from_double (y0);
-
- p1.x = _cairo_fixed_from_double (x1);
- p1.y = _cairo_fixed_from_double (y1);
-
- p2.x = _cairo_fixed_from_double (x2);
- p2.y = _cairo_fixed_from_double (y2);
-
- return _cairo_path_curve_to (&gstate->path, &p0, &p1, &p2);
-}
-
-/* Spline deviation from the circle in radius would be given by:
-
- error = sqrt (x**2 + y**2) - 1
-
- A simpler error function to work with is:
-
- e = x**2 + y**2 - 1
-
- From "Good approximation of circles by curvature-continuous Bezier
- curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric
- Design 8 (1990) 22-41, we learn:
-
- abs (max(e)) = 4/27 * sin**6(angle/4) / cos**2(angle/4)
-
- and
- abs (error) =~ 1/2 * e
-
- Of course, this error value applies only for the particular spline
- approximation that is used in _cairo_gstate_arc_segment.
-*/
-static double
-_arc_error_normalized (double angle)
-{
- return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
-}
-
-static double
-_arc_max_angle_for_tolerance_normalized (double tolerance)
-{
- double angle, error;
- int i;
-
- /* Use table lookup to reduce search time in most cases. */
- struct {
- double angle;
- double error;
- } table[] = {
- { M_PI / 1.0, 0.0185185185185185036127 },
- { M_PI / 2.0, 0.000272567143730179811158 },
- { M_PI / 3.0, 2.38647043651461047433e-05 },
- { M_PI / 4.0, 4.2455377443222443279e-06 },
- { M_PI / 5.0, 1.11281001494389081528e-06 },
- { M_PI / 6.0, 3.72662000942734705475e-07 },
- { M_PI / 7.0, 1.47783685574284411325e-07 },
- { M_PI / 8.0, 6.63240432022601149057e-08 },
- { M_PI / 9.0, 3.2715520137536980553e-08 },
- { M_PI / 10.0, 1.73863223499021216974e-08 },
- { M_PI / 11.0, 9.81410988043554039085e-09 },
- };
- int table_size = (sizeof (table) / sizeof (table[0]));
-
- for (i = 0; i < table_size; i++)
- if (table[i].error < tolerance)
- return table[i].angle;
-
- ++i;
- do {
- angle = M_PI / i++;
- error = _arc_error_normalized (angle);
- } while (error > tolerance);
-
- return angle;
-}
-
-static int
-_cairo_gstate_arc_segments_needed (cairo_gstate_t *gstate,
- double angle,
- double radius)
-{
- double l1, l2, lmax;
- double max_angle;
-
- _cairo_matrix_compute_eigen_values (&gstate->ctm, &l1, &l2);
-
- l1 = fabs (l1);
- l2 = fabs (l2);
- if (l1 > l2)
- lmax = l1;
- else
- lmax = l2;
-
- max_angle = _arc_max_angle_for_tolerance_normalized (gstate->tolerance / (radius * lmax));
-
- return (int) ceil (angle / max_angle);
-}
-
-/* We want to draw a single spline approximating a circular arc radius
- R from angle A to angle B. Since we want a symmetric spline that
- matches the endpoints of the arc in position and slope, we know
- that the spline control points must be:
-
- (R * cos(A), R * sin(A))
- (R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
- (R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
- (R * cos(B), R * sin(B))
-
- for some value of h.
-
- "Approximation of circular arcs by cubic poynomials", Michael
- Goldapp, Computer Aided Geometric Design 8 (1991) 227-238, provides
- various values of h along with error analysis for each.
-
- From that paper, a very practical value of h is:
-
- h = 4/3 * tan(angle/4)
-
- This value does not give the spline with minimal error, but it does
- provide a very good approximation, (6th-order convergence), and the
- error expression is quite simple, (see the comment for
- _arc_error_normalized).
-*/
-static cairo_status_t
-_cairo_gstate_arc_segment (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle_A, double angle_B)
+_cairo_gstate_stroke_to_path (cairo_gstate_t *gstate)
{
cairo_status_t status;
- double r_sin_A, r_cos_A;
- double r_sin_B, r_cos_B;
- double h;
-
- r_sin_A = radius * sin (angle_A);
- r_cos_A = radius * cos (angle_A);
- r_sin_B = radius * sin (angle_B);
- r_cos_B = radius * cos (angle_B);
-
- h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
-
- status = _cairo_gstate_curve_to (gstate,
- xc + r_cos_A - h * r_sin_A, yc + r_sin_A + h * r_cos_A,
- xc + r_cos_B + h * r_sin_B, yc + r_sin_B - h * r_cos_B,
- xc + r_cos_B, yc + r_sin_B);
- if (status)
- return status;
+ _cairo_pen_init (&gstate);
return CAIRO_STATUS_SUCCESS;
}
+*/
-static cairo_status_t
-_cairo_gstate_arc_dir (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle_min,
- double angle_max,
- cairo_direction_t dir)
+static void
+_cairo_gstate_pattern_transform (cairo_gstate_t *gstate,
+ cairo_pattern_t *pattern)
{
- cairo_status_t status;
-
- while (angle_max - angle_min > 4 * M_PI)
- angle_max -= 2 * M_PI;
-
- /* Recurse if drawing arc larger than pi */
- if (angle_max - angle_min > M_PI) {
- double angle_mid = angle_min + (angle_max - angle_min) / 2.0;
- /* XXX: Something tells me this block could be condensed. */
- if (dir == CAIRO_DIRECTION_FORWARD) {
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_min, angle_mid, dir);
- if (status)
- return status;
-
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_mid, angle_max, dir);
- if (status)
- return status;
- } else {
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_mid, angle_max, dir);
- if (status)
- return status;
-
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_min, angle_mid, dir);
- if (status)
- return status;
- }
- } else {
- int i, segments;
- double angle, angle_step;
-
- segments = _cairo_gstate_arc_segments_needed (gstate,
- angle_max - angle_min,
- radius);
- angle_step = (angle_max - angle_min) / (double) segments;
-
- if (dir == CAIRO_DIRECTION_FORWARD) {
- angle = angle_min;
- } else {
- angle = angle_max;
- angle_step = - angle_step;
- }
-
- for (i = 0; i < segments; i++, angle += angle_step) {
- _cairo_gstate_arc_segment (gstate,
- xc, yc,
- radius,
- angle,
- angle + angle_step);
- }
-
- }
+ cairo_matrix_t tmp_matrix = gstate->ctm_inverse;
+
+ if (gstate->surface)
+ cairo_matrix_translate (&tmp_matrix,
+ - gstate->surface->device_x_offset,
+ - gstate->surface->device_y_offset);
- return CAIRO_STATUS_SUCCESS;
+ _cairo_pattern_transform (pattern, &tmp_matrix);
}
cairo_status_t
-_cairo_gstate_arc (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle1, double angle2)
+_cairo_gstate_paint (cairo_gstate_t *gstate)
{
+ cairo_rectangle_t rectangle;
cairo_status_t status;
+ cairo_box_t box;
+ cairo_traps_t traps;
- if (radius <= 0.0)
- return CAIRO_STATUS_SUCCESS;
-
- while (angle2 < angle1)
- angle2 += 2 * M_PI;
-
- status = _cairo_gstate_line_to (gstate,
- xc + radius * cos (angle1),
- yc + radius * sin (angle1));
- if (status)
- return status;
-
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle1, angle2, CAIRO_DIRECTION_FORWARD);
- if (status)
+ if (gstate->surface->level != gstate->surface_level)
+ return CAIRO_STATUS_BAD_NESTING;
+
+ status = _cairo_surface_get_clip_extents (gstate->surface, &rectangle);
+ if (!CAIRO_OK (status))
return status;
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_arc_negative (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle1, double angle2)
-{
- cairo_status_t status;
-
- if (radius <= 0.0)
- return CAIRO_STATUS_SUCCESS;
-
- while (angle2 > angle1)
- angle2 -= 2 * M_PI;
-
- status = _cairo_gstate_line_to (gstate,
- xc + radius * cos (angle1),
- yc + radius * sin (angle1));
- if (status)
+ box.p1.x = _cairo_fixed_from_int (rectangle.x);
+ box.p1.y = _cairo_fixed_from_int (rectangle.y);
+ box.p2.x = _cairo_fixed_from_int (rectangle.x + rectangle.width);
+ box.p2.y = _cairo_fixed_from_int (rectangle.y + rectangle.height);
+ status = _cairo_traps_init_box (&traps, &box);
+ if (!CAIRO_OK (status))
return status;
+
+ _cairo_gstate_clip_and_composite_trapezoids (gstate,
+ gstate->source,
+ gstate->operator,
+ gstate->surface,
+ &traps);
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle2, angle1, CAIRO_DIRECTION_REVERSE);
- if (status)
- return status;
+ _cairo_traps_fini (&traps);
return CAIRO_STATUS_SUCCESS;
}
-/* XXX: NYI
-cairo_status_t
-_cairo_gstate_arc_to (cairo_gstate_t *gstate,
- double x1, double y1,
- double x2, double y2,
- double radius)
-{
-
-}
-*/
-
-cairo_status_t
-_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy)
-{
- cairo_distance_t distance;
-
- cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
-
- distance.dx = _cairo_fixed_from_double (dx);
- distance.dy = _cairo_fixed_from_double (dy);
-
- return _cairo_path_rel_move_to (&gstate->path, &distance);
-}
-
-cairo_status_t
-_cairo_gstate_rel_line_to (cairo_gstate_t *gstate, double dx, double dy)
-{
- cairo_distance_t distance;
-
- cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
-
- distance.dx = _cairo_fixed_from_double (dx);
- distance.dy = _cairo_fixed_from_double (dy);
-
- return _cairo_path_rel_line_to (&gstate->path, &distance);
-}
-
-cairo_status_t
-_cairo_gstate_rel_curve_to (cairo_gstate_t *gstate,
- double dx0, double dy0,
- double dx1, double dy1,
- double dx2, double dy2)
-{
- cairo_distance_t distance[3];
-
- cairo_matrix_transform_distance (&gstate->ctm, &dx0, &dy0);
- cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1);
- cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
-
- distance[0].dx = _cairo_fixed_from_double (dx0);
- distance[0].dy = _cairo_fixed_from_double (dy0);
-
- distance[1].dx = _cairo_fixed_from_double (dx1);
- distance[1].dy = _cairo_fixed_from_double (dy1);
-
- distance[2].dx = _cairo_fixed_from_double (dx2);
- distance[2].dy = _cairo_fixed_from_double (dy2);
-
- return _cairo_path_rel_curve_to (&gstate->path,
- &distance[0],
- &distance[1],
- &distance[2]);
-}
-
-/* XXX: NYI
-cairo_status_t
-_cairo_gstate_stroke_path (cairo_gstate_t *gstate)
+/* Combines @gstate->clip_surface using the IN operator with
+ * the given intermediate surface, which corresponds to the
+ * rectangle of the destination space given by @extents.
+ */
+static cairo_status_t
+_cairo_gstate_combine_clip_surface (cairo_gstate_t *gstate,
+ cairo_surface_t *intermediate,
+ cairo_rectangle_t *extents)
{
+ cairo_pattern_union_t pattern;
cairo_status_t status;
- _cairo_pen_init (&gstate);
- return CAIRO_STATUS_SUCCESS;
-}
-*/
+ _cairo_pattern_init_for_surface (&pattern.surface,
+ gstate->clip.surface);
+
+ status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
+ &pattern.base,
+ NULL,
+ intermediate,
+ extents->x - gstate->clip.rect.x,
+ extents->y - gstate->clip.rect.y,
+ 0, 0,
+ 0, 0,
+ extents->width, extents->height);
+
+ _cairo_pattern_fini (&pattern.base);
-cairo_status_t
-_cairo_gstate_close_path (cairo_gstate_t *gstate)
-{
- return _cairo_path_close_path (&gstate->path);
+ return status;
}
-cairo_status_t
-_cairo_gstate_current_point (cairo_gstate_t *gstate, double *x_ret, double *y_ret)
-{
- cairo_status_t status;
- cairo_point_t point;
- double x, y;
-
- status = _cairo_path_current_point (&gstate->path, &point);
- if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
- x = 0.0;
- y = 0.0;
- } else {
- x = _cairo_fixed_to_double (point.x);
- y = _cairo_fixed_to_double (point.y);
- cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y);
+/* Creates a region from a cairo_rectangle_t */
+static cairo_status_t
+_region_new_from_rect (cairo_rectangle_t *rect,
+ pixman_region16_t **region)
+{
+ *region = pixman_region_create ();
+ if (pixman_region_union_rect (*region, *region,
+ rect->x, rect->y,
+ rect->width, rect->height) != PIXMAN_REGION_STATUS_SUCCESS) {
+ pixman_region_destroy (*region);
+ return CAIRO_STATUS_NO_MEMORY;
}
- if (x_ret)
- *x_ret = x;
- if (y_ret)
- *y_ret = y;
-
return CAIRO_STATUS_SUCCESS;
}
-typedef struct gstate_path_interpreter {
- cairo_matrix_t ctm_inverse;
- double tolerance;
- cairo_point_t current_point;
-
- cairo_move_to_func_t *move_to;
- cairo_line_to_func_t *line_to;
- cairo_curve_to_func_t *curve_to;
- cairo_close_path_func_t *close_path;
+/* Gets the bounding box of a region as a cairo_rectangle_t */
+static void
+_region_rect_extents (pixman_region16_t *region,
+ cairo_rectangle_t *rect)
+{
+ pixman_box16_t *region_extents = pixman_region_extents (region);
- void *closure;
-} gpi_t;
+ rect->x = region_extents->x1;
+ rect->y = region_extents->y1;
+ rect->width = region_extents->x2 - region_extents->x1;
+ rect->height = region_extents->y2 - region_extents->y1;
+}
+/* Intersects @region with the clipping bounds (both region
+ * and surface) of @gstate
+ */
static cairo_status_t
-_gpi_move_to (void *closure, cairo_point_t *point)
+_cairo_gstate_intersect_clip (cairo_gstate_t *gstate,
+ pixman_region16_t *region)
{
- gpi_t *gpi = closure;
- double x, y;
+ if (gstate->clip.region)
+ pixman_region_intersect (region, gstate->clip.region, region);
- x = _cairo_fixed_to_double (point->x);
- y = _cairo_fixed_to_double (point->y);
+ if (gstate->clip.surface) {
+ pixman_region16_t *clip_rect;
+ cairo_status_t status;
+
+ status = _region_new_from_rect (&gstate->clip.rect, &clip_rect);
+ if (!CAIRO_OK (status))
+ return status;
+
+ if (pixman_region_intersect (region,
+ clip_rect,
+ region) != PIXMAN_REGION_STATUS_SUCCESS)
+ status = CAIRO_STATUS_NO_MEMORY;
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
+ pixman_region_destroy (clip_rect);
- gpi->move_to (gpi->closure, x, y);
- gpi->current_point = *point;
+ if (!CAIRO_OK (status))
+ return status;
+ }
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_gpi_line_to (void *closure, cairo_point_t *point)
+_get_mask_extents (cairo_gstate_t *gstate,
+ cairo_pattern_t *mask,
+ cairo_rectangle_t *extents)
{
- gpi_t *gpi = closure;
- double x, y;
+ cairo_rectangle_t clip_rect;
+ pixman_region16_t *clip_region;
+ cairo_status_t status;
+
+ status = _cairo_surface_get_clip_extents (gstate->surface, &clip_rect);
+ if (!CAIRO_OK (status))
+ return status;
- x = _cairo_fixed_to_double (point->x);
- y = _cairo_fixed_to_double (point->y);
+ status = _region_new_from_rect (&clip_rect, &clip_region);
+ if (!CAIRO_OK (status))
+ return status;
+
+ status = _cairo_gstate_intersect_clip (gstate, clip_region);
+ if (!CAIRO_OK (status))
+ return status;
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
+ _region_rect_extents (clip_region, extents);
- gpi->line_to (gpi->closure, x, y);
- gpi->current_point = *point;
+ pixman_region_destroy (clip_region);
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_gpi_curve_to (void *closure,
- cairo_point_t *p1,
- cairo_point_t *p2,
- cairo_point_t *p3)
+cairo_status_t
+_cairo_gstate_mask (cairo_gstate_t *gstate,
+ cairo_pattern_t *mask)
{
- gpi_t *gpi = closure;
+ cairo_rectangle_t extents;
+ cairo_pattern_union_t pattern;
+ cairo_surface_pattern_t intermediate_pattern;
+ cairo_pattern_t *effective_mask;
cairo_status_t status;
- cairo_spline_t spline;
- double x1, y1, x2, y2, x3, y3;
-
- if (gpi->curve_to) {
- x1 = _cairo_fixed_to_double (p1->x);
- y1 = _cairo_fixed_to_double (p1->y);
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x1, &y1);
-
- x2 = _cairo_fixed_to_double (p2->x);
- y2 = _cairo_fixed_to_double (p2->y);
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x2, &y2);
-
- x3 = _cairo_fixed_to_double (p3->x);
- y3 = _cairo_fixed_to_double (p3->y);
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x3, &y3);
+ int mask_x, mask_y;
- gpi->curve_to (gpi->closure, x1, y1, x2, y2, x3, y3);
- } else {
- cairo_point_t *p0 = &gpi->current_point;
- int i;
- double x, y;
+ if (gstate->surface->level != gstate->surface_level)
+ return CAIRO_STATUS_BAD_NESTING;
+
+ _get_mask_extents (gstate, mask, &extents);
+
+ if (gstate->clip.surface) {
+ /* When there is clip surface, we'll need to create a
+ * temporary surface that combines the clip and mask
+ */
+ cairo_surface_t *intermediate;
- status = _cairo_spline_init (&spline, p0, p1, p2, p3);
- if (status == CAIRO_INT_STATUS_DEGENERATE)
- return CAIRO_STATUS_SUCCESS;
+ intermediate = cairo_surface_create_similar (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ extents.width,
+ extents.height);
+ if (intermediate == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
- status = _cairo_spline_decompose (&spline, gpi->tolerance);
- if (status)
+ status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
+ mask, NULL, intermediate,
+ extents.x, extents.y,
+ 0, 0,
+ 0, 0,
+ extents.width, extents.height);
+ if (!CAIRO_OK (status)) {
+ cairo_surface_destroy (intermediate);
return status;
-
- for (i=1; i < spline.num_points; i++) {
- x = _cairo_fixed_to_double (spline.points[i].x);
- y = _cairo_fixed_to_double (spline.points[i].y);
-
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
-
- gpi->line_to (gpi->closure, x, y);
}
- }
-
- gpi->current_point = *p3;
-
- return CAIRO_STATUS_SUCCESS;
-}
+
+ status = _cairo_gstate_combine_clip_surface (gstate, intermediate, &extents);
+ if (!CAIRO_OK (status)) {
+ cairo_surface_destroy (intermediate);
+ return status;
+ }
+
+ _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
+ cairo_surface_destroy (intermediate);
-static cairo_status_t
-_gpi_close_path (void *closure)
-{
- gpi_t *gpi = closure;
+ effective_mask = &intermediate_pattern.base;
+ mask_x = extents.x;
+ mask_y = extents.y;
+
+ } else {
+ effective_mask = mask;
+ mask_x = mask_y = 0;
+ }
- gpi->close_path (gpi->closure);
+ _cairo_pattern_init_copy (&pattern.base, gstate->source);
+ _cairo_gstate_pattern_transform (gstate, &pattern.base);
- gpi->current_point.x = 0;
- gpi->current_point.y = 0;
+ status = _cairo_surface_composite (gstate->operator,
+ &pattern.base,
+ effective_mask,
+ gstate->surface,
+ extents.x, extents.y,
+ extents.x - mask_x, extents.y - mask_y,
+ extents.x, extents.y,
+ extents.width, extents.height);
- return CAIRO_STATUS_SUCCESS;
-}
+ if (gstate->clip.surface)
+ _cairo_pattern_fini (&intermediate_pattern.base);
-/* It's OK for curve_path to be NULL. In that case, all curves in the
- path will be decomposed into one or more calls to the line_to
- function, (according to the current tolerance). */
-cairo_status_t
-_cairo_gstate_interpret_path (cairo_gstate_t *gstate,
- cairo_move_to_func_t *move_to,
- cairo_line_to_func_t *line_to,
- cairo_curve_to_func_t *curve_to,
- cairo_close_path_func_t *close_path,
- void *closure)
-{
- cairo_path_t path;
- gpi_t gpi;
-
- /* Anything we want from gstate must be copied. We must not retain
- pointers into gstate. */
- _cairo_path_init_copy (&path, &gstate->path);
-
- cairo_matrix_copy (&gpi.ctm_inverse, &gstate->ctm_inverse);
- gpi.tolerance = gstate->tolerance;
-
- gpi.move_to = move_to;
- gpi.line_to = line_to;
- gpi.curve_to = curve_to;
- gpi.close_path = close_path;
- gpi.closure = closure;
-
- gpi.current_point.x = 0;
- gpi.current_point.y = 0;
-
- return _cairo_path_interpret (&path,
- CAIRO_DIRECTION_FORWARD,
- _gpi_move_to,
- _gpi_line_to,
- _gpi_curve_to,
- _gpi_close_path,
- &gpi);
-}
-
-/* XXX: gstate->alpha will be going away before too long, and when it
- * does, it may make sense for this function to just disappear.
- */
-static void
-_cairo_gstate_pattern_init_copy (cairo_gstate_t *gstate,
- cairo_pattern_union_t *pattern,
- cairo_pattern_t *src)
-{
- _cairo_pattern_init_copy (&pattern->base, src);
- _cairo_pattern_transform (&pattern->base, &gstate->ctm_inverse);
- _cairo_pattern_set_alpha (&pattern->base, gstate->alpha);
+ return status;
}
cairo_status_t
-_cairo_gstate_stroke (cairo_gstate_t *gstate)
+_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_status_t status;
cairo_traps_t traps;
+ if (gstate->surface->level != gstate->surface_level)
+ return CAIRO_STATUS_BAD_NESTING;
+
if (gstate->line_width <= 0.0)
return CAIRO_STATUS_SUCCESS;
@@ -1335,41 +970,40 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate)
_cairo_traps_init (&traps);
- status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
+ status = _cairo_path_fixed_stroke_to_traps (path, gstate, &traps);
if (status) {
_cairo_traps_fini (&traps);
return status;
}
_cairo_gstate_clip_and_composite_trapezoids (gstate,
- gstate->pattern,
+ gstate->source,
gstate->operator,
gstate->surface,
&traps);
_cairo_traps_fini (&traps);
- _cairo_gstate_new_path (gstate);
-
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
- double x,
- double y,
- cairo_bool_t *inside_ret)
+_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
+ double x,
+ double y,
+ cairo_bool_t *inside_ret)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_traps_t traps;
- cairo_matrix_transform_point (&gstate->ctm, &x, &y);
+ _cairo_gstate_user_to_backend (gstate, &x, &y);
_cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate);
_cairo_traps_init (&traps);
- status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
+ status = _cairo_path_fixed_stroke_to_traps (path, gstate, &traps);
if (status)
goto BAIL;
@@ -1433,6 +1067,119 @@ _cairo_rectangle_empty (cairo_rectangle_t *rect)
return rect->width == 0 || rect->height == 0;
}
+/* Given a region representing a set of trapezoids that will be
+ * drawn, clip the region according to the gstate and compute
+ * the overall extents.
+ */
+static cairo_status_t
+_clip_and_compute_extents_region (cairo_gstate_t *gstate,
+ pixman_region16_t *trap_region,
+ cairo_rectangle_t *extents)
+{
+ cairo_status_t status;
+
+ status = _cairo_gstate_intersect_clip (gstate, trap_region);
+ if (!CAIRO_OK (status))
+ return status;
+
+ _region_rect_extents (trap_region, extents);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Given a a set of trapezoids to draw, find a bounding box (non-exact)
+ * of the trapezoids clipped by the gstate
+ */
+static cairo_status_t
+_clip_and_compute_extents_arbitrary (cairo_gstate_t *gstate,
+ cairo_traps_t *traps,
+ cairo_rectangle_t *extents)
+{
+ cairo_box_t trap_extents;
+
+ _cairo_traps_extents (traps, &trap_extents);
+ _cairo_box_round_to_rectangle (&trap_extents, extents);
+
+ if (gstate->clip.region) {
+ pixman_region16_t *intersection;
+ cairo_status_t status;
+
+ status = _region_new_from_rect (extents, &intersection);
+ if (!CAIRO_OK (status))
+ return status;
+
+ if (pixman_region_intersect (intersection,
+ gstate->clip.region,
+ intersection) == PIXMAN_REGION_STATUS_SUCCESS)
+ _region_rect_extents (intersection, extents);
+ else
+ status = CAIRO_STATUS_NO_MEMORY;
+
+ pixman_region_destroy (intersection);
+
+ if (!CAIRO_OK (status))
+ return status;
+ }
+
+ if (gstate->clip.surface)
+ _cairo_rectangle_intersect (extents, &gstate->clip.rect);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Composites a region representing a set of trapezoids.
+ */
+static cairo_status_t
+_composite_trap_region (cairo_gstate_t *gstate,
+ cairo_pattern_t *src,
+ cairo_operator_t operator,
+ cairo_surface_t *dst,
+ pixman_region16_t *trap_region,
+ cairo_rectangle_t *extents)
+{
+ cairo_status_t status, tmp_status;
+ cairo_pattern_union_t pattern;
+ cairo_pattern_union_t mask;
+ int num_rects = pixman_region_num_rects (trap_region);
+
+ if (num_rects == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (num_rects > 1) {
+ status = _cairo_surface_set_clip_region (dst, trap_region);
+ if (!CAIRO_OK (status))
+ return status;
+ }
+
+ _cairo_pattern_init_copy (&pattern.base, src);
+ _cairo_gstate_pattern_transform (gstate, &pattern.base);
+
+ if (gstate->clip.surface)
+ _cairo_pattern_init_for_surface (&mask.surface, gstate->clip.surface);
+
+ status = _cairo_surface_composite (gstate->operator,
+ &pattern.base,
+ gstate->clip.surface ? &mask.base : NULL,
+ dst,
+ extents->x, extents->y,
+ extents->x - (gstate->clip.surface ? gstate->clip.rect.x : 0),
+ extents->y - (gstate->clip.surface ? gstate->clip.rect.y : 0),
+ extents->x, extents->y,
+ extents->width, extents->height);
+
+ _cairo_pattern_fini (&pattern.base);
+ if (gstate->clip.surface)
+ _cairo_pattern_fini (&mask.base);
+
+ if (num_rects > 1) {
+ tmp_status = _cairo_surface_set_clip_region (dst, gstate->clip.region);
+ if (!CAIRO_OK (tmp_status))
+ status = tmp_status;
+ }
+
+ return status;
+}
+
static void
translate_traps (cairo_traps_t *traps, int x, int y)
{
@@ -1462,6 +1209,145 @@ translate_traps (cairo_traps_t *traps, int x, int y)
}
}
+/* Composites a set of trapezoids in the case where we need to create
+ * an intermediate surface to handle gstate->clip.surface
+ *
+ * Warning: This call modifies the coordinates of traps
+ */
+static cairo_status_t
+_composite_traps_intermediate_surface (cairo_gstate_t *gstate,
+ cairo_pattern_t *src,
+ cairo_operator_t operator,
+ cairo_surface_t *dst,
+ cairo_traps_t *traps,
+ cairo_rectangle_t *extents)
+{
+ cairo_pattern_union_t pattern;
+ cairo_surface_t *intermediate;
+ cairo_surface_pattern_t intermediate_pattern;
+ cairo_status_t status;
+
+ translate_traps (traps, -extents->x, -extents->y);
+
+ intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ extents->width,
+ extents->height,
+ CAIRO_COLOR_TRANSPARENT);
+ if (intermediate == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
+
+ status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
+ &pattern.base,
+ intermediate,
+ extents->x, extents->y,
+ 0, 0,
+ extents->width,
+ extents->height,
+ traps->traps,
+ traps->num_traps);
+ _cairo_pattern_fini (&pattern.base);
+
+ if (!CAIRO_OK (status))
+ goto out;
+
+ status = _cairo_gstate_combine_clip_surface (gstate, intermediate, extents);
+ if (!CAIRO_OK (status))
+ goto out;
+
+ _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
+ _cairo_pattern_init_copy (&pattern.base, src);
+ _cairo_gstate_pattern_transform (gstate, &pattern.base);
+
+ status = _cairo_surface_composite (operator,
+ &pattern.base,
+ &intermediate_pattern.base,
+ dst,
+ extents->x, extents->y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+
+ _cairo_pattern_fini (&pattern.base);
+ _cairo_pattern_fini (&intermediate_pattern.base);
+
+ out:
+ cairo_surface_destroy (intermediate);
+
+ return status;
+}
+
+/* Composites a region representing a set of trapezoids in the
+ * case of a solid source (so we can use
+ * _cairo_surface_fill_rectangles).
+ */
+static cairo_status_t
+_composite_trap_region_solid (cairo_gstate_t *gstate,
+ cairo_solid_pattern_t *src,
+ cairo_operator_t operator,
+ cairo_surface_t *dst,
+ pixman_region16_t *region)
+{
+ int num_rects = pixman_region_num_rects (region);
+ pixman_box16_t *boxes = pixman_region_rects (region);
+ cairo_rectangle_t *rects;
+ cairo_status_t status;
+ int i;
+
+ if (!num_rects)
+ return CAIRO_STATUS_SUCCESS;
+
+ rects = malloc (sizeof (pixman_rectangle_t) * num_rects);
+ if (!rects)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ for (i = 0; i < num_rects; i++) {
+ rects[i].x = boxes[i].x1;
+ rects[i].y = boxes[i].y1;
+ rects[i].width = boxes[i].x2 - boxes[i].x1;
+ rects[i].height = boxes[i].y2 - boxes[i].y1;
+ }
+
+ status = _cairo_surface_fill_rectangles (dst, operator,
+ &src->color, rects, num_rects);
+
+ free (rects);
+
+ return status;
+}
+
+/* Composites a set of trapezoids in the general case where
+ gstate->clip.surface == NULL
+ */
+static cairo_status_t
+_composite_traps (cairo_gstate_t *gstate,
+ cairo_pattern_t *src,
+ cairo_operator_t operator,
+ cairo_surface_t *dst,
+ cairo_traps_t *traps,
+ cairo_rectangle_t *extents)
+{
+ cairo_pattern_union_t pattern;
+ cairo_status_t status;
+
+ _cairo_pattern_init_copy (&pattern.base, src);
+ _cairo_gstate_pattern_transform (gstate, &pattern.base);
+
+ status = _cairo_surface_composite_trapezoids (gstate->operator,
+ &pattern.base, dst,
+ extents->x, extents->y,
+ extents->x, extents->y,
+ extents->width,
+ extents->height,
+ traps->traps,
+ traps->num_traps);
+
+ _cairo_pattern_fini (&pattern.base);
+
+ return status;
+}
/* Warning: This call modifies the coordinates of traps */
static cairo_status_t
@@ -1472,197 +1358,124 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
cairo_traps_t *traps)
{
cairo_status_t status;
- cairo_pattern_union_t pattern;
+ pixman_region16_t *trap_region;
cairo_rectangle_t extents;
- cairo_box_t trap_extents;
-
+
if (traps->num_traps == 0)
return CAIRO_STATUS_SUCCESS;
if (gstate->surface == NULL)
return CAIRO_STATUS_NO_TARGET_SURFACE;
- _cairo_traps_extents (traps, &trap_extents);
- _cairo_box_round_to_rectangle (&trap_extents, &extents);
-
- if (gstate->clip.surface) {
- cairo_surface_t *intermediate;
- cairo_surface_pattern_t intermediate_pattern;
- cairo_color_t empty_color;
-
- _cairo_rectangle_intersect (&extents, &gstate->clip.rect);
-
- if (_cairo_rectangle_empty (&extents)) {
- status = CAIRO_STATUS_SUCCESS;
- goto BAIL1;
- }
-
- translate_traps (traps, -extents.x, -extents.y);
+ status = _cairo_traps_extract_region (traps, &trap_region);
+ if (!CAIRO_OK (status))
+ return status;
- _cairo_color_init (&empty_color);
- _cairo_color_set_alpha (&empty_color, 0.);
- intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
- CAIRO_FORMAT_A8,
- extents.width,
- extents.height,
- &empty_color);
- if (intermediate == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL1;
- }
+ if (trap_region)
+ status = _clip_and_compute_extents_region (gstate, trap_region, &extents);
+ else
+ status = _clip_and_compute_extents_arbitrary (gstate, traps, &extents);
- _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
-
- status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
- &pattern.base,
- intermediate,
- extents.x, extents.y,
- 0, 0,
- extents.width,
- extents.height,
- traps->traps,
- traps->num_traps);
- _cairo_pattern_fini (&pattern.base);
-
- if (status)
- goto BAIL2;
-
-
- _cairo_pattern_init_for_surface (&pattern.surface,
- gstate->clip.surface);
-
- status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- &pattern.base,
- NULL,
- intermediate,
- extents.x - gstate->clip.rect.x,
- extents.y - gstate->clip.rect.y,
- 0, 0,
- 0, 0,
- extents.width, extents.height);
- _cairo_pattern_fini (&pattern.base);
+ if (!CAIRO_OK (status))
+ goto out;
- if (status)
- goto BAIL2;
-
- _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
- _cairo_gstate_pattern_init_copy (gstate, &pattern, src);
-
- status = _cairo_surface_composite (operator,
- &pattern.base,
- &intermediate_pattern.base,
- dst,
- extents.x, extents.y,
- 0, 0,
- extents.x, extents.y,
- extents.width, extents.height);
-
- _cairo_pattern_fini (&pattern.base);
- _cairo_pattern_fini (&intermediate_pattern.base);
-
- BAIL2:
- cairo_surface_destroy (intermediate);
- BAIL1:
+ if (_cairo_rectangle_empty (&extents))
+ /* Nothing to do */
+ goto out;
- if (status)
- return status;
+ if (gstate->clip.surface) {
+ if (trap_region) {
+ /* If we are compositing a set of rectangles, we can set them as the
+ * clip region for the destination surface and use the clip surface
+ * as the mask. A clip region might not be supported, in which case
+ * we fall through to the next method
+ */
+ status = _composite_trap_region (gstate, src, operator, dst,
+ trap_region, &extents);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ goto out;
+ }
+ /* Handle a clip surface by creating an intermediate surface. */
+ status = _composite_traps_intermediate_surface (gstate, src, operator,
+ dst, traps, &extents);
} else {
- if (gstate->clip.region) {
- pixman_box16_t box;
- pixman_box16_t *intersection_extents;
- pixman_region16_t *rect, *intersection;
-
- box.x1 = _cairo_fixed_integer_floor (trap_extents.p1.x);
- box.y1 = _cairo_fixed_integer_floor (trap_extents.p1.y);
- box.x2 = _cairo_fixed_integer_ceil (trap_extents.p2.x);
- box.y2 = _cairo_fixed_integer_ceil (trap_extents.p2.y);
-
- rect = pixman_region_create_simple (&box);
- if (rect == NULL)
- goto bail1;
- intersection = pixman_region_create();
- if (intersection == NULL)
- goto bail2;
-
- if (pixman_region_intersect (intersection, gstate->clip.region,
- rect) != PIXMAN_REGION_STATUS_SUCCESS)
- goto bail3;
- intersection_extents = pixman_region_extents (intersection);
-
- extents.x = intersection_extents->x1;
- extents.y = intersection_extents->y1;
- extents.width = intersection_extents->x2 - intersection_extents->x1;
- extents.height = intersection_extents->y2 - intersection_extents->y1;
- bail3:
- pixman_region_destroy (intersection);
- bail2:
- pixman_region_destroy (rect);
- bail1:
- ;
+ /* No clip surface */
+ if (trap_region && src->type == CAIRO_PATTERN_SOLID) {
+ /* Solid rectangles are handled specially */
+ status = _composite_trap_region_solid (gstate, (cairo_solid_pattern_t *)src,
+ operator, dst, trap_region);
+ } else if (trap_region && pixman_region_num_rects (trap_region) <= 1) {
+ /* For a simple rectangle, we can just use composite(), for more
+ * rectangles, we'd have to set a clip region. That might still
+ * be a win, but it's less obvious. (Depends on the backend)
+ */
+ status = _composite_trap_region (gstate, src, operator, dst,
+ trap_region, &extents);
+ } else {
+ status = _composite_traps (gstate, src, operator,
+ dst, traps, &extents);
}
-
- _cairo_gstate_pattern_init_copy (gstate, &pattern, src);
-
- status = _cairo_surface_composite_trapezoids (gstate->operator,
- &pattern.base, dst,
- extents.x, extents.y,
- extents.x, extents.y,
- extents.width,
- extents.height,
- traps->traps,
- traps->num_traps);
-
- _cairo_pattern_fini (&pattern.base);
-
- if (status)
- return status;
}
+
+ out:
+ if (trap_region)
+ pixman_region_destroy (trap_region);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
cairo_status_t
-_cairo_gstate_fill (cairo_gstate_t *gstate)
+_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_status_t status;
cairo_traps_t traps;
+ if (gstate->surface->level != gstate->surface_level)
+ return CAIRO_STATUS_BAD_NESTING;
+
+ status = _cairo_surface_fill_path (gstate->operator,
+ gstate->source,
+ gstate->surface,
+ path);
+
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
_cairo_traps_init (&traps);
- status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
+ status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps);
if (status) {
_cairo_traps_fini (&traps);
return status;
}
_cairo_gstate_clip_and_composite_trapezoids (gstate,
- gstate->pattern,
+ gstate->source,
gstate->operator,
gstate->surface,
&traps);
_cairo_traps_fini (&traps);
- _cairo_gstate_new_path (gstate);
-
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gstate_in_fill (cairo_gstate_t *gstate,
- double x,
- double y,
- cairo_bool_t *inside_ret)
+_cairo_gstate_in_fill (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
+ double x,
+ double y,
+ cairo_bool_t *inside_ret)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_traps_t traps;
- cairo_matrix_transform_point (&gstate->ctm, &x, &y);
+ _cairo_gstate_user_to_backend (gstate, &x, &y);
_cairo_traps_init (&traps);
- status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
+ status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps);
if (status)
goto BAIL;
@@ -1693,7 +1506,8 @@ _cairo_gstate_show_page (cairo_gstate_t *gstate)
}
cairo_status_t
-_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
+_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2)
{
@@ -1701,9 +1515,11 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
cairo_traps_t traps;
cairo_box_t extents;
+ _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate);
+
_cairo_traps_init (&traps);
- status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
+ status = _cairo_path_fixed_stroke_to_traps (path, gstate, &traps);
if (status)
goto BAIL;
@@ -1714,8 +1530,8 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
*x2 = _cairo_fixed_to_double (extents.p2.x);
*y2 = _cairo_fixed_to_double (extents.p2.y);
- cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1);
- cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2);
+ _cairo_gstate_backend_to_user (gstate, x1, y1);
+ _cairo_gstate_backend_to_user (gstate, x2, y2);
BAIL:
_cairo_traps_fini (&traps);
@@ -1724,7 +1540,8 @@ BAIL:
}
cairo_status_t
-_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
+_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2)
{
@@ -1734,7 +1551,7 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate,
_cairo_traps_init (&traps);
- status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
+ status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps);
if (status)
goto BAIL;
@@ -1745,8 +1562,8 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate,
*x2 = _cairo_fixed_to_double (extents.p2.x);
*y2 = _cairo_fixed_to_double (extents.p2.y);
- cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1);
- cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2);
+ _cairo_gstate_backend_to_user (gstate, x1, y1);
+ _cairo_gstate_backend_to_user (gstate, x2, y2);
BAIL:
_cairo_traps_fini (&traps);
@@ -1755,8 +1572,11 @@ BAIL:
}
cairo_status_t
-_cairo_gstate_init_clip (cairo_gstate_t *gstate)
+_cairo_gstate_reset_clip (cairo_gstate_t *gstate)
{
+ if (gstate->surface->level != gstate->surface_level)
+ return CAIRO_STATUS_BAD_NESTING;
+
/* destroy any existing clip-region artifacts */
if (gstate->clip.surface)
cairo_surface_destroy (gstate->clip.surface);
@@ -1774,113 +1594,57 @@ _cairo_gstate_init_clip (cairo_gstate_t *gstate)
return CAIRO_STATUS_SUCCESS;
}
-static int
-extract_transformed_rectangle(cairo_matrix_t *mat,
- cairo_traps_t *tr,
- pixman_box16_t *box)
-{
- double a, b, c, d, tx, ty;
- cairo_status_t st;
-
- st = cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
- if (!(st == CAIRO_STATUS_SUCCESS && b == 0. && c == 0.))
- return 0;
-
- if (tr->num_traps == 1
- && tr->traps[0].left.p1.x == tr->traps[0].left.p2.x
- && tr->traps[0].right.p1.x == tr->traps[0].right.p2.x
- && tr->traps[0].left.p1.y == tr->traps[0].right.p1.y
- && tr->traps[0].left.p2.y == tr->traps[0].right.p2.y
- && _cairo_fixed_is_integer(tr->traps[0].left.p1.x)
- && _cairo_fixed_is_integer(tr->traps[0].left.p1.y)
- && _cairo_fixed_is_integer(tr->traps[0].left.p2.x)
- && _cairo_fixed_is_integer(tr->traps[0].left.p2.y)
- && _cairo_fixed_is_integer(tr->traps[0].right.p1.x)
- && _cairo_fixed_is_integer(tr->traps[0].right.p1.y)
- && _cairo_fixed_is_integer(tr->traps[0].right.p2.x)
- && _cairo_fixed_is_integer(tr->traps[0].right.p2.y)) {
-
- box->x1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.x);
- box->x2 = (short) _cairo_fixed_integer_part(tr->traps[0].right.p1.x);
- box->y1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.y);
- box->y2 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p2.y);
- return 1;
- }
- return 0;
-}
-
-/* Reset surface clip region to the one in the gstate */
-cairo_status_t
-_cairo_gstate_restore_external_state (cairo_gstate_t *gstate)
-{
- cairo_status_t status;
-
- status = CAIRO_STATUS_SUCCESS;
-
- if (gstate->surface)
- status = _cairo_surface_set_clip_region (gstate->surface,
- gstate->clip.region);
-
- /* If not supported we're already using surface clipping */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
- status = CAIRO_STATUS_SUCCESS;
-
- return status;
-}
-
cairo_status_t
-_cairo_gstate_clip (cairo_gstate_t *gstate)
+_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_status_t status;
cairo_pattern_union_t pattern;
cairo_traps_t traps;
- cairo_color_t white_color;
cairo_box_t extents;
- pixman_box16_t box;
+ pixman_region16_t *region;
+ if (gstate->surface->level != gstate->surface_level)
+ return CAIRO_STATUS_BAD_NESTING;
+
/* Fill the clip region as traps. */
_cairo_traps_init (&traps);
- status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
- if (status) {
+ status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps);
+ if (!CAIRO_OK (status)) {
_cairo_traps_fini (&traps);
return status;
}
/* Check to see if we can represent these traps as a PixRegion. */
- if (extract_transformed_rectangle (&gstate->ctm, &traps, &box)) {
-
- pixman_region16_t *rect = NULL;
- pixman_region16_t *intersection = NULL;
-
+ status = _cairo_traps_extract_region (&traps, &region);
+ if (!CAIRO_OK (status)) {
+ _cairo_traps_fini (&traps);
+ return status;
+ }
+
+ if (region) {
status = CAIRO_STATUS_SUCCESS;
- rect = pixman_region_create_simple (&box);
- if (rect == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
-
+ if (gstate->clip.region == NULL) {
+ gstate->clip.region = region;
} else {
-
- if (gstate->clip.region == NULL) {
- gstate->clip.region = rect;
- } else {
- intersection = pixman_region_create();
- if (pixman_region_intersect (intersection,
- gstate->clip.region, rect)
- == PIXMAN_REGION_STATUS_SUCCESS) {
- pixman_region_destroy (gstate->clip.region);
- gstate->clip.region = intersection;
- } else {
- status = CAIRO_STATUS_NO_MEMORY;
- }
- pixman_region_destroy (rect);
+ pixman_region16_t *intersection = pixman_region_create();
+
+ if (pixman_region_intersect (intersection,
+ gstate->clip.region, region)
+ == PIXMAN_REGION_STATUS_SUCCESS) {
+ pixman_region_destroy (gstate->clip.region);
+ gstate->clip.region = intersection;
+ } else {
+ status = CAIRO_STATUS_NO_MEMORY;
}
-
- if (!status)
- status = _cairo_surface_set_clip_region (gstate->surface,
- gstate->clip.region);
+ pixman_region_destroy (region);
}
+
+ if (CAIRO_OK (status))
+ status = _cairo_surface_set_clip_region (gstate->surface,
+ gstate->clip.region);
if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
_cairo_traps_fini (&traps);
@@ -1894,8 +1658,6 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
/* Otherwise represent the clip as a mask surface. */
- _cairo_color_init (&white_color);
-
if (gstate->clip.surface == NULL) {
_cairo_traps_extents (&traps, &extents);
_cairo_box_round_to_rectangle (&extents, &gstate->clip.rect);
@@ -1904,13 +1666,13 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
CAIRO_FORMAT_A8,
gstate->clip.rect.width,
gstate->clip.rect.height,
- &white_color);
+ CAIRO_COLOR_WHITE);
if (gstate->clip.surface == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
translate_traps (&traps, -gstate->clip.rect.x, -gstate->clip.rect.y);
- _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
+ _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
&pattern.base,
@@ -1929,254 +1691,77 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
return CAIRO_STATUS_SUCCESS;
}
-cairo_status_t
-_cairo_gstate_show_surface (cairo_gstate_t *gstate,
- cairo_surface_t *surface,
- int width,
- int height)
-{
-
- /* We are dealing with 6 coordinate spaces in this function. this makes
- * it ugly.
- *
- * - "Image" space is the space of the surface we're reading pixels from.
- * it is the surface argument to this function. The surface has a
- * matrix attached to it which maps "user" space (see below) into
- * image space.
- *
- * - "Device" space is the space of the surface we're ultimately writing
- * pixels to. It is the current surface of the gstate argument to
- * this function.
- *
- * - "User" space is an arbitrary space defined by the user, defined
- * implicitly by the gstate's CTM. The CTM maps from user space to
- * device space. The CTM inverse (which is also kept at all times)
- * maps from device space to user space.
- *
- * - "Clip" space is the space of the surface being used to clip pixels
- * during compositing. Space-wise, it is a bounding box (offset+size)
- * within device space. This surface is usually smaller than the device
- * surface (and possibly the image surface too) and logically occupies
- * a bounding box around the "clip path", situated somewhere in device
- * space. The clip path is already painted on the clip surface.
- *
- * - "Intermediate" space is the subset of the Clip space that the
- * drawing will affect, and we allocate an intermediate surface
- * of this size so that we can paint in it.
- *
- * - "Pattern" space is another arbitrary space defined in the pattern
- * element of gstate. As pixels are read from image space, they are
- * combined with pixels being read from pattern space and pixels
- * already existing in device space. User coordinates are converted
- * to pattern space, similarly, using a matrix attached to the pattern.
- * (in fact, there is a 7th space in here, which is the space of the
- * surface acting as a source for the pattern)
- *
- * To composite these spaces, we temporarily change the image surface
- * so that it can be read and written in device coordinates; in a sense
- * this makes it "spatially compatible" with the clip and device spaces.
- *
- *
- * There is also some confusion about the interaction between a clip and
- * a pattern; it is assumed that in this "show surface" operation a pattern
- * is to be used as an auxiliary alpha mask. this might be wrong, but it's
- * what we're doing now.
- *
- * so, to follow the operations below, remember that in the compositing
- * model, each operation is always of the form ((src IN mask) OP dst).
- * that's the basic operation.
- *
- * so the compositing we are trying to do here, in general, involves 2
- * steps, going via a temporary surface:
- *
- * - combining clip and pattern pixels together into a mask channel.
- * this will be ((pattern IN clip) SRC temporary). it ignores the
- * pixels already in the temporary, overwriting it with the
- * pattern, clipped to the clip mask.
- *
- * - combining temporary and "image" pixels with "device" pixels,
- * with a user-provided porter/duff operator. this will be
- * ((image IN temporary) OP device).
- *
- * if there is no clip, the degenerate case is just the second step
- * with pattern standing in for temporary.
- *
- */
-
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_matrix_t image_to_user, image_to_device;
- double device_x, device_y;
- double device_width, device_height;
- cairo_surface_pattern_t pattern;
- cairo_box_t pattern_extents;
- cairo_rectangle_t extents;
-
- cairo_surface_get_matrix (surface, &image_to_user);
- cairo_matrix_invert (&image_to_user);
- cairo_matrix_multiply (&image_to_device, &image_to_user, &gstate->ctm);
-
- _cairo_gstate_current_point (gstate, &device_x, &device_y);
- device_width = width;
- device_height = height;
- _cairo_matrix_transform_bounding_box (&image_to_device,
- &device_x, &device_y,
- &device_width, &device_height);
-
- _cairo_pattern_init_for_surface (&pattern, surface);
-
- /* inherit surface attributes while surface attribute functions still
- exist */
- pattern.base.matrix = surface->matrix;
- pattern.base.filter = surface->filter;
- if (surface->repeat)
- pattern.base.extend = CAIRO_EXTEND_REPEAT;
- else
- pattern.base.extend = CAIRO_EXTEND_NONE;
-
- _cairo_pattern_transform (&pattern.base, &gstate->ctm_inverse);
- _cairo_pattern_set_alpha (&pattern.base, gstate->alpha);
-
- pattern_extents.p1.x = _cairo_fixed_from_double (device_x);
- pattern_extents.p1.y = _cairo_fixed_from_double (device_y);
- pattern_extents.p2.x = _cairo_fixed_from_double (device_x + device_width);
- pattern_extents.p2.y = _cairo_fixed_from_double (device_y + device_height);
- _cairo_box_round_to_rectangle (&pattern_extents, &extents);
-
- if (gstate->clip.surface)
- {
- _cairo_rectangle_intersect (&extents, &gstate->clip.rect);
-
- /* We only need to composite if the rectangle is not empty. */
- if (!_cairo_rectangle_empty (&extents)) {
- cairo_surface_pattern_t clip_pattern;
-
- _cairo_pattern_init_for_surface (&clip_pattern,
- gstate->clip.surface);
-
- status = _cairo_surface_composite (gstate->operator,
- &pattern.base,
- &clip_pattern.base,
- gstate->surface,
- extents.x, extents.y,
- 0, 0,
- extents.x, extents.y,
- extents.width, extents.height);
-
- _cairo_pattern_fini (&clip_pattern.base);
- }
- }
- else
- {
- /* XXX: The rendered size is sometimes 1 or 2 pixels short
- * from what I expect. Need to fix this.
- * KRH: I'm guessing this was due to rounding error when
- * passing double coordinates for integer arguments. Using
- * the extents rectangle should fix this, since it's properly
- * rounded. Is this still the case?
- */
- status = _cairo_surface_composite (gstate->operator,
- &pattern.base,
- NULL,
- gstate->surface,
- extents.x, extents.y,
- 0, 0,
- extents.x, extents.y,
- extents.width, extents.height);
-
- }
-
- _cairo_pattern_fini (&pattern.base);
-
- return status;
-}
-
static void
_cairo_gstate_unset_font (cairo_gstate_t *gstate)
{
- if (gstate->font) {
- cairo_font_destroy (gstate->font);
- gstate->font = NULL;
+ if (gstate->scaled_font) {
+ cairo_scaled_font_destroy (gstate->scaled_font);
+ gstate->scaled_font = NULL;
}
}
cairo_status_t
-_cairo_gstate_select_font (cairo_gstate_t *gstate,
- const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight)
+_cairo_gstate_select_font_face (cairo_gstate_t *gstate,
+ const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight)
{
- char *new_family;
+ cairo_font_face_t *font_face;
- new_family = strdup (family);
- if (!new_family)
+ font_face = _cairo_simple_font_face_create (family, slant, weight);
+ if (!font_face)
return CAIRO_STATUS_NO_MEMORY;
-
- _cairo_gstate_unset_font (gstate);
-
- gstate->font_family = new_family;
- gstate->font_slant = slant;
- gstate->font_weight = weight;
- cairo_matrix_set_identity (&gstate->font_matrix);
-
+ _cairo_gstate_set_font_face (gstate, font_face);
+ cairo_font_face_destroy (font_face);
+
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gstate_scale_font (cairo_gstate_t *gstate,
- double scale)
+_cairo_gstate_set_font_size (cairo_gstate_t *gstate,
+ double size)
{
_cairo_gstate_unset_font (gstate);
- return cairo_matrix_scale (&gstate->font_matrix, scale, scale);
+ cairo_matrix_init_scale (&gstate->font_matrix, size, size);
+
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gstate_transform_font (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
+_cairo_gstate_set_font_matrix (cairo_gstate_t *gstate,
+ const cairo_matrix_t *matrix)
{
- cairo_matrix_t tmp;
- double a, b, c, d, tx, ty;
-
_cairo_gstate_unset_font (gstate);
- cairo_matrix_get_affine (matrix, &a, &b, &c, &d, &tx, &ty);
- cairo_matrix_set_affine (&tmp, a, b, c, d, 0, 0);
- return cairo_matrix_multiply (&gstate->font_matrix, &gstate->font_matrix, &tmp);
+ gstate->font_matrix = *matrix;
+
+ return CAIRO_STATUS_SUCCESS;
}
+void
+_cairo_gstate_get_font_matrix (cairo_gstate_t *gstate,
+ cairo_matrix_t *matrix)
+{
+ *matrix = gstate->font_matrix;
+}
cairo_status_t
-_cairo_gstate_current_font (cairo_gstate_t *gstate,
- cairo_font_t **font)
+_cairo_gstate_get_font_face (cairo_gstate_t *gstate,
+ cairo_font_face_t **font_face)
{
cairo_status_t status;
- status = _cairo_gstate_ensure_font (gstate);
+ status = _cairo_gstate_ensure_font_face (gstate);
if (status)
return status;
- *font = gstate->font;
+ *font_face = gstate->font_face;
return CAIRO_STATUS_SUCCESS;
}
-void
-_cairo_gstate_set_font_transform (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
-{
- _cairo_gstate_unset_font (gstate);
-
- cairo_matrix_copy (&gstate->font_matrix, matrix);
-}
-
-void
-_cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
-{
- cairo_matrix_copy (matrix, &gstate->font_matrix);
-}
-
/*
* Like everything else in this file, fonts involve Too Many Coordinate Spaces;
* it is easy to get confused about what's going on.
@@ -2191,11 +1776,10 @@ _cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
* independently scale the user coordinate system *or* the font matrix, in
* order to adjust the rendered size of the font.
*
- * The only font type exposed to the user is cairo_font_t which is a
- * a font specialized to a particular scale matrix, CTM, and target
- * surface. The user is responsible for not using a cairo_font_t
- * after changing the parameters; doing so will produce garbled metrics.
- *
+ * Metrics are returned in user space, whether they are obtained from
+ * the currently selected font in a #cairo_t or from a #cairo_scaled_font_t
+ * which is aa font specialized to a particular scale matrix, CTM, and target
+ * surface.
*
* The font's view
* ---------------
@@ -2254,122 +1838,102 @@ _cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
*
*/
-void
-_cairo_gstate_current_font_scale (cairo_gstate_t *gstate,
- cairo_font_scale_t *sc)
+static cairo_status_t
+_cairo_gstate_ensure_font_face (cairo_gstate_t *gstate)
{
- cairo_matrix_t tmp;
- double dummy;
- cairo_matrix_multiply (&tmp, &gstate->font_matrix, &gstate->ctm);
- cairo_matrix_get_affine (&tmp,
- &sc->matrix[0][0],
- &sc->matrix[0][1],
- &sc->matrix[1][0],
- &sc->matrix[1][1],
- &dummy, &dummy);
+ if (!gstate->font_face) {
+ gstate->font_face = _cairo_simple_font_face_create (CAIRO_FONT_FAMILY_DEFAULT,
+ CAIRO_FONT_SLANT_DEFAULT,
+ CAIRO_FONT_WEIGHT_DEFAULT);
+ if (!gstate->font_face)
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
}
-
+
static cairo_status_t
_cairo_gstate_ensure_font (cairo_gstate_t *gstate)
{
- cairo_font_scale_t sc;
cairo_status_t status;
- const char *family;
- if (gstate->font)
+ if (gstate->scaled_font)
return CAIRO_STATUS_SUCCESS;
- _cairo_gstate_current_font_scale (gstate, &sc);
-
- if (gstate->font_family)
- family = gstate->font_family;
- else
- family = CAIRO_FONT_FAMILY_DEFAULT;
-
- status = _cairo_font_create (family,
- gstate->font_slant,
- gstate->font_weight,
- &sc,
- &gstate->font);
-
+ status = _cairo_gstate_ensure_font_face (gstate);
if (status)
return status;
+ gstate->scaled_font = cairo_scaled_font_create (gstate->font_face,
+ &gstate->font_matrix,
+ &gstate->ctm);
+
+ if (!gstate->scaled_font)
+ return CAIRO_STATUS_NO_MEMORY;
+
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
- cairo_font_extents_t *extents)
+_cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
+ cairo_font_extents_t *extents)
{
cairo_status_t status = _cairo_gstate_ensure_font (gstate);
if (status)
return status;
- return cairo_font_extents (gstate->font,
- &gstate->font_matrix,
- extents);
+ return cairo_scaled_font_extents (gstate->scaled_font, extents);
}
cairo_status_t
_cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
- const unsigned char *utf8,
+ const char *utf8,
+ double x,
+ double y,
cairo_glyph_t **glyphs,
- int *nglyphs)
+ int *num_glyphs)
{
cairo_status_t status;
-
- cairo_point_t point;
- double origin_x, origin_y;
int i;
status = _cairo_gstate_ensure_font (gstate);
if (status)
return status;
- status = _cairo_path_current_point (&gstate->path, &point);
- if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
- origin_x = 0.0;
- origin_y = 0.0;
- } else {
- origin_x = _cairo_fixed_to_double (point.x);
- origin_y = _cairo_fixed_to_double (point.y);
- cairo_matrix_transform_point (&gstate->ctm_inverse,
- &origin_x, &origin_y);
- }
-
- status = _cairo_font_text_to_glyphs (gstate->font,
- utf8, glyphs, nglyphs);
+ status = _cairo_scaled_font_text_to_glyphs (gstate->scaled_font,
+ utf8, glyphs, num_glyphs);
- if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs))
+ if (status || !glyphs || !num_glyphs || !(*glyphs) || !(num_glyphs))
return status;
/* The font responded in glyph space, starting from (0,0). Convert to
user space by applying the font transform, then add any current point
offset. */
- for (i = 0; i < *nglyphs; ++i) {
+ for (i = 0; i < *num_glyphs; ++i) {
cairo_matrix_transform_point (&gstate->font_matrix,
&((*glyphs)[i].x),
&((*glyphs)[i].y));
- (*glyphs)[i].x += origin_x;
- (*glyphs)[i].y += origin_y;
+ (*glyphs)[i].x += x;
+ (*glyphs)[i].y += y;
}
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gstate_set_font (cairo_gstate_t *gstate,
- cairo_font_t *font)
-{
- if (font != gstate->font) {
- if (gstate->font)
- cairo_font_destroy (gstate->font);
- gstate->font = font;
- if (gstate->font)
- cairo_font_reference (gstate->font);
+_cairo_gstate_set_font_face (cairo_gstate_t *gstate,
+ cairo_font_face_t *font_face)
+{
+ if (font_face != gstate->font_face) {
+ if (gstate->font_face)
+ cairo_font_face_destroy (gstate->font_face);
+ gstate->font_face = font_face;
+ if (gstate->font_face)
+ cairo_font_face_reference (gstate->font_face);
}
+
+ _cairo_gstate_unset_font (gstate);
return CAIRO_STATUS_SUCCESS;
}
@@ -2386,10 +1950,9 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
if (status)
return status;
- cairo_font_glyph_extents (gstate->font,
- &gstate->font_matrix,
- glyphs, num_glyphs,
- extents);
+ cairo_scaled_font_glyph_extents (gstate->scaled_font,
+ glyphs, num_glyphs,
+ extents);
return CAIRO_STATUS_SUCCESS;
}
@@ -2406,6 +1969,9 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
cairo_box_t bbox;
cairo_rectangle_t extents;
+ if (gstate->surface->level != gstate->surface_level)
+ return CAIRO_STATUS_BAD_NESTING;
+
status = _cairo_gstate_ensure_font (gstate);
if (status)
return status;
@@ -2417,14 +1983,14 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
for (i = 0; i < num_glyphs; ++i)
{
transformed_glyphs[i] = glyphs[i];
- cairo_matrix_transform_point (&gstate->ctm,
- &transformed_glyphs[i].x,
- &transformed_glyphs[i].y);
+ _cairo_gstate_user_to_backend (gstate,
+ &transformed_glyphs[i].x,
+ &transformed_glyphs[i].y);
}
- status = _cairo_font_glyph_bbox (gstate->font,
- transformed_glyphs, num_glyphs,
- &bbox);
+ status = _cairo_scaled_font_glyph_bbox (gstate->scaled_font,
+ transformed_glyphs, num_glyphs,
+ &bbox);
_cairo_box_round_to_rectangle (&bbox, &extents);
if (status)
@@ -2434,7 +2000,6 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
{
cairo_surface_t *intermediate;
cairo_surface_pattern_t intermediate_pattern;
- cairo_color_t empty_color;
_cairo_rectangle_intersect (&extents, &gstate->clip.rect);
@@ -2444,13 +2009,11 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
goto BAIL1;
}
- _cairo_color_init (&empty_color);
- _cairo_color_set_alpha (&empty_color, .0);
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
CAIRO_FORMAT_A8,
extents.width,
extents.height,
- &empty_color);
+ CAIRO_COLOR_TRANSPARENT);
if (intermediate == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto BAIL1;
@@ -2463,15 +2026,15 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
transformed_glyphs[i].y -= extents.y;
}
- _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
+ _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
- status = _cairo_font_show_glyphs (gstate->font,
- CAIRO_OPERATOR_ADD,
- &pattern.base, intermediate,
- extents.x, extents.y,
- 0, 0,
- extents.width, extents.height,
- transformed_glyphs, num_glyphs);
+ status = _cairo_scaled_font_show_glyphs (gstate->scaled_font,
+ CAIRO_OPERATOR_ADD,
+ &pattern.base, intermediate,
+ extents.x, extents.y,
+ 0, 0,
+ extents.width, extents.height,
+ transformed_glyphs, num_glyphs);
_cairo_pattern_fini (&pattern.base);
@@ -2497,7 +2060,8 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
goto BAIL2;
_cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
- _cairo_gstate_pattern_init_copy (gstate, &pattern, gstate->pattern);
+ _cairo_pattern_init_copy (&pattern.base, gstate->source);
+ _cairo_gstate_pattern_transform (gstate, &pattern.base);
status = _cairo_surface_composite (gstate->operator,
&pattern.base,
@@ -2517,15 +2081,16 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
}
else
{
- _cairo_gstate_pattern_init_copy (gstate, &pattern, gstate->pattern);
+ _cairo_pattern_init_copy (&pattern.base, gstate->source);
+ _cairo_gstate_pattern_transform (gstate, &pattern.base);
- status = _cairo_font_show_glyphs (gstate->font,
- gstate->operator, &pattern.base,
- gstate->surface,
- extents.x, extents.y,
- extents.x, extents.y,
- extents.width, extents.height,
- transformed_glyphs, num_glyphs);
+ status = _cairo_scaled_font_show_glyphs (gstate->scaled_font,
+ gstate->operator, &pattern.base,
+ gstate->surface,
+ extents.x, extents.y,
+ extents.x, extents.y,
+ extents.width, extents.height,
+ transformed_glyphs, num_glyphs);
_cairo_pattern_fini (&pattern.base);
}
@@ -2537,14 +2102,19 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
}
cairo_status_t
-_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
- cairo_glyph_t *glyphs,
- int num_glyphs)
+_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_fixed_t *path)
{
cairo_status_t status;
int i;
cairo_glyph_t *transformed_glyphs = NULL;
+ status = _cairo_gstate_ensure_font (gstate);
+ if (status)
+ return status;
+
transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
if (transformed_glyphs == NULL)
return CAIRO_STATUS_NO_MEMORY;
@@ -2552,14 +2122,14 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
for (i = 0; i < num_glyphs; ++i)
{
transformed_glyphs[i] = glyphs[i];
- cairo_matrix_transform_point (&gstate->ctm,
- &(transformed_glyphs[i].x),
- &(transformed_glyphs[i].y));
+ _cairo_gstate_user_to_backend (gstate,
+ &(transformed_glyphs[i].x),
+ &(transformed_glyphs[i].y));
}
- status = _cairo_font_glyph_path (gstate->font,
- transformed_glyphs, num_glyphs,
- &gstate->path);
+ status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
+ transformed_glyphs, num_glyphs,
+ path);
free (transformed_glyphs);
return status;
diff --git a/src/cairo-hash.c b/src/cairo-hash.c
index d1ad5a4e2..e95894960 100644
--- a/src/cairo-hash.c
+++ b/src/cairo-hash.c
@@ -113,7 +113,9 @@ static const cairo_cache_arrangement_t cache_arrangements [] = {
#define LIVE_ENTRY_P(cache, i) \
(!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i)))))
-#ifdef CAIRO_DO_SANITY_CHECKING
+#ifdef NDEBUG
+#define _cache_sane_state(c)
+#else
static void
_cache_sane_state (cairo_cache_t *cache)
{
@@ -125,8 +127,6 @@ _cache_sane_state (cairo_cache_t *cache)
/* assert (cache->used_memory <= cache->max_memory); */
assert (cache->live_entries <= cache->arrangement->size);
}
-#else
-#define _cache_sane_state(c)
#endif
static void
@@ -351,8 +351,9 @@ _cairo_cache_init (cairo_cache_t *cache,
#endif
cache->backend = backend;
- cache->entries = calloc (sizeof(cairo_cache_entry_base_t *),
- cache->arrangement->size);
+ cache->entries = calloc (cache->arrangement->size,
+ sizeof(cairo_cache_entry_base_t *));
+
if (cache->entries == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 9745b3150..19dc7b611 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -68,7 +68,7 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
surface->pixman_image = pixman_image;
surface->format = format;
- surface->data = (char *) pixman_image_get_data (pixman_image);
+ surface->data = (unsigned char *) pixman_image_get_data (pixman_image);
surface->owns_data = 0;
surface->width = pixman_image_get_width (pixman_image);
@@ -80,8 +80,8 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
}
cairo_image_surface_t *
-_cairo_image_surface_create_with_masks (char *data,
- cairo_format_masks_t *format,
+_cairo_image_surface_create_with_masks (unsigned char *data,
+ cairo_format_masks_t *format,
int width,
int height,
int stride)
@@ -195,7 +195,7 @@ cairo_image_surface_create (cairo_format_t format,
* be created because of lack of memory
**/
cairo_surface_t *
-cairo_image_surface_create_for_data (char *data,
+cairo_image_surface_create_for_data (unsigned char *data,
cairo_format_t format,
int width,
int height,
@@ -224,6 +224,38 @@ cairo_image_surface_create_for_data (char *data,
return &surface->base;
}
+/**
+ * cairo_image_surface_get_width:
+ * @surface: a #cairo_image_surface_t
+ *
+ * Get the width of the image surface in pixels.
+ *
+ * Return value: the width of the surface in pixels.
+ **/
+int
+cairo_image_surface_get_width (cairo_surface_t *surface)
+{
+ cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
+
+ return image_surface->width;
+}
+
+/**
+ * cairo_image_surface_get_height:
+ * @surface: a #cairo_image_surface_t
+ *
+ * Get the height of the image surface in pixels.
+ *
+ * Return value: the height of the surface in pixels.
+ **/
+int
+cairo_image_surface_get_height (cairo_surface_t *surface)
+{
+ cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
+
+ return image_surface->height;
+}
+
static cairo_surface_t *
_cairo_image_surface_create_similar (void *abstract_src,
cairo_format_t format,
@@ -234,20 +266,22 @@ _cairo_image_surface_create_similar (void *abstract_src,
return cairo_image_surface_create (format, width, height);
}
-static void
-_cairo_image_abstract_surface_destroy (void *abstract_surface)
+static cairo_status_t
+_cairo_image_abstract_surface_finish (void *abstract_surface)
{
cairo_image_surface_t *surface = abstract_surface;
- if (surface->pixman_image)
+ if (surface->pixman_image) {
pixman_image_destroy (surface->pixman_image);
+ surface->pixman_image = NULL;
+ }
if (surface->owns_data) {
free (surface->data);
surface->data = NULL;
}
- free (surface);
+ return CAIRO_STATUS_SUCCESS;
}
void
@@ -256,13 +290,6 @@ _cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface)
surface->owns_data = 1;
}
-static double
-_cairo_image_surface_pixels_per_inch (void *abstract_surface)
-{
- /* XXX: We'll want a way to let the user set this. */
- return 96.0;
-}
-
static cairo_status_t
_cairo_image_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
@@ -327,17 +354,17 @@ _cairo_image_surface_clone_similar (void *abstract_surface,
cairo_status_t
_cairo_image_surface_set_matrix (cairo_image_surface_t *surface,
- cairo_matrix_t *matrix)
+ const cairo_matrix_t *matrix)
{
pixman_transform_t pixman_transform;
- pixman_transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
- pixman_transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
- pixman_transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
+ pixman_transform.matrix[0][0] = _cairo_fixed_from_double (matrix->xx);
+ pixman_transform.matrix[0][1] = _cairo_fixed_from_double (matrix->xy);
+ pixman_transform.matrix[0][2] = _cairo_fixed_from_double (matrix->x0);
- pixman_transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
- pixman_transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
- pixman_transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
+ pixman_transform.matrix[1][0] = _cairo_fixed_from_double (matrix->yx);
+ pixman_transform.matrix[1][1] = _cairo_fixed_from_double (matrix->yy);
+ pixman_transform.matrix[1][2] = _cairo_fixed_from_double (matrix->y0);
pixman_transform.matrix[2][0] = 0;
pixman_transform.matrix[2][1] = 0;
@@ -414,32 +441,40 @@ _cairo_image_surface_set_attributes (cairo_image_surface_t *surface,
return status;
}
+/* XXX: I think we should fix pixman to match the names/order of the
+ * cairo operators, but that will likely be better done at the same
+ * time the X server is ported to pixman, (which will change a lot of
+ * things in pixman I think).
+ */
static pixman_operator_t
_pixman_operator (cairo_operator_t operator)
{
switch (operator) {
case CAIRO_OPERATOR_CLEAR:
return PIXMAN_OPERATOR_CLEAR;
- case CAIRO_OPERATOR_SRC:
+
+ case CAIRO_OPERATOR_SOURCE:
return PIXMAN_OPERATOR_SRC;
- case CAIRO_OPERATOR_DST:
- return PIXMAN_OPERATOR_DST;
case CAIRO_OPERATOR_OVER:
return PIXMAN_OPERATOR_OVER;
- case CAIRO_OPERATOR_OVER_REVERSE:
- return PIXMAN_OPERATOR_OVER_REVERSE;
case CAIRO_OPERATOR_IN:
return PIXMAN_OPERATOR_IN;
- case CAIRO_OPERATOR_IN_REVERSE:
- return PIXMAN_OPERATOR_IN_REVERSE;
case CAIRO_OPERATOR_OUT:
return PIXMAN_OPERATOR_OUT;
- case CAIRO_OPERATOR_OUT_REVERSE:
- return PIXMAN_OPERATOR_OUT_REVERSE;
case CAIRO_OPERATOR_ATOP:
return PIXMAN_OPERATOR_ATOP;
- case CAIRO_OPERATOR_ATOP_REVERSE:
+
+ case CAIRO_OPERATOR_DEST:
+ return PIXMAN_OPERATOR_DST;
+ case CAIRO_OPERATOR_DEST_OVER:
+ return PIXMAN_OPERATOR_OVER_REVERSE;
+ case CAIRO_OPERATOR_DEST_IN:
+ return PIXMAN_OPERATOR_IN_REVERSE;
+ case CAIRO_OPERATOR_DEST_OUT:
+ return PIXMAN_OPERATOR_OUT_REVERSE;
+ case CAIRO_OPERATOR_DEST_ATOP:
return PIXMAN_OPERATOR_ATOP_REVERSE;
+
case CAIRO_OPERATOR_XOR:
return PIXMAN_OPERATOR_XOR;
case CAIRO_OPERATOR_ADD:
@@ -587,7 +622,7 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t operator,
* somehow. */
status = _cairo_image_surface_set_attributes (src, &attributes);
if (CAIRO_OK (status))
- pixman_composite_trapezoids (operator,
+ pixman_composite_trapezoids (_pixman_operator (operator),
src->pixman_image,
dst->pixman_image,
render_src_x + attributes.x_offset,
@@ -600,18 +635,6 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t operator,
}
static cairo_int_status_t
-_cairo_image_surface_copy_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
_cairo_image_abstract_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
@@ -642,6 +665,27 @@ _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
+static cairo_int_status_t
+_cairo_image_surface_get_extents (cairo_image_surface_t *surface,
+ cairo_rectangle_t *rectangle)
+{
+ rectangle->x = 0;
+ rectangle->y = 0;
+ rectangle->width = surface->width;
+ rectangle->height = surface->height;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_image_abstract_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t *rectangle)
+{
+ cairo_image_surface_t *surface = abstract_surface;
+
+ return _cairo_image_surface_get_extents (surface, rectangle);
+}
+
/**
* _cairo_surface_is_image:
* @surface: a #cairo_surface_t
@@ -658,8 +702,7 @@ _cairo_surface_is_image (cairo_surface_t *surface)
static const cairo_surface_backend_t cairo_image_surface_backend = {
_cairo_image_surface_create_similar,
- _cairo_image_abstract_surface_destroy,
- _cairo_image_surface_pixels_per_inch,
+ _cairo_image_abstract_surface_finish,
_cairo_image_surface_acquire_source_image,
_cairo_image_surface_release_source_image,
_cairo_image_surface_acquire_dest_image,
@@ -668,8 +711,9 @@ static const cairo_surface_backend_t cairo_image_surface_backend = {
_cairo_image_surface_composite,
_cairo_image_surface_fill_rectangles,
_cairo_image_surface_composite_trapezoids,
- _cairo_image_surface_copy_page,
- _cairo_image_surface_show_page,
+ NULL, /* copy_page */
+ NULL, /* show_page */
_cairo_image_abstract_surface_set_clip_region,
+ _cairo_image_abstract_surface_get_extents,
NULL /* show_glyphs */
};
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index 88e536e8a..82ec0dbb7 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -40,14 +40,6 @@
#include "cairoint.h"
-static cairo_matrix_t const CAIRO_MATRIX_IDENTITY = {
- {
- {1, 0},
- {0, 1},
- {0, 0}
- }
-};
-
static void
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar);
@@ -55,228 +47,185 @@ static void
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix);
/**
- * cairo_matrix_create:
- *
- * Creates a new identity matrix.
- *
- * Return value: a newly created matrix; free with cairo_matrix_destroy(),
- * or %NULL if memory couldn't be allocated.
- **/
-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 */
-}
-
-/**
- * cairo_matrix_destroy:
- * @matrix: a #cairo_matrix_t
- *
- * Frees a matrix created with cairo_matrix_create.
- **/
-void
-cairo_matrix_destroy (cairo_matrix_t *matrix)
-{
- _cairo_matrix_fini (matrix);
- free (matrix);
-}
-
-/**
- * cairo_matrix_copy:
- * @matrix: a #cairo_matrix_t
- * @other: another #cairo_
- *
- * Modifies @matrix to be identical to @other.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-cairo_status_t
-cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other)
-{
- *matrix = *other;
-
- return CAIRO_STATUS_SUCCESS;
-}
-slim_hidden_def(cairo_matrix_copy);
-
-/**
- * cairo_matrix_set_identity:
+ * cairo_matrix_init_identity:
* @matrix: a #cairo_matrix_t
*
* Modifies @matrix to be an identity transformation.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
**/
-cairo_status_t
-cairo_matrix_set_identity (cairo_matrix_t *matrix)
+void
+cairo_matrix_init_identity (cairo_matrix_t *matrix)
{
- *matrix = CAIRO_MATRIX_IDENTITY;
-
- return CAIRO_STATUS_SUCCESS;
+ cairo_matrix_init (matrix,
+ 1, 0,
+ 0, 1,
+ 0, 0);
}
-slim_hidden_def(cairo_matrix_set_identity);
+slim_hidden_def(cairo_matrix_init_identity);
/**
- * cairo_matrix_set_affine:
+ * cairo_matrix_init:
* @matrix: a cairo_matrix_t
- * @a: a component of the affine transformation
- * @b: b component of the affine transformation
- * @c: c component of the affine transformation
- * @d: d component of the affine transformation
- * @tx: X translation component of the affine transformation
- * @ty: Y translation component of the affine transformation
+ * @xx: xx component of the affine transformation
+ * @yx: yx component of the affine transformation
+ * @xy: xy component of the affine transformation
+ * @yy: yy component of the affine transformation
+ * @x0: X translation component of the affine transformation
+ * @y0: Y translation component of the affine transformation
*
* Sets @matrix to be the affine transformation given by
- * @a, b, @c, @d, @tx, @ty. The transformation is given
+ * @xx, @yx, @xy, @yy, @x0, @y0. The transformation is given
* by:
* <programlisting>
- * x_new = x * a + y * c + tx;
- * y_new = x * b + y * d + ty;
+ * x_new = xx * x + xy * y + x0;
+ * y_new = yx * x + yy * y + y0;
* </programlisting>
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
**/
-cairo_status_t
-cairo_matrix_set_affine (cairo_matrix_t *matrix,
- double a, double b,
- double c, double d,
- double tx, double ty)
+void
+cairo_matrix_init (cairo_matrix_t *matrix,
+ double xx, double yx,
+ double xy, double yy,
+ double x0, double y0)
{
- 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;
+ matrix->xx = xx; matrix->yx = yx;
+ matrix->xy = xy; matrix->yy = yy;
+ matrix->x0 = x0; matrix->y0 = y0;
}
-slim_hidden_def(cairo_matrix_set_affine);
+slim_hidden_def(cairo_matrix_init);
/**
- * cairo_matrix_get_affine:
+ * _cairo_matrix_get_affine:
* @matrix: a @cairo_matrix_t
- * @a: location to store a component of affine transformation, or %NULL
- * @b: location to store b component of affine transformation, or %NULL
- * @c: location to store c component of affine transformation, or %NULL
- * @d: location to store d component of affine transformation, or %NULL
- * @tx: location to store X-translation component of affine transformation, or %NULL
- * @ty: location to store Y-translation component of affine transformation, or %NULL
+ * @xx: location to store xx component of matrix
+ * @yx: location to store yx component of matrix
+ * @xy: location to store xy component of matrix
+ * @yy: location to store yy component of matrix
+ * @x0: location to store x0 (X-translation component) of matrix, or %NULL
+ * @y0: location to store y0 (Y-translation component) of matrix, or %NULL
*
* Gets the matrix values for the affine tranformation that @matrix represents.
- * See cairo_matrix_set_affine().
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
+ * See cairo_matrix_init().
+ *
+ *
+ * This function is a leftover from the old public API, but is still
+ * mildly useful as an internal means for getting at the matrix
+ * members in a positional way. For example, when reassigning to some
+ * external matrix type, or when renaming members to more meaningful
+ * names (such as a,b,c,d,e,f) for particular manipulations.
**/
-cairo_status_t
-cairo_matrix_get_affine (cairo_matrix_t *matrix,
- double *a, double *b,
- double *c, double *d,
- double *tx, double *ty)
+void
+_cairo_matrix_get_affine (const cairo_matrix_t *matrix,
+ double *xx, double *yx,
+ double *xy, double *yy,
+ double *x0, double *y0)
{
- if (a)
- *a = matrix->m[0][0];
- if (b)
- *b = matrix->m[0][1];
+ *xx = matrix->xx;
+ *yx = matrix->yx;
- if (c)
- *c = matrix->m[1][0];
- if (d)
- *d = matrix->m[1][1];
+ *xy = matrix->xy;
+ *yy = matrix->yy;
- if (tx)
- *tx = matrix->m[2][0];
- if (ty)
- *ty = matrix->m[2][1];
-
- return CAIRO_STATUS_SUCCESS;
+ if (x0)
+ *x0 = matrix->x0;
+ if (y0)
+ *y0 = matrix->y0;
}
-cairo_status_t
-_cairo_matrix_set_translate (cairo_matrix_t *matrix,
+/**
+ * cairo_matrix_init_translate:
+ * @matrix: a cairo_matrix_t
+ * @tx: amount to translate in the X direction
+ * @ty: amount to translate in the Y direction
+ *
+ * Initializes @matrix to a transformation that translates by @tx and
+ * @ty in the X and Y dimensions, respectively.
+ **/
+void
+cairo_matrix_init_translate (cairo_matrix_t *matrix,
double tx, double ty)
{
- return cairo_matrix_set_affine (matrix,
- 1, 0,
- 0, 1,
- tx, ty);
+ cairo_matrix_init (matrix,
+ 1, 0,
+ 0, 1,
+ tx, ty);
}
+slim_hidden_def(cairo_matrix_init_translate);
/**
* cairo_matrix_translate:
* @matrix: a cairo_matrix_t
- * @tx: amount to rotate in the X direction
- * @ty: amount to rotate in the Y direction
+ * @tx: amount to translate in the X direction
+ * @ty: amount to translate in the Y direction
*
* Applies a translation by @tx, @ty to the transformation in
- * @matrix. The new transformation is given by first translating by
- * @tx, @ty then applying the original transformation
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
+ * @matrix. The effect of the new transformation is to first translate
+ * the coordinates by @tx and @ty, then apply the original transformation
+ * to the coordinates.
**/
-cairo_status_t
+void
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty)
{
cairo_matrix_t tmp;
- _cairo_matrix_set_translate (&tmp, tx, ty);
+ cairo_matrix_init_translate (&tmp, tx, ty);
- return cairo_matrix_multiply (matrix, &tmp, matrix);
+ cairo_matrix_multiply (matrix, &tmp, matrix);
}
-cairo_status_t
-_cairo_matrix_set_scale (cairo_matrix_t *matrix,
+/**
+ * cairo_matrix_init_scale:
+ * @matrix: a cairo_matrix_t
+ * @sx: scale factor in the X direction
+ * @sy: scale factor in the Y direction
+ *
+ * Initializes @matrix to a transformation that scales by @sx and @sy
+ * in the X and Y dimensions, respectively.
+ **/
+void
+cairo_matrix_init_scale (cairo_matrix_t *matrix,
double sx, double sy)
{
- return cairo_matrix_set_affine (matrix,
- sx, 0,
- 0, sy,
- 0, 0);
+ cairo_matrix_init (matrix,
+ sx, 0,
+ 0, sy,
+ 0, 0);
}
+slim_hidden_def(cairo_matrix_init_scale);
/**
* cairo_matrix_scale:
* @matrix: a #cairo_matrix_t
- * @sx: Scale factor in the X direction
- * @sy: Scale factor in the Y direction
+ * @sx: scale factor in the X direction
+ * @sy: scale factor in the Y direction
*
- * Applies scaling by @tx, @ty to the transformation in
- * @matrix. The new transformation is given by first scaling by @sx
- * and @sy then applying the original transformation
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
+ * Applies scaling by @tx, @ty to the transformation in @matrix. The
+ * effect of the new transformation is to first scale the coordinates
+ * by @sx and @sy, then apply the original transformation to the coordinates.
**/
-cairo_status_t
+void
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy)
{
cairo_matrix_t tmp;
- _cairo_matrix_set_scale (&tmp, sx, sy);
+ cairo_matrix_init_scale (&tmp, sx, sy);
- return cairo_matrix_multiply (matrix, &tmp, matrix);
+ cairo_matrix_multiply (matrix, &tmp, matrix);
}
slim_hidden_def(cairo_matrix_scale);
-cairo_status_t
-_cairo_matrix_set_rotate (cairo_matrix_t *matrix,
- double radians)
+/**
+ * cairo_matrix_init_rotate:
+ * @matrix: a cairo_matrix_t
+ * @radians: angle of rotation, in radians. The direction of rotation
+ * is defined such that positive angles rotate in the direction from
+ * the positive X axis toward the positive Y axis. With the default
+ * axis orientation of cairo, positive angles rotate in a clockwise
+ * direction.
+ *
+ * Initialized @matrix to a transformation that rotates by @radians.
+ **/
+void
+cairo_matrix_init_rotate (cairo_matrix_t *matrix,
+ double radians)
{
double s;
double c;
@@ -286,35 +235,35 @@ _cairo_matrix_set_rotate (cairo_matrix_t *matrix,
s = sin (radians);
c = cos (radians);
#endif
- return cairo_matrix_set_affine (matrix,
- c, s,
- -s, c,
- 0, 0);
+ cairo_matrix_init (matrix,
+ c, s,
+ -s, c,
+ 0, 0);
}
+slim_hidden_def(cairo_matrix_init_rotate);
/**
* cairo_matrix_rotate:
* @matrix: a @cairo_matrix_t
- * @radians: angle of rotation, in radians. Angles are defined
- * so that an angle of 90 degrees (%M_PI radians) rotates the
- * positive X axis into the positive Y axis. With the default
- * Cairo choice of axis orientation, positive rotations are
- * clockwise.
+ * @radians: angle of rotation, in radians. The direction of rotation
+ * is defined such that positive angles rotate in the direction from
+ * the positive X axis toward the positive Y axis. With the default
+ * axis orientation of cairo, positive angles rotate in a clockwise
+ * direction.
*
* Applies rotation by @radians to the transformation in
- * @matrix. The new transformation is given by first rotating by
- * @radians then applying the original transformation
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
+ * @matrix. The effect of the new transformation is to first rotate the
+ * coordinates by @radians, then apply the original transformation
+ * to the coordinates.
**/
-cairo_status_t
+void
cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
{
cairo_matrix_t tmp;
- _cairo_matrix_set_rotate (&tmp, radians);
+ cairo_matrix_init_rotate (&tmp, radians);
- return cairo_matrix_multiply (matrix, &tmp, matrix);
+ cairo_matrix_multiply (matrix, &tmp, matrix);
}
/**
@@ -324,46 +273,47 @@ cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
* @b: a @cairo_matrix_t
*
* Multiplies the affine transformations in @a and @b together
- * and stores the result in @result. The resulting transformation
- * is given by first applying the transformation in @b then
- * applying the transformation in @a.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
+ * and stores the result in @result. The effect of the resulting
+ * transformation is to first apply the transformation in @a to the
+ * coordinates and then apply the transformation in @b to the
+ * coordinates.
+ *
+ * It is allowable for @result to be identical to either @a or @b.
**/
-cairo_status_t
+/*
+ * XXX: The ordering of the arguments to this function corresponds
+ * to [row_vector]*A*B. If we want to use column vectors instead,
+ * then we need to switch the two arguments and fix up all
+ * uses.
+ */
+void
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;
+ r.xx = a->xx * b->xx + a->yx * b->xy;
+ r.yx = a->xx * b->yx + a->yx * b->yy;
- return CAIRO_STATUS_SUCCESS;
+ r.xy = a->xy * b->xx + a->yy * b->xy;
+ r.yy = a->xy * b->yx + a->yy * b->yy;
+
+ r.x0 = a->x0 * b->xx + a->y0 * b->xy + b->x0;
+ r.y0 = a->x0 * b->yx + a->y0 * b->yy + b->y0;
+
+ *result = r;
}
slim_hidden_def(cairo_matrix_multiply);
/**
* cairo_matrix_transform_distance:
* @matrix: a @cairo_matrix_t
- * @dx: a distance in the X direction. An in/out parameter
- * @dy: a distance in the Y direction. An in/out parameter
+ * @dx: X component of a distance vector. An in/out parameter
+ * @dy: Y component of a distance vector. An in/out parameter
*
- * Transforms the vector (@dx,@dy) by @matrix. Translation is
- * ignored. In terms of the components of the affine transformation:
+ * Transforms the distance vector (@dx,@dy) by @matrix. This is
+ * similar to cairo_matrix_transform() except that the translation
+ * components of the transformation are ignored. The calculation of
+ * the returned vector is as follows:
*
* <programlisting>
* dx2 = dx1 * a + dy1 * c;
@@ -374,23 +324,17 @@ slim_hidden_def(cairo_matrix_multiply);
* always transforms to the same vector. If (@x1,@y1) transforms
* to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to
* (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
**/
-cairo_status_t
-cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy)
+void
+cairo_matrix_transform_distance (const 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);
+ new_x = (matrix->xx * *dx + matrix->xy * *dy);
+ new_y = (matrix->yx * *dx + matrix->yy * *dy);
*dx = new_x;
*dy = new_y;
-
- return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def(cairo_matrix_transform_distance);
@@ -401,23 +345,19 @@ slim_hidden_def(cairo_matrix_transform_distance);
* @y: Y position. An in/out parameter
*
* Transforms the point (@x, @y) by @matrix.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
**/
-cairo_status_t
-cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y)
+void
+cairo_matrix_transform_point (const 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;
+ *x += matrix->x0;
+ *y += matrix->y0;
}
slim_hidden_def(cairo_matrix_transform_point);
-cairo_status_t
-_cairo_matrix_transform_bounding_box (cairo_matrix_t *matrix,
+void
+_cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
double *x, double *y,
double *width, double *height)
{
@@ -466,18 +406,19 @@ _cairo_matrix_transform_bounding_box (cairo_matrix_t *matrix,
*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;
+ matrix->xx *= scalar;
+ matrix->yx *= scalar;
+
+ matrix->xy *= scalar;
+ matrix->yy *= scalar;
- for (row = 0; row < 3; row++)
- for (col = 0; col < 2; col++)
- matrix->m[row][col] *= scalar;
+ matrix->x0 *= scalar;
+ matrix->y0 *= scalar;
}
/* This function isn't a correct adjoint in that the implicit 1 in the
@@ -490,14 +431,15 @@ _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_get_affine (matrix,
+ &a, &b,
+ &c, &d,
+ &tx, &ty);
- cairo_matrix_set_affine (matrix,
- d, -b,
- -c, a,
- c*ty - d*tx, b*tx - a*ty);
+ cairo_matrix_init (matrix,
+ d, -b,
+ -c, a,
+ c*ty - d*tx, b*tx - a*ty);
}
/**
@@ -531,21 +473,21 @@ cairo_matrix_invert (cairo_matrix_t *matrix)
}
slim_hidden_def(cairo_matrix_invert);
-cairo_status_t
-_cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det)
+void
+_cairo_matrix_compute_determinant (const 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];
+ a = matrix->xx; b = matrix->yx;
+ c = matrix->xy; d = matrix->yy;
*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)
+void
+_cairo_matrix_compute_eigen_values (const cairo_matrix_t *matrix,
+ double *lambda1, double *lambda2)
{
/* The eigenvalues of an NxN matrix M are found by solving the polynomial:
@@ -566,21 +508,18 @@ _cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, dou
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];
+ a = matrix->xx; b = matrix->yx;
+ c = matrix->xy; d = matrix->yy;
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;
}
/* Compute the amount that each basis vector is scaled by. */
cairo_status_t
-_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy, int x_major)
+_cairo_matrix_compute_scale_factors (const cairo_matrix_t *matrix,
+ double *sx, double *sy, int x_major)
{
double det;
@@ -621,13 +560,13 @@ _cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double
}
cairo_bool_t
-_cairo_matrix_is_integer_translation(cairo_matrix_t *mat,
+_cairo_matrix_is_integer_translation(const cairo_matrix_t *mat,
int *itx, int *ity)
{
double a, b, c, d, tx, ty;
int ttx, tty;
int ok = 0;
- cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
+ _cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
ttx = _cairo_fixed_from_double (tx);
tty = _cairo_fixed_from_double (ty);
ok = ((a == 1.0)
diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
new file mode 100644
index 000000000..14b4486a6
--- /dev/null
+++ b/src/cairo-output-stream.c
@@ -0,0 +1,285 @@
+/* cairo_output_stream.c: Output stream abstraction
+ *
+ * Copyright © 2005 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is cairo_output_stream.c as distributed with the
+ * cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Author(s):
+ * Kristian Høgsberg <krh@redhat.com>
+ */
+
+#include <stdio.h>
+#include <locale.h>
+#include <ctype.h>
+#include "cairoint.h"
+
+struct _cairo_output_stream {
+ cairo_write_func_t write_data;
+ void *closure;
+ cairo_bool_t owns_closure_is_file;
+ unsigned long position;
+ cairo_status_t status;
+};
+
+cairo_output_stream_t *
+_cairo_output_stream_create (cairo_write_func_t write_data,
+ void *closure)
+{
+ cairo_output_stream_t *stream;
+
+ stream = malloc (sizeof (cairo_output_stream_t));
+ if (stream == NULL)
+ return NULL;
+
+ stream->write_data = write_data;
+ stream->closure = closure;
+ stream->owns_closure_is_file = FALSE;
+ stream->position = 0;
+ stream->status = CAIRO_STATUS_SUCCESS;
+
+ return stream;
+}
+
+void
+_cairo_output_stream_destroy (cairo_output_stream_t *stream)
+{
+ if (stream->owns_closure_is_file) {
+ FILE *file = stream->closure;
+ fflush (file);
+ fclose (file);
+ }
+ free (stream);
+}
+
+cairo_status_t
+_cairo_output_stream_write (cairo_output_stream_t *stream,
+ const void *data, size_t length)
+{
+ if (length == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ stream->status = stream->write_data (stream->closure, data, length);
+ stream->position += length;
+
+ return stream->status;
+}
+
+/* Format a double in a locale independent way and trim trailing
+ * zeros. Based on code from Alex Larson <alexl@redhat.com>.
+ * http://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html
+ */
+
+static int
+dtostr (char *buffer, size_t size, double d)
+{
+ struct lconv *locale_data;
+ const char *decimal_point;
+ int decimal_point_len;
+ char *p;
+ int decimal_len;
+
+ snprintf (buffer, size, "%f", d);
+
+ locale_data = localeconv ();
+ decimal_point = locale_data->decimal_point;
+ decimal_point_len = strlen (decimal_point);
+
+ assert (decimal_point_len != 0);
+ p = buffer;
+
+ if (*p == '+' || *p == '-')
+ p++;
+
+ while (isdigit (*p))
+ p++;
+
+ if (strncmp (p, decimal_point, decimal_point_len) == 0) {
+ *p = '.';
+ decimal_len = strlen (p + decimal_point_len);
+ memmove (p + 1, p + decimal_point_len, decimal_len);
+ p[1 + decimal_len] = 0;
+
+ /* Remove trailing zeros and decimal point if possible. */
+ for (p = p + decimal_len; *p == '0'; p--)
+ *p = 0;
+
+ if (*p == '.') {
+ *p = 0;
+ p--;
+ }
+ }
+
+ return p + 1 - buffer;
+}
+
+
+enum {
+ LENGTH_MODIFIER_LONG = 0x100
+};
+
+/* Here's a limited reimplementation of printf. The reason for doing
+ * this is primarily to special case handling of doubles. We want
+ * locale independent formatting of doubles and we want to trim
+ * trailing zeros. This is handled by dtostr() above, and the code
+ * below handles everything else by calling snprintf() to do the
+ * formatting. This functionality is only for internal use and we
+ * only implement the formats we actually use.
+ */
+
+cairo_status_t
+_cairo_output_stream_vprintf (cairo_output_stream_t *stream,
+ const char *fmt, va_list ap)
+{
+ char buffer[512];
+ char *p;
+ const char *f;
+ int length_modifier;
+
+ f = fmt;
+ p = buffer;
+ while (*f != '\0') {
+ if (p == buffer + sizeof (buffer)) {
+ _cairo_output_stream_write (stream, buffer, sizeof (buffer));
+ p = buffer;
+ }
+
+ if (*f != '%') {
+ *p++ = *f++;
+ continue;
+ }
+
+ f++;
+
+ _cairo_output_stream_write (stream, buffer, p - buffer);
+ p = buffer;
+
+ length_modifier = 0;
+ if (*f == 'l') {
+ length_modifier = LENGTH_MODIFIER_LONG;
+ f++;
+ }
+
+ switch (*f | length_modifier) {
+ case '%':
+ p[0] = *f;
+ p[1] = 0;
+ break;
+ case 'd':
+ snprintf (buffer, sizeof buffer, "%d", va_arg (ap, int));
+ break;
+ case 'd' | LENGTH_MODIFIER_LONG:
+ snprintf (buffer, sizeof buffer, "%ld", va_arg (ap, long int));
+ break;
+ case 'u':
+ snprintf (buffer, sizeof buffer, "%u", va_arg (ap, unsigned int));
+ break;
+ case 'u' | LENGTH_MODIFIER_LONG:
+ snprintf (buffer, sizeof buffer, "%lu", va_arg (ap, long unsigned int));
+ break;
+ case 'o':
+ snprintf (buffer, sizeof buffer, "%o", va_arg (ap, int));
+ break;
+ case 's':
+ snprintf (buffer, sizeof buffer, "%s", va_arg (ap, const char *));
+ break;
+ case 'f':
+ dtostr (buffer, sizeof buffer, va_arg (ap, double));
+ break;
+ default:
+ ASSERT_NOT_REACHED;
+ }
+ p = buffer + strlen (buffer);
+ f++;
+ }
+
+ _cairo_output_stream_write (stream, buffer, p - buffer);
+
+ return stream->status;
+}
+
+cairo_status_t
+_cairo_output_stream_printf (cairo_output_stream_t *stream,
+ const char *fmt, ...)
+{
+ va_list ap;
+ cairo_status_t status;
+
+ va_start (ap, fmt);
+
+ status = _cairo_output_stream_vprintf (stream, fmt, ap);
+
+ va_end (ap);
+
+ return status;
+}
+
+long
+_cairo_output_stream_get_position (cairo_output_stream_t *stream)
+{
+ return stream->position;
+}
+
+cairo_status_t
+_cairo_output_stream_get_status (cairo_output_stream_t *stream)
+{
+ return stream->status;
+}
+
+
+/* Maybe this should be a configure time option, so embedded targets
+ * don't have to pull in stdio. */
+
+static cairo_status_t
+stdio_write (void *closure, const unsigned char *data, unsigned int length)
+{
+ FILE *fp = closure;
+
+ if (fwrite (data, 1, length, fp) == length)
+ return CAIRO_STATUS_SUCCESS;
+
+ return CAIRO_STATUS_WRITE_ERROR;
+}
+
+cairo_output_stream_t *
+_cairo_output_stream_create_for_file (const char *filename)
+{
+ FILE *fp;
+ cairo_output_stream_t *stream;
+
+ fp = fopen (filename, "wb");
+ if (fp == NULL)
+ return NULL;
+
+ stream = _cairo_output_stream_create (stdio_write, fp);
+ if (stream == NULL)
+ fclose (fp);
+ stream->owns_closure_is_file = TRUE;
+
+ return stream;
+}
diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c
index 7c5772a82..670036cfd 100644
--- a/src/cairo-path-bounds.c
+++ b/src/cairo-path-bounds.c
@@ -151,7 +151,9 @@ _cairo_path_bounder_close_path (void *closure)
/* 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_path_fixed_bounds (cairo_path_fixed_t *path,
+ double *x1, double *y1,
+ double *x2, double *y2)
{
cairo_status_t status;
@@ -159,12 +161,12 @@ _cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, doub
_cairo_path_bounder_init (&bounder);
- status = _cairo_path_interpret (path, CAIRO_DIRECTION_FORWARD,
- _cairo_path_bounder_move_to,
- _cairo_path_bounder_line_to,
- _cairo_path_bounder_curve_to,
- _cairo_path_bounder_close_path,
- &bounder);
+ status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
+ _cairo_path_bounder_move_to,
+ _cairo_path_bounder_line_to,
+ _cairo_path_bounder_curve_to,
+ _cairo_path_bounder_close_path,
+ &bounder);
if (status) {
*x1 = *y1 = *x2 = *y2 = 0.0;
_cairo_path_bounder_fini (&bounder);
diff --git a/src/cairo-path-data-private.h b/src/cairo-path-data-private.h
new file mode 100644
index 000000000..e47eaaef9
--- /dev/null
+++ b/src/cairo-path-data-private.h
@@ -0,0 +1,55 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@redhat.com>
+ */
+
+#ifndef CAIRO_PATH_DATA_PRIVATE_H
+#define CAIRO_PATH_DATA_PRIVATE_H
+
+#include "cairoint.h"
+
+extern cairo_path_t _cairo_path_nil;
+
+cairo_path_t *
+_cairo_path_data_create (cairo_path_fixed_t *path,
+ cairo_gstate_t *gstate);
+
+cairo_path_t *
+_cairo_path_data_create_flat (cairo_path_fixed_t *path,
+ cairo_gstate_t *gstate);
+
+cairo_status_t
+_cairo_path_data_append_to_context (cairo_path_t *path,
+ cairo_t *cr);
+
+#endif /* CAIRO_PATH_DATA_PRIVATE_H */
diff --git a/src/cairo-path-data.c b/src/cairo-path-data.c
new file mode 100644
index 000000000..95fc3bb26
--- /dev/null
+++ b/src/cairo-path-data.c
@@ -0,0 +1,422 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@redhat.com>
+ */
+
+#include "cairo-path-data-private.h"
+#include "cairo-path-fixed-private.h"
+#include "cairo-gstate-private.h"
+
+cairo_path_t
+_cairo_path_nil = { NULL, 0 };
+
+/* Closure for path interpretation. */
+typedef struct cairo_path_data_count {
+ int count;
+ double tolerance;
+ cairo_point_t current_point;
+} cpdc_t;
+
+static cairo_status_t
+_cpdc_move_to (void *closure, cairo_point_t *point)
+{
+ cpdc_t *cpdc = closure;
+
+ cpdc->count += 2;
+
+ cpdc->current_point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cpdc_line_to (void *closure, cairo_point_t *point)
+{
+ cpdc_t *cpdc = closure;
+
+ cpdc->count += 2;
+
+ cpdc->current_point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cpdc_curve_to (void *closure,
+ cairo_point_t *p1,
+ cairo_point_t *p2,
+ cairo_point_t *p3)
+{
+ cpdc_t *cpdc = closure;
+
+ cpdc->count += 4;
+
+ cpdc->current_point = *p3;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cpdc_curve_to_flatten (void *closure,
+ cairo_point_t *p1,
+ cairo_point_t *p2,
+ cairo_point_t *p3)
+{
+ cpdc_t *cpdc = closure;
+ cairo_status_t status;
+ cairo_spline_t spline;
+ int i;
+
+ cairo_point_t *p0 = &cpdc->current_point;
+
+ status = _cairo_spline_init (&spline, p0, p1, p2, p3);
+ if (status == CAIRO_INT_STATUS_DEGENERATE)
+ return CAIRO_STATUS_SUCCESS;
+
+ status = _cairo_spline_decompose (&spline, cpdc->tolerance);
+ if (status)
+ return status;
+
+ for (i=1; i < spline.num_points; i++)
+ _cpdc_line_to (cpdc, &spline.points[i]);
+
+ cpdc->current_point = *p3;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cpdc_close_path (void *closure)
+{
+ cpdc_t *cpdc = closure;
+
+ cpdc->count += 1;
+
+ cpdc->current_point.x = 0;
+ cpdc->current_point.y = 0;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static int
+_cairo_path_data_count (cairo_path_t *path,
+ cairo_path_fixed_t *path_fixed,
+ double tolerance,
+ cairo_bool_t flatten)
+{
+ cpdc_t cpdc;
+
+ cpdc.count = 0;
+ cpdc.tolerance = tolerance;
+ cpdc.current_point.x = 0;
+ cpdc.current_point.y = 0;
+
+ _cairo_path_fixed_interpret (path_fixed,
+ CAIRO_DIRECTION_FORWARD,
+ _cpdc_move_to,
+ _cpdc_line_to,
+ flatten ?
+ _cpdc_curve_to_flatten :
+ _cpdc_curve_to,
+ _cpdc_close_path,
+ &cpdc);
+
+ return cpdc.count;
+}
+
+/* Closure for path interpretation. */
+typedef struct cairo_path_data_populate {
+ cairo_path_data_t *data;
+ cairo_gstate_t *gstate;
+ cairo_point_t current_point;
+} cpdp_t;
+
+static cairo_status_t
+_cpdp_move_to (void *closure, cairo_point_t *point)
+{
+ cpdp_t *cpdp = closure;
+ cairo_path_data_t *data = cpdp->data;
+ double x, y;
+
+ x = _cairo_fixed_to_double (point->x);
+ y = _cairo_fixed_to_double (point->y);
+
+ _cairo_gstate_backend_to_user (cpdp->gstate, &x, &y);
+
+ data->header.type = CAIRO_PATH_MOVE_TO;
+ data->header.length = 2;
+
+ /* We index from 1 to leave room for data->header */
+ data[1].point.x = x;
+ data[1].point.y = y;
+
+ cpdp->data += data->header.length;
+
+ cpdp->current_point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cpdp_line_to (void *closure, cairo_point_t *point)
+{
+ cpdp_t *cpdp = closure;
+ cairo_path_data_t *data = cpdp->data;
+ double x, y;
+
+ x = _cairo_fixed_to_double (point->x);
+ y = _cairo_fixed_to_double (point->y);
+
+ _cairo_gstate_backend_to_user (cpdp->gstate, &x, &y);
+
+ data->header.type = CAIRO_PATH_LINE_TO;
+ data->header.length = 2;
+
+ /* We index from 1 to leave room for data->header */
+ data[1].point.x = x;
+ data[1].point.y = y;
+
+ cpdp->data += data->header.length;
+
+ cpdp->current_point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cpdp_curve_to (void *closure,
+ cairo_point_t *p1,
+ cairo_point_t *p2,
+ cairo_point_t *p3)
+{
+ cpdp_t *cpdp = closure;
+ cairo_path_data_t *data = cpdp->data;
+ double x1, y1;
+ double x2, y2;
+ double x3, y3;
+
+ x1 = _cairo_fixed_to_double (p1->x);
+ y1 = _cairo_fixed_to_double (p1->y);
+ _cairo_gstate_backend_to_user (cpdp->gstate, &x1, &y1);
+
+ x2 = _cairo_fixed_to_double (p2->x);
+ y2 = _cairo_fixed_to_double (p2->y);
+ _cairo_gstate_backend_to_user (cpdp->gstate, &x2, &y2);
+
+ x3 = _cairo_fixed_to_double (p3->x);
+ y3 = _cairo_fixed_to_double (p3->y);
+ _cairo_gstate_backend_to_user (cpdp->gstate, &x3, &y3);
+
+ data->header.type = CAIRO_PATH_CURVE_TO;
+ data->header.length = 4;
+
+ /* We index from 1 to leave room for data->header */
+ data[1].point.x = x1;
+ data[1].point.y = y1;
+
+ data[2].point.x = x2;
+ data[2].point.y = y2;
+
+ data[3].point.x = x3;
+ data[3].point.y = y3;
+
+ cpdp->data += data->header.length;
+
+ cpdp->current_point = *p3;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cpdp_curve_to_flatten (void *closure,
+ cairo_point_t *p1,
+ cairo_point_t *p2,
+ cairo_point_t *p3)
+{
+ cpdp_t *cpdp = closure;
+ cairo_status_t status;
+ cairo_spline_t spline;
+ int i;
+
+ cairo_point_t *p0 = &cpdp->current_point;
+
+ status = _cairo_spline_init (&spline, p0, p1, p2, p3);
+ if (status == CAIRO_INT_STATUS_DEGENERATE)
+ return CAIRO_STATUS_SUCCESS;
+
+ status = _cairo_spline_decompose (&spline, cpdp->gstate->tolerance);
+ if (status)
+ return status;
+
+ for (i=1; i < spline.num_points; i++)
+ _cpdp_line_to (cpdp, &spline.points[i]);
+
+ cpdp->current_point = *p3;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cpdp_close_path (void *closure)
+{
+ cpdp_t *cpdp = closure;
+ cairo_path_data_t *data = cpdp->data;
+
+ data->header.type = CAIRO_PATH_CLOSE_PATH;
+ data->header.length = 1;
+
+ cpdp->data += data->header.length;
+
+ cpdp->current_point.x = 0;
+ cpdp->current_point.y = 0;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_path_data_populate (cairo_path_t *path,
+ cairo_path_fixed_t *path_fixed,
+ cairo_gstate_t *gstate,
+ cairo_bool_t flatten)
+{
+ cpdp_t cpdp;
+
+ cpdp.data = path->data;
+ cpdp.gstate = gstate;
+ cpdp.current_point.x = 0;
+ cpdp.current_point.y = 0;
+
+ _cairo_path_fixed_interpret (path_fixed,
+ CAIRO_DIRECTION_FORWARD,
+ _cpdp_move_to,
+ _cpdp_line_to,
+ flatten ?
+ _cpdp_curve_to_flatten :
+ _cpdp_curve_to,
+ _cpdp_close_path,
+ &cpdp);
+
+ /* Sanity check the count */
+ assert (cpdp.data - path->data == path->num_data);
+}
+
+static cairo_path_t *
+_cairo_path_data_create_real (cairo_path_fixed_t *path_fixed,
+ cairo_gstate_t *gstate,
+ cairo_bool_t flatten)
+{
+ cairo_path_t *path;
+
+ path = malloc (sizeof (cairo_path_t));
+ if (path == NULL)
+ return &_cairo_path_nil;
+
+ path->num_data = _cairo_path_data_count (path, path_fixed,
+ gstate->tolerance, flatten);
+
+ path->data = malloc (path->num_data * sizeof (cairo_path_data_t));
+ if (path->data == NULL) {
+ free (path);
+ return &_cairo_path_nil;
+ }
+
+ _cairo_path_data_populate (path, path_fixed,
+ gstate, flatten);
+
+ return path;
+}
+
+void
+cairo_path_destroy (cairo_path_t *path)
+{
+ free (path->data);
+ path->num_data = 0;
+ free (path);
+}
+
+cairo_path_t *
+_cairo_path_data_create (cairo_path_fixed_t *path,
+ cairo_gstate_t *gstate)
+{
+ return _cairo_path_data_create_real (path, gstate, FALSE);
+}
+
+cairo_path_t *
+_cairo_path_data_create_flat (cairo_path_fixed_t *path,
+ cairo_gstate_t *gstate)
+{
+ return _cairo_path_data_create_real (path, gstate, TRUE);
+}
+
+cairo_status_t
+_cairo_path_data_append_to_context (cairo_path_t *path,
+ cairo_t *cr)
+{
+ int i;
+ cairo_path_data_t *p;
+
+ for (i=0; i < path->num_data; i += path->data[i].header.length) {
+ p = &path->data[i];
+ switch (p->header.type) {
+ case CAIRO_PATH_MOVE_TO:
+ cairo_move_to (cr,
+ p[1].point.x, p[1].point.y);
+ if (p->header.length != 2)
+ return CAIRO_STATUS_INVALID_PATH_DATA;
+ break;
+ case CAIRO_PATH_LINE_TO:
+ cairo_line_to (cr,
+ p[1].point.x, p[1].point.y);
+ if (p->header.length != 2)
+ return CAIRO_STATUS_INVALID_PATH_DATA;
+ break;
+ case CAIRO_PATH_CURVE_TO:
+ cairo_curve_to (cr,
+ p[1].point.x, p[1].point.y,
+ p[2].point.x, p[2].point.y,
+ p[3].point.x, p[3].point.y);
+ if (p->header.length != 4)
+ return CAIRO_STATUS_INVALID_PATH_DATA;
+ break;
+ case CAIRO_PATH_CLOSE_PATH:
+ cairo_close_path (cr);
+ if (p->header.length != 1)
+ return CAIRO_STATUS_INVALID_PATH_DATA;
+ break;
+ default:
+ return CAIRO_STATUS_INVALID_PATH_DATA;
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c
index dc79b6b96..c0015fc96 100644
--- a/src/cairo-path-fill.c
+++ b/src/cairo-path-fill.c
@@ -36,6 +36,8 @@
#include "cairoint.h"
+#include "cairo-gstate-private.h"
+
typedef struct cairo_filler {
cairo_gstate_t *gstate;
cairo_traps_t *traps;
@@ -171,20 +173,22 @@ _cairo_filler_close_path (void *closure)
}
cairo_status_t
-_cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
+_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
+ cairo_gstate_t *gstate,
+ cairo_traps_t *traps)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler_t filler;
_cairo_filler_init (&filler, gstate, traps);
- status = _cairo_path_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_filler_move_to,
- _cairo_filler_line_to,
- _cairo_filler_curve_to,
- _cairo_filler_close_path,
- &filler);
+ status = _cairo_path_fixed_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_filler_move_to,
+ _cairo_filler_line_to,
+ _cairo_filler_curve_to,
+ _cairo_filler_close_path,
+ &filler);
if (status)
goto BAIL;
diff --git a/src/cairo-path-fixed-private.h b/src/cairo-path-fixed-private.h
new file mode 100644
index 000000000..e8e0df194
--- /dev/null
+++ b/src/cairo-path-fixed-private.h
@@ -0,0 +1,74 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@redhat.com>
+ */
+
+#ifndef CAIRO_PATH_FIXED_PRIVATE_H
+#define CAIRO_PATH_FIXED_PRIVATE_H
+
+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_t; /* Don't want 32 bits if we can avoid it. */
+
+#define CAIRO_PATH_BUF_SIZE 64
+
+typedef struct _cairo_path_op_buf {
+ int num_ops;
+ cairo_path_op_t op[CAIRO_PATH_BUF_SIZE];
+
+ struct _cairo_path_op_buf *next, *prev;
+} cairo_path_op_buf_t;
+
+typedef struct _cairo_path_arg_buf {
+ int num_points;
+ cairo_point_t points[CAIRO_PATH_BUF_SIZE];
+
+ struct _cairo_path_arg_buf *next, *prev;
+} cairo_path_arg_buf_t;
+
+struct _cairo_path_fixed {
+ cairo_path_op_buf_t *op_buf_head;
+ cairo_path_op_buf_t *op_buf_tail;
+
+ cairo_path_arg_buf_t *arg_buf_head;
+ cairo_path_arg_buf_t *arg_buf_tail;
+
+ cairo_point_t last_move_point;
+ cairo_point_t current_point;
+ int has_current_point;
+};
+
+#endif /* CAIRO_PATH_FIXED_PRIVATE_H */
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 08b380902..b81d862b9 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -36,6 +36,8 @@
#include "cairoint.h"
+#include "cairo-gstate-private.h"
+
typedef struct cairo_stroker {
cairo_gstate_t *gstate;
cairo_traps_t *traps;
@@ -794,7 +796,9 @@ _cairo_stroker_close_path (void *closure)
}
cairo_status_t
-_cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
+_cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path,
+ cairo_gstate_t *gstate,
+ cairo_traps_t *traps)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_stroker_t stroker;
@@ -802,21 +806,21 @@ _cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_t
_cairo_stroker_init (&stroker, gstate, traps);
if (gstate->dash)
- status = _cairo_path_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_stroker_move_to,
- _cairo_stroker_line_to_dashed,
- _cairo_stroker_curve_to,
- _cairo_stroker_close_path,
- &stroker);
+ status = _cairo_path_fixed_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_stroker_move_to,
+ _cairo_stroker_line_to_dashed,
+ _cairo_stroker_curve_to,
+ _cairo_stroker_close_path,
+ &stroker);
else
- status = _cairo_path_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_stroker_move_to,
- _cairo_stroker_line_to,
- _cairo_stroker_curve_to,
- _cairo_stroker_close_path,
- &stroker);
+ status = _cairo_path_fixed_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_stroker_move_to,
+ _cairo_stroker_line_to,
+ _cairo_stroker_curve_to,
+ _cairo_stroker_close_path,
+ &stroker);
if (status)
goto BAIL;
diff --git a/src/cairo-path.c b/src/cairo-path.c
index 8314f601c..0940c4d1e 100644
--- a/src/cairo-path.c
+++ b/src/cairo-path.c
@@ -1,7 +1,8 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
- *
+ * Copyright © 2005 Red Hat, Inc.
+ *
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
@@ -37,48 +38,52 @@
#include <stdlib.h>
#include "cairoint.h"
+#include "cairo-path-fixed-private.h"
+
/* private functions */
static cairo_status_t
-_cairo_path_add (cairo_path_t *path, cairo_path_op_t op, cairo_point_t *points, int num_pts);
+_cairo_path_fixed_add (cairo_path_fixed_t *path,
+ cairo_path_op_t op,
+ cairo_point_t *points,
+ int num_points);
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);
+_cairo_path_fixed_add_op_buf (cairo_path_fixed_t *path,
+ cairo_path_op_buf_t *op_buf);
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);
+_cairo_path_fixed_add_arg_buf (cairo_path_fixed_t *path,
+ cairo_path_arg_buf_t *arg_buf);
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);
+_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op_buf);
static void
-_cairo_path_op_buf_add (cairo_path_op_buf_t *op_buf, cairo_path_op_t op);
+_cairo_path_op_buf_add_op (cairo_path_op_buf_t *op_buf,
+ cairo_path_op_t 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);
+_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg_buf);
static void
-_cairo_path_arg_buf_add (cairo_path_arg_buf_t *arg, cairo_point_t *points, int num_points);
+_cairo_path_arg_buf_add_points (cairo_path_arg_buf_t *arg_buf,
+ cairo_point_t *points,
+ int num_points);
void
-_cairo_path_init (cairo_path_t *path)
+_cairo_path_fixed_init (cairo_path_fixed_t *path)
{
- path->op_head = NULL;
- path->op_tail = NULL;
+ path->op_buf_head = NULL;
+ path->op_buf_tail = NULL;
- path->arg_head = NULL;
- path->arg_tail = NULL;
+ path->arg_buf_head = NULL;
+ path->arg_buf_tail = NULL;
path->current_point.x = 0;
path->current_point.y = 0;
@@ -87,72 +92,85 @@ _cairo_path_init (cairo_path_t *path)
}
cairo_status_t
-_cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other)
+_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
+ cairo_path_fixed_t *other)
{
- cairo_path_op_buf_t *op, *other_op;
- cairo_path_arg_buf_t *arg, *other_arg;
+ cairo_path_op_buf_t *op_buf, *other_op_buf;
+ cairo_path_arg_buf_t *arg_buf, *other_arg_buf;
- _cairo_path_init (path);
+ _cairo_path_fixed_init (path);
path->current_point = other->current_point;
path->has_current_point = other->has_current_point;
path->last_move_point = other->last_move_point;
- for (other_op = other->op_head; other_op; other_op = other_op->next) {
- op = _cairo_path_op_buf_create ();
- if (op == NULL) {
- _cairo_path_fini(path);
+ for (other_op_buf = other->op_buf_head;
+ other_op_buf;
+ other_op_buf = other_op_buf->next)
+ {
+ op_buf = _cairo_path_op_buf_create ();
+ if (op_buf == NULL) {
+ _cairo_path_fixed_fini (path);
return CAIRO_STATUS_NO_MEMORY;
}
- *op = *other_op;
- _cairo_path_add_op_buf (path, op);
+ memcpy (op_buf, other_op_buf, sizeof (cairo_path_op_buf_t));
+ _cairo_path_fixed_add_op_buf (path, op_buf);
}
- for (other_arg = other->arg_head; other_arg; other_arg = other_arg->next) {
- arg = _cairo_path_arg_buf_create ();
- if (arg == NULL) {
- _cairo_path_fini(path);
+ for (other_arg_buf = other->arg_buf_head;
+ other_arg_buf;
+ other_arg_buf = other_arg_buf->next)
+ {
+ arg_buf = _cairo_path_arg_buf_create ();
+ if (arg_buf == NULL) {
+ _cairo_path_fixed_fini (path);
return CAIRO_STATUS_NO_MEMORY;
}
- *arg = *other_arg;
- _cairo_path_add_arg_buf (path, arg);
+ memcpy (arg_buf, other_arg_buf, sizeof (cairo_path_arg_buf_t));
+ _cairo_path_fixed_add_arg_buf (path, arg_buf);
}
return CAIRO_STATUS_SUCCESS;
}
void
-_cairo_path_fini (cairo_path_t *path)
+_cairo_path_fixed_fini (cairo_path_fixed_t *path)
{
- cairo_path_op_buf_t *op;
- cairo_path_arg_buf_t *arg;
+ cairo_path_op_buf_t *op_buf;
+ cairo_path_arg_buf_t *arg_buf;
- while (path->op_head) {
- op = path->op_head;
- path->op_head = op->next;
- _cairo_path_op_buf_destroy (op);
+ while (path->op_buf_head) {
+ op_buf = path->op_buf_head;
+ path->op_buf_head = op_buf->next;
+ _cairo_path_op_buf_destroy (op_buf);
}
- path->op_tail = NULL;
+ path->op_buf_tail = NULL;
- while (path->arg_head) {
- arg = path->arg_head;
- path->arg_head = arg->next;
- _cairo_path_arg_buf_destroy (arg);
+ while (path->arg_buf_head) {
+ arg_buf = path->arg_buf_head;
+ path->arg_buf_head = arg_buf->next;
+ _cairo_path_arg_buf_destroy (arg_buf);
}
- path->arg_tail = NULL;
+ path->arg_buf_tail = NULL;
path->has_current_point = 0;
}
cairo_status_t
-_cairo_path_move_to (cairo_path_t *path, cairo_point_t *point)
+_cairo_path_fixed_move_to (cairo_path_fixed_t *path,
+ cairo_fixed_t x,
+ cairo_fixed_t y)
{
cairo_status_t status;
+ cairo_point_t point;
+
+ point.x = x;
+ point.y = y;
- status = _cairo_path_add (path, CAIRO_PATH_OP_MOVE_TO, point, 1);
+ status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1);
if (status)
return status;
- path->current_point = *point;
+ path->current_point = point;
path->has_current_point = 1;
path->last_move_point = path->current_point;
@@ -160,91 +178,115 @@ _cairo_path_move_to (cairo_path_t *path, cairo_point_t *point)
}
cairo_status_t
-_cairo_path_rel_move_to (cairo_path_t *path, cairo_distance_t *distance)
+_cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path,
+ cairo_fixed_t dx,
+ cairo_fixed_t dy)
{
- cairo_point_t point;
+ cairo_fixed_t x, y;
- point.x = path->current_point.x + distance->dx;
- point.y = path->current_point.y + distance->dy;
+ if (!path->has_current_point)
+ return CAIRO_STATUS_NO_CURRENT_POINT;
+
+ x = path->current_point.x + dx;
+ y = path->current_point.y + dy;
- return _cairo_path_move_to (path, &point);
+ return _cairo_path_fixed_move_to (path, x, y);
}
cairo_status_t
-_cairo_path_line_to (cairo_path_t *path, cairo_point_t *point)
+_cairo_path_fixed_line_to (cairo_path_fixed_t *path,
+ cairo_fixed_t x,
+ cairo_fixed_t y)
{
cairo_status_t status;
+ cairo_point_t point;
- status = _cairo_path_add (path, CAIRO_PATH_OP_LINE_TO, point, 1);
+ point.x = x;
+ point.y = y;
+
+ status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
if (status)
return status;
- path->current_point = *point;
+ path->current_point = point;
path->has_current_point = 1;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_path_rel_line_to (cairo_path_t *path, cairo_distance_t *distance)
+_cairo_path_fixed_rel_line_to (cairo_path_fixed_t *path,
+ cairo_fixed_t dx,
+ cairo_fixed_t dy)
{
- cairo_point_t point;
+ cairo_fixed_t x, y;
+
+ if (!path->has_current_point)
+ return CAIRO_STATUS_NO_CURRENT_POINT;
- point.x = path->current_point.x + distance->dx;
- point.y = path->current_point.y + distance->dy;
+ x = path->current_point.x + dx;
+ y = path->current_point.y + dy;
- return _cairo_path_line_to (path, &point);
+ return _cairo_path_fixed_line_to (path, x, y);
}
cairo_status_t
-_cairo_path_curve_to (cairo_path_t *path,
- cairo_point_t *p0,
- cairo_point_t *p1,
- cairo_point_t *p2)
+_cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
+ cairo_fixed_t x0, cairo_fixed_t y0,
+ cairo_fixed_t x1, cairo_fixed_t y1,
+ cairo_fixed_t x2, cairo_fixed_t y2)
{
cairo_status_t status;
cairo_point_t point[3];
- point[0] = *p0;
- point[1] = *p1;
- point[2] = *p2;
+ point[0].x = x0; point[0].y = y0;
+ point[1].x = x1; point[1].y = y1;
+ point[2].x = x2; point[2].y = y2;
- status = _cairo_path_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
+ status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
if (status)
return status;
- path->current_point = *p2;
+ path->current_point = point[2];
path->has_current_point = 1;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_path_rel_curve_to (cairo_path_t *path,
- cairo_distance_t *d0,
- cairo_distance_t *d1,
- cairo_distance_t *d2)
+_cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path,
+ cairo_fixed_t dx0, cairo_fixed_t dy0,
+ cairo_fixed_t dx1, cairo_fixed_t dy1,
+ cairo_fixed_t dx2, cairo_fixed_t dy2)
{
- cairo_point_t p0, p1, p2;
+ cairo_fixed_t x0, y0;
+ cairo_fixed_t x1, y1;
+ cairo_fixed_t x2, y2;
+
+ if (!path->has_current_point)
+ return CAIRO_STATUS_NO_CURRENT_POINT;
- p0.x = path->current_point.x + d0->dx;
- p0.y = path->current_point.y + d0->dy;
+ x0 = path->current_point.x + dx0;
+ y0 = path->current_point.y + dy0;
- p1.x = path->current_point.x + d1->dx;
- p1.y = path->current_point.y + d1->dy;
+ x1 = path->current_point.x + dx1;
+ y1 = path->current_point.y + dy1;
- p2.x = path->current_point.x + d2->dx;
- p2.y = path->current_point.y + d2->dy;
+ x2 = path->current_point.x + dx2;
+ y2 = path->current_point.y + dy2;
- return _cairo_path_curve_to (path, &p0, &p1, &p2);
+ return _cairo_path_fixed_curve_to (path,
+ x0, y0,
+ x1, y1,
+ x2, y2);
}
cairo_status_t
-_cairo_path_close_path (cairo_path_t *path)
+_cairo_path_fixed_close_path (cairo_path_fixed_t *path)
{
cairo_status_t status;
- status = _cairo_path_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
+ status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
if (status)
return status;
@@ -256,120 +298,113 @@ _cairo_path_close_path (cairo_path_t *path)
}
cairo_status_t
-_cairo_path_current_point (cairo_path_t *path, cairo_point_t *point)
+_cairo_path_fixed_get_current_point (cairo_path_fixed_t *path,
+ cairo_fixed_t *x,
+ cairo_fixed_t *y)
{
if (! path->has_current_point)
return CAIRO_STATUS_NO_CURRENT_POINT;
- *point = path->current_point;
+ *x = path->current_point.x;
+ *y = path->current_point.y;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_path_add (cairo_path_t *path, cairo_path_op_t op, cairo_point_t *points, int num_points)
+_cairo_path_fixed_add (cairo_path_fixed_t *path,
+ cairo_path_op_t op,
+ cairo_point_t *points,
+ int num_points)
{
- cairo_status_t status;
+ if (path->op_buf_tail == NULL ||
+ path->op_buf_tail->num_ops + 1 > CAIRO_PATH_BUF_SIZE)
+ {
+ cairo_path_op_buf_t *op_buf;
- 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);
+ op_buf = _cairo_path_op_buf_create ();
+ if (op_buf == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
- if (path->arg_tail == NULL || path->arg_tail->num_points + num_points > CAIRO_PATH_BUF_SZ) {
- status = _cairo_path_new_arg_buf (path);
- if (status)
- return status;
+ _cairo_path_fixed_add_op_buf (path, op_buf);
}
- _cairo_path_arg_buf_add (path->arg_tail, points, num_points);
-
- 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;
+ _cairo_path_op_buf_add_op (path->op_buf_tail, op);
- if (path->op_tail) {
- path->op_tail->next = op;
- } else {
- path->op_head = op;
- }
+ if (path->arg_buf_tail == NULL ||
+ path->arg_buf_tail->num_points + num_points > CAIRO_PATH_BUF_SIZE)
+ {
+ cairo_path_arg_buf_t *arg_buf;
- path->op_tail = op;
-}
+ arg_buf = _cairo_path_arg_buf_create ();
-static cairo_status_t
-_cairo_path_new_op_buf (cairo_path_t *path)
-{
- cairo_path_op_buf_t *op;
+ if (arg_buf == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
- op = _cairo_path_op_buf_create ();
- if (op == NULL)
- return CAIRO_STATUS_NO_MEMORY;
+ _cairo_path_fixed_add_arg_buf (path, arg_buf);
+ }
- _cairo_path_add_op_buf (path, op);
+ _cairo_path_arg_buf_add_points (path->arg_buf_tail, points, num_points);
return CAIRO_STATUS_SUCCESS;
}
static void
-_cairo_path_add_arg_buf (cairo_path_t *path, cairo_path_arg_buf_t *arg)
+_cairo_path_fixed_add_op_buf (cairo_path_fixed_t *path,
+ cairo_path_op_buf_t *op_buf)
{
- arg->next = NULL;
- arg->prev = path->arg_tail;
+ op_buf->next = NULL;
+ op_buf->prev = path->op_buf_tail;
- if (path->arg_tail) {
- path->arg_tail->next = arg;
+ if (path->op_buf_tail) {
+ path->op_buf_tail->next = op_buf;
} else {
- path->arg_head = arg;
+ path->op_buf_head = op_buf;
}
- path->arg_tail = arg;
+ path->op_buf_tail = op_buf;
}
-static cairo_status_t
-_cairo_path_new_arg_buf (cairo_path_t *path)
+static void
+_cairo_path_fixed_add_arg_buf (cairo_path_fixed_t *path,
+ cairo_path_arg_buf_t *arg_buf)
{
- cairo_path_arg_buf_t *arg;
-
- arg = _cairo_path_arg_buf_create ();
-
- if (arg == NULL)
- return CAIRO_STATUS_NO_MEMORY;
+ arg_buf->next = NULL;
+ arg_buf->prev = path->arg_buf_tail;
- _cairo_path_add_arg_buf (path, arg);
+ if (path->arg_buf_tail) {
+ path->arg_buf_tail->next = arg_buf;
+ } else {
+ path->arg_buf_head = arg_buf;
+ }
- return CAIRO_STATUS_SUCCESS;
+ path->arg_buf_tail = arg_buf;
}
static cairo_path_op_buf_t *
_cairo_path_op_buf_create (void)
{
- cairo_path_op_buf_t *op;
+ cairo_path_op_buf_t *op_buf;
- op = malloc (sizeof (cairo_path_op_buf_t));
+ op_buf = malloc (sizeof (cairo_path_op_buf_t));
- if (op) {
- op->num_ops = 0;
- op->next = NULL;
+ if (op_buf) {
+ op_buf->num_ops = 0;
+ op_buf->next = NULL;
}
- return op;
+ return op_buf;
}
static void
-_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op)
+_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op_buf)
{
- free (op);
+ free (op_buf);
}
static void
-_cairo_path_op_buf_add (cairo_path_op_buf_t *op_buf, cairo_path_op_t op)
+_cairo_path_op_buf_add_op (cairo_path_op_buf_t *op_buf,
+ cairo_path_op_t op)
{
op_buf->op[op_buf->num_ops++] = op;
}
@@ -377,31 +412,33 @@ _cairo_path_op_buf_add (cairo_path_op_buf_t *op_buf, cairo_path_op_t op)
static cairo_path_arg_buf_t *
_cairo_path_arg_buf_create (void)
{
- cairo_path_arg_buf_t *arg;
+ cairo_path_arg_buf_t *arg_buf;
- arg = malloc (sizeof (cairo_path_arg_buf_t));
+ arg_buf = malloc (sizeof (cairo_path_arg_buf_t));
- if (arg) {
- arg->num_points = 0;
- arg->next = NULL;
+ if (arg_buf) {
+ arg_buf->num_points = 0;
+ arg_buf->next = NULL;
}
- return arg;
+ return arg_buf;
}
static void
-_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg)
+_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg_buf)
{
- free (arg);
+ free (arg_buf);
}
static void
-_cairo_path_arg_buf_add (cairo_path_arg_buf_t *arg, cairo_point_t *points, int num_points)
+_cairo_path_arg_buf_add_points (cairo_path_arg_buf_t *arg_buf,
+ cairo_point_t *points,
+ int num_points)
{
int i;
for (i=0; i < num_points; i++) {
- arg->points[arg->num_points++] = points[i];
+ arg_buf->points[arg_buf->num_points++] = points[i];
}
}
@@ -416,29 +453,30 @@ static int const num_args[] =
};
cairo_status_t
-_cairo_path_interpret (cairo_path_t *path,
- cairo_direction_t dir,
- cairo_path_move_to_func_t *move_to,
- cairo_path_line_to_func_t *line_to,
- cairo_path_curve_to_func_t *curve_to,
- cairo_path_close_path_func_t *close_path,
- void *closure)
+_cairo_path_fixed_interpret (cairo_path_fixed_t *path,
+ cairo_direction_t dir,
+ cairo_path_fixed_move_to_func_t *move_to,
+ cairo_path_fixed_line_to_func_t *line_to,
+ cairo_path_fixed_curve_to_func_t *curve_to,
+ cairo_path_fixed_close_path_func_t *close_path,
+ void *closure)
{
cairo_status_t status;
int i, arg;
cairo_path_op_buf_t *op_buf;
cairo_path_op_t op;
- cairo_path_arg_buf_t *arg_buf = path->arg_head;
+ cairo_path_arg_buf_t *arg_buf = path->arg_buf_head;
int buf_i = 0;
cairo_point_t point[CAIRO_PATH_OP_MAX_ARGS];
- int step = (dir == CAIRO_DIRECTION_FORWARD) ? 1 : -1;
+ cairo_bool_t forward = (dir == CAIRO_DIRECTION_FORWARD);
+ int step = forward ? 1 : -1;
- for (op_buf = (dir == CAIRO_DIRECTION_FORWARD) ? path->op_head : path->op_tail;
+ for (op_buf = forward ? path->op_buf_head : path->op_buf_tail;
op_buf;
- op_buf = (dir == CAIRO_DIRECTION_FORWARD) ? op_buf->next : op_buf->prev)
+ op_buf = forward ? op_buf->next : op_buf->prev)
{
int start, stop;
- if (dir == CAIRO_DIRECTION_FORWARD) {
+ if (forward) {
start = 0;
stop = op_buf->num_ops;
} else {
@@ -449,7 +487,7 @@ _cairo_path_interpret (cairo_path_t *path,
for (i=start; i != stop; i += step) {
op = op_buf->op[i];
- if (dir == CAIRO_DIRECTION_REVERSE) {
+ if (! forward) {
if (buf_i == 0) {
arg_buf = arg_buf->prev;
buf_i = arg_buf->num_points;
@@ -466,7 +504,7 @@ _cairo_path_interpret (cairo_path_t *path,
}
}
- if (dir == CAIRO_DIRECTION_REVERSE) {
+ if (! forward) {
buf_i -= num_args[op];
}
@@ -492,4 +530,3 @@ _cairo_path_interpret (cairo_path_t *path,
return CAIRO_STATUS_SUCCESS;
}
-
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 283c36dbd..1746b6b2a 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 David Reveman
+ * Copyright © 2005 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
@@ -56,9 +57,8 @@ _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
pattern->ref_count = 1;
pattern->extend = CAIRO_EXTEND_DEFAULT;
pattern->filter = CAIRO_FILTER_DEFAULT;
- pattern->alpha = 1.0;
- _cairo_matrix_init (&pattern->matrix);
+ cairo_matrix_init_identity (&pattern->matrix);
}
static cairo_status_t
@@ -150,15 +150,10 @@ _cairo_pattern_fini (cairo_pattern_t *pattern)
void
_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
- double red,
- double green,
- double blue)
+ const cairo_color_t *color)
{
_cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SOLID);
-
- pattern->red = red;
- pattern->green = green;
- pattern->blue = blue;
+ pattern->color = *color;
}
void
@@ -209,7 +204,7 @@ _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
}
cairo_pattern_t *
-_cairo_pattern_create_solid (double red, double green, double blue)
+_cairo_pattern_create_solid (const cairo_color_t *color)
{
cairo_solid_pattern_t *pattern;
@@ -217,7 +212,7 @@ _cairo_pattern_create_solid (double red, double green, double blue)
if (pattern == NULL)
return NULL;
- _cairo_pattern_init_solid (pattern, red, green, blue);
+ _cairo_pattern_init_solid (pattern, color);
return &pattern->base;
}
@@ -296,11 +291,8 @@ cairo_pattern_destroy (cairo_pattern_t *pattern)
static cairo_status_t
_cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern,
- double offset,
- double red,
- double green,
- double blue,
- double alpha)
+ double offset,
+ cairo_color_t *color)
{
cairo_color_stop_t *stop;
@@ -316,22 +308,48 @@ _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern,
stop = &pattern->stops[pattern->n_stops - 1];
stop->offset = _cairo_fixed_from_double (offset);
-
- _cairo_color_init (&stop->color);
- _cairo_color_set_rgb (&stop->color, red, green, blue);
- _cairo_color_set_alpha (&stop->color, alpha);
+ stop->color = *color;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
- double offset,
- double red,
- double green,
- double blue,
- double alpha)
+cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern,
+ double offset,
+ double red,
+ double green,
+ double blue)
{
+ cairo_color_t color;
+
+ if (pattern->type != CAIRO_PATTERN_LINEAR &&
+ pattern->type != CAIRO_PATTERN_RADIAL)
+ {
+ /* XXX: CAIRO_STATUS_INVALID_PATTERN? */
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ _cairo_restrict_value (&offset, 0.0, 1.0);
+ _cairo_restrict_value (&red, 0.0, 1.0);
+ _cairo_restrict_value (&green, 0.0, 1.0);
+ _cairo_restrict_value (&blue, 0.0, 1.0);
+
+ _cairo_color_init_rgb (&color, red, green, blue);
+ return _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern,
+ offset,
+ &color);
+}
+
+cairo_status_t
+cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern,
+ double offset,
+ double red,
+ double green,
+ double blue,
+ double alpha)
+{
+ cairo_color_t color;
+
if (pattern->type != CAIRO_PATTERN_LINEAR &&
pattern->type != CAIRO_PATTERN_RADIAL)
{
@@ -345,22 +363,27 @@ cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
_cairo_restrict_value (&blue, 0.0, 1.0);
_cairo_restrict_value (&alpha, 0.0, 1.0);
+ _cairo_color_init_rgba (&color, red, green, blue, alpha);
return _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern,
offset,
- red, green, blue,
- alpha);
+ &color);
}
cairo_status_t
-cairo_pattern_set_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
+cairo_pattern_set_matrix (cairo_pattern_t *pattern,
+ const cairo_matrix_t *matrix)
{
- return cairo_matrix_copy (&pattern->matrix, matrix);
+ pattern->matrix = *matrix;
+
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
{
- return cairo_matrix_copy (matrix, &pattern->matrix);
+ *matrix = pattern->matrix;
+
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
@@ -391,35 +414,9 @@ cairo_pattern_get_extend (cairo_pattern_t *pattern)
return pattern->extend;
}
-cairo_status_t
-_cairo_pattern_get_rgb (cairo_pattern_t *pattern,
- double *red,
- double *green,
- double *blue)
-{
-
- if (pattern->type == CAIRO_PATTERN_SOLID)
- {
- cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
-
- *red = solid->red;
- *green = solid->green;
- *blue = solid->blue;
- } else
- *red = *green = *blue = 1.0;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha)
-{
- pattern->alpha = alpha;
-}
-
void
-_cairo_pattern_transform (cairo_pattern_t *pattern,
- cairo_matrix_t *ctm_inverse)
+_cairo_pattern_transform (cairo_pattern_t *pattern,
+ const cairo_matrix_t *ctm_inverse)
{
cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix);
}
@@ -506,8 +503,7 @@ _cairo_pattern_shader_init (cairo_gradient_pattern_t *pattern,
op->stops[i].color_char[0] = pattern->stops[i].color.red * 0xff;
op->stops[i].color_char[1] = pattern->stops[i].color.green * 0xff;
op->stops[i].color_char[2] = pattern->stops[i].color.blue * 0xff;
- op->stops[i].color_char[3] = pattern->stops[i].color.alpha *
- pattern->base.alpha * 0xff;
+ op->stops[i].color_char[3] = pattern->stops[i].color.alpha * 0xff;
op->stops[i].offset = pattern->stops[i].offset;
op->stops[i].id = i;
}
@@ -516,6 +512,13 @@ _cairo_pattern_shader_init (cairo_gradient_pattern_t *pattern,
qsort (op->stops, pattern->n_stops, sizeof (cairo_shader_color_stop_t),
_cairo_shader_color_stop_compare);
+ /* this scale value is used only when computing gradient values
+ * before the defined range, in which case stop 0 is used for both
+ * ends of the interpolation, making the value of 'scale' not
+ * actually matter, except that valgrind notices we're using
+ * an undefined value.
+ */
+ op->stops[0].scale = 0;
for (i = 0; i < pattern->n_stops - 1; i++)
{
op->stops[i + 1].scale = op->stops[i + 1].offset - op->stops[i].offset;
@@ -666,8 +669,8 @@ _cairo_image_data_set_linear (cairo_linear_pattern_t *pattern,
point1.x = pattern->point1.x;
point1.y = pattern->point1.y;
- cairo_matrix_get_affine (&pattern->base.base.matrix,
- &a, &b, &c, &d, &tx, &ty);
+ _cairo_matrix_get_affine (&pattern->base.base.matrix,
+ &a, &b, &c, &d, &tx, &ty);
dx = point1.x - point0.x;
dy = point1.y - point0.y;
@@ -721,8 +724,8 @@ _cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern,
point1.x = pattern->point1.x;
point1.y = pattern->point1.y;
- cairo_matrix_get_affine (&pattern->base.base.matrix,
- &a, &b, &c, &d, &tx, &ty);
+ _cairo_matrix_get_affine (&pattern->base.base.matrix,
+ &a, &b, &c, &d, &tx, &ty);
dx = point1.x - point0.x;
dy = point1.y - point0.y;
@@ -795,8 +798,8 @@ _cairo_image_data_set_radial (cairo_radial_pattern_t *pattern,
r1_2 = c0_c1 = 0.0; /* shut up compiler */
}
- cairo_matrix_get_affine (&pattern->base.base.matrix,
- &a, &b, &c, &d, &tx, &ty);
+ _cairo_matrix_get_affine (&pattern->base.base.matrix,
+ &a, &b, &c, &d, &tx, &ty);
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
@@ -889,9 +892,9 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
cairo_surface_attributes_t *attr)
{
cairo_image_surface_t *image;
- cairo_status_t status;
- uint32_t *data;
- cairo_bool_t repeat = FALSE;
+ cairo_status_t status;
+ uint32_t *data;
+ cairo_bool_t repeat = FALSE;
if (pattern->base.type == CAIRO_PATTERN_LINEAR) {
cairo_bool_t is_horizontal;
@@ -935,7 +938,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
}
image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data ((char *) data,
+ cairo_image_surface_create_for_data ((unsigned char *) data,
CAIRO_FORMAT_ARGB32,
width, height,
width * 4);
@@ -953,10 +956,11 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
attr->x_offset = -x;
attr->y_offset = -y;
- cairo_matrix_set_identity (&attr->matrix);
+ cairo_matrix_init_identity (&attr->matrix);
attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
attr->filter = CAIRO_FILTER_NEAREST;
attr->acquired = FALSE;
+ attr->clip_saved = FALSE;
return status;
}
@@ -971,53 +975,47 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern,
cairo_surface_t **out,
cairo_surface_attributes_t *attribs)
{
- cairo_color_t color;
-
- _cairo_color_init (&color);
- _cairo_color_set_rgb (&color, pattern->red, pattern->green, pattern->blue);
- _cairo_color_set_alpha (&color, pattern->base.alpha);
-
*out = _cairo_surface_create_similar_solid (dst,
CAIRO_FORMAT_ARGB32,
1, 1,
- &color);
+ &pattern->color);
if (*out == NULL)
return CAIRO_STATUS_NO_MEMORY;
attribs->x_offset = attribs->y_offset = 0;
- cairo_matrix_set_identity (&attribs->matrix);
+ cairo_matrix_init_identity (&attribs->matrix);
attribs->extend = CAIRO_EXTEND_REPEAT;
attribs->filter = CAIRO_FILTER_NEAREST;
attribs->acquired = FALSE;
+ attribs->clip_saved = FALSE;
return CAIRO_STATUS_SUCCESS;
}
/**
- * _cairo_pattern_is_opaque
+ * _cairo_pattern_is_opaque_solid
*
- * Convenience function to determine whether a pattern has an opaque
- * alpha value. This is done by testing whether the pattern's alpha
- * value when converted to a byte is 255, so if a backend actually
- * supported deep alpha channels this function might not do the right
- * thing.
+ * Convenience function to determine whether a pattern is an opaque
+ * (alpha==1.0) solid color pattern. This is done by testing whether
+ * the pattern's alpha value when converted to a byte is 255, so if a
+ * backend actually supported deep alpha channels this function might
+ * not do the right thing.
*
- * Note that for a gradient or surface pattern, the overall resulting
- * alpha for the pattern can be non-opaque even this function returns
- * %TRUE, since the resulting alpha is the multiplication of the
- * alpha of the gradient or surface with the pattern's alpha. In
- * the future, alpha will be moved from the base pattern to the
- * solid pattern subtype, at which point this function should
- * probably be renamed to _cairo_pattern_is_opaque_solid()
- *
- * Return value: %TRUE if the pattern is opaque
+ * Return value: %TRUE if the pattern is an opaque, solid color.
**/
cairo_bool_t
-_cairo_pattern_is_opaque (cairo_pattern_t *pattern)
+_cairo_pattern_is_opaque_solid (cairo_pattern_t *pattern)
{
- return (pattern->alpha >= ((double)0xff00 / (double)0xffff));
+ cairo_solid_pattern_t *solid;
+
+ if (pattern->type != CAIRO_PATTERN_SOLID)
+ return FALSE;
+
+ solid = (cairo_solid_pattern_t *) pattern;
+
+ return (solid->color.alpha >= ((double)0xff00 / (double)0xffff));
}
static cairo_int_status_t
@@ -1031,84 +1029,54 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern,
cairo_surface_attributes_t *attr)
{
cairo_int_status_t status;
+ int tx, ty;
attr->acquired = FALSE;
-
- /* handle pattern opacity */
- if (!_cairo_pattern_is_opaque (&pattern->base))
+ attr->clip_saved = FALSE;
+
+ if (_cairo_surface_is_image (dst))
{
- cairo_surface_pattern_t tmp;
- cairo_color_t color;
-
- _cairo_color_init (&color);
- _cairo_color_set_alpha (&color, pattern->base.alpha);
-
- *out = _cairo_surface_create_similar_solid (dst,
- CAIRO_FORMAT_ARGB32,
- width, height,
- &color);
- if (*out == NULL)
- return CAIRO_STATUS_NO_MEMORY;
+ cairo_image_surface_t *image;
+
+ status = _cairo_surface_begin_reset_clip (pattern->surface);
+ if (!CAIRO_OK (status))
+ return status;
- status = _cairo_pattern_init_copy (&tmp.base, &pattern->base);
- if (CAIRO_OK (status))
- {
- tmp.base.alpha = 1.0;
- status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- &tmp.base,
- NULL,
- *out,
- x, y, 0, 0, 0, 0,
- width, height);
+ status = _cairo_surface_acquire_source_image (pattern->surface,
+ &image,
+ &attr->extra);
+ if (!CAIRO_OK (status))
+ return status;
- _cairo_pattern_fini (&tmp.base);
- }
+ _cairo_surface_end (pattern->surface);
- if (status) {
- cairo_surface_destroy (*out);
- return status;
- }
-
- attr->x_offset = -x;
- attr->y_offset = -y;
- attr->extend = CAIRO_EXTEND_NONE;
- attr->filter = CAIRO_FILTER_NEAREST;
-
- cairo_matrix_set_identity (&attr->matrix);
+ *out = &image->base;
+ attr->acquired = TRUE;
}
else
{
- int tx, ty;
-
- if (_cairo_surface_is_image (dst))
- {
- cairo_image_surface_t *image;
-
- status = _cairo_surface_acquire_source_image (pattern->surface,
- &image,
- &attr->extra);
- if (CAIRO_OK (status))
- *out = &image->base;
+ status = _cairo_surface_begin_reset_clip (pattern->surface);
+ if (!CAIRO_OK (status))
+ return status;
- attr->acquired = TRUE;
- }
- else
- status = _cairo_surface_clone_similar (dst, pattern->surface, out);
-
- attr->extend = pattern->base.extend;
- attr->filter = pattern->base.filter;
- if (_cairo_matrix_is_integer_translation (&pattern->base.matrix,
- &tx, &ty))
- {
- cairo_matrix_set_identity (&attr->matrix);
- attr->x_offset = tx;
- attr->y_offset = ty;
- }
- else
- {
- attr->matrix = pattern->base.matrix;
- attr->x_offset = attr->y_offset = 0;
- }
+ status = _cairo_surface_clone_similar (dst, pattern->surface, out);
+ _cairo_surface_end (pattern->surface);
+ }
+
+ attr->extend = pattern->base.extend;
+ attr->filter = pattern->base.filter;
+ if (_cairo_matrix_is_integer_translation (&pattern->base.matrix,
+ &tx, &ty))
+ {
+ cairo_matrix_init_identity (&attr->matrix);
+ attr->x_offset = tx;
+ attr->y_offset = ty;
+ attr->filter = CAIRO_FILTER_NEAREST;
+ }
+ else
+ {
+ attr->matrix = pattern->base.matrix;
+ attr->x_offset = attr->y_offset = 0;
}
return status;
@@ -1141,14 +1109,16 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
cairo_surface_t **surface_out,
cairo_surface_attributes_t *attributes)
{
+ cairo_status_t status;
+
switch (pattern->type) {
case CAIRO_PATTERN_SOLID: {
cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) pattern;
- return _cairo_pattern_acquire_surface_for_solid (src, dst,
- x, y, width, height,
- surface_out,
- attributes);
+ status = _cairo_pattern_acquire_surface_for_solid (src, dst,
+ x, y, width, height,
+ surface_out,
+ attributes);
} break;
case CAIRO_PATTERN_LINEAR:
case CAIRO_PATTERN_RADIAL: {
@@ -1157,47 +1127,53 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
/* fast path for gradients with less than 2 color stops */
if (src->n_stops < 2)
{
+ const cairo_color_t *color;
cairo_solid_pattern_t solid;
if (src->n_stops)
- {
- _cairo_pattern_init_solid (&solid,
- src->stops->color.red,
- src->stops->color.green,
- src->stops->color.blue);
- _cairo_pattern_set_alpha (&solid.base,
- src->stops->color.alpha);
- }
+ color = &src->stops->color;
else
- {
- _cairo_pattern_init_solid (&solid, 0.0, 0.0, 0.0);
- _cairo_pattern_set_alpha (&solid.base, 0.0);
- }
+ color = CAIRO_COLOR_TRANSPARENT;
- return _cairo_pattern_acquire_surface_for_solid (&solid, dst,
- x, y,
- width, height,
- surface_out,
- attributes);
+ _cairo_pattern_init_solid (&solid, color);
+
+ status = _cairo_pattern_acquire_surface_for_solid (&solid, dst,
+ x, y,
+ width, height,
+ surface_out,
+ attributes);
}
else
- return _cairo_pattern_acquire_surface_for_gradient (src, dst,
- x, y,
- width, height,
- surface_out,
- attributes);
+ status = _cairo_pattern_acquire_surface_for_gradient (src, dst,
+ x, y,
+ width, height,
+ surface_out,
+ attributes);
} break;
case CAIRO_PATTERN_SURFACE: {
cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) pattern;
- return _cairo_pattern_acquire_surface_for_surface (src, dst,
- x, y, width, height,
- surface_out,
- attributes);
+ status = _cairo_pattern_acquire_surface_for_surface (src, dst,
+ x, y, width, height,
+ surface_out,
+ attributes);
} break;
+ default:
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+
+ if (CAIRO_OK (status) && (*surface_out)->clip_region) {
+ status = _cairo_surface_begin_reset_clip (*surface_out);
+ if (!CAIRO_OK (status)) {
+ _cairo_pattern_release_surface (dst, *surface_out, attributes);
+ return status;
+ }
+
+ attributes->clip_saved = TRUE;
}
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return status;
}
/**
@@ -1213,11 +1189,15 @@ _cairo_pattern_release_surface (cairo_surface_t *dst,
cairo_surface_t *surface,
cairo_surface_attributes_t *attributes)
{
+ if (attributes->clip_saved)
+ _cairo_surface_end (surface);
+
if (attributes->acquired)
+ {
_cairo_surface_release_source_image (dst,
(cairo_image_surface_t *) surface,
attributes->extra);
- else
+ } else
cairo_surface_destroy (surface);
}
@@ -1237,71 +1217,44 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src,
cairo_surface_attributes_t *mask_attributes)
{
cairo_int_status_t status;
-
cairo_pattern_union_t tmp;
- cairo_bool_t src_opaque, mask_opaque;
- double src_alpha, mask_alpha;
- src_opaque = _cairo_pattern_is_opaque (src);
- mask_opaque = !mask || _cairo_pattern_is_opaque (mask);
-
- /* For surface patterns, we move any translucency from src->alpha
- * to mask->alpha so we can use the source unchanged. Otherwise we
- * move the translucency from mask->alpha to src->alpha so that
- * we can drop the mask if possible.
- */
- if (src->type == CAIRO_PATTERN_SURFACE)
- {
- if (mask) {
- mask_opaque = mask_opaque && src_opaque;
- mask_alpha = mask->alpha * src->alpha;
- } else {
- mask_opaque = src_opaque;
- mask_alpha = src->alpha;
- }
-
- src_alpha = 1.0;
- src_opaque = TRUE;
- }
- else
- {
- if (mask)
- {
- src_opaque = mask_opaque && src_opaque;
- src_alpha = mask->alpha * src->alpha;
- /* FIXME: This needs changing when we support RENDER
- * style 4-channel masks.
- */
- if (mask->type == CAIRO_PATTERN_SOLID)
- mask = NULL;
- } else
- src_alpha = src->alpha;
-
- mask_alpha = 1.0;
- mask_opaque = TRUE;
+ /* If src and mask are both solid, then the mask alpha can be
+ * combined into src and mask can be ignored. */
+
+ /* XXX: This optimization assumes that there is no color
+ * information in mask, so this will need to change when we
+ * support RENDER-style 4-channel masks. */
+ if (src->type == CAIRO_PATTERN_SOLID &&
+ mask && mask->type == CAIRO_PATTERN_SOLID)
+ {
+ cairo_color_t combined;
+ cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
+ cairo_solid_pattern_t *mask_solid = (cairo_solid_pattern_t *) mask;
+
+ combined = src_solid->color;
+ _cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
+
+ _cairo_pattern_init_solid (&tmp.solid, &combined);
+
+ mask = NULL;
+ } else {
+ _cairo_pattern_init_copy (&tmp.base, src);
}
- _cairo_pattern_init_copy (&tmp.base, src);
- _cairo_pattern_set_alpha (&tmp.base, src_alpha);
-
status = _cairo_pattern_acquire_surface (&tmp.base, dst,
src_x, src_y,
width, height,
src_out, src_attributes);
-
+
_cairo_pattern_fini (&tmp.base);
if (status)
return status;
- if (mask || !mask_opaque)
+ if (mask)
{
- if (mask)
- _cairo_pattern_init_copy (&tmp.base, mask);
- else
- _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0);
-
- _cairo_pattern_set_alpha (&tmp.base, mask_alpha);
+ _cairo_pattern_init_copy (&tmp.base, mask);
status = _cairo_pattern_acquire_surface (&tmp.base, dst,
mask_x, mask_y,
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index fee918355..228c2c89a 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -153,13 +153,15 @@ struct cairo_pdf_stream {
};
struct cairo_pdf_document {
- FILE *file;
+ cairo_output_stream_t *output_stream;
unsigned long refcount;
+ cairo_surface_t *owner;
+ cairo_bool_t finished;
- double width_inches;
- double height_inches;
- double x_ppi;
- double y_ppi;
+ double width;
+ double height;
+ double x_dpi;
+ double y_dpi;
unsigned int next_available_id;
unsigned int pages_id;
@@ -175,8 +177,8 @@ struct cairo_pdf_document {
struct cairo_pdf_surface {
cairo_surface_t base;
- double width_inches;
- double height_inches;
+ double width;
+ double height;
cairo_pdf_document_t *document;
cairo_pdf_stream_t *current_stream;
@@ -188,17 +190,19 @@ struct cairo_pdf_surface {
cairo_array_t fonts;
};
+#define DEFAULT_DPI 300
static cairo_pdf_document_t *
-_cairo_pdf_document_create (FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch);
+_cairo_pdf_document_create (cairo_output_stream_t *stream,
+ double width,
+ double height);
static void
_cairo_pdf_document_destroy (cairo_pdf_document_t *document);
+static cairo_status_t
+_cairo_pdf_document_finish (cairo_pdf_document_t *document);
+
static void
_cairo_pdf_document_reference (cairo_pdf_document_t *document);
@@ -214,11 +218,12 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface);
static cairo_pdf_stream_t *
_cairo_pdf_document_open_stream (cairo_pdf_document_t *document,
- const char *extra_entries);
+ const char *fmt,
+ ...);
static cairo_surface_t *
_cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document,
- double width_inches,
- double height_inches);
+ double width,
+ double height);
static void
_cairo_pdf_surface_add_stream (cairo_pdf_surface_t *surface,
cairo_pdf_stream_t *stream);
@@ -319,8 +324,6 @@ cairo_pdf_ft_font_create (cairo_pdf_document_t *document,
if (_cairo_array_grow_by (&font->output, 4096) != CAIRO_STATUS_SUCCESS)
goto fail1;
- font->base.unscaled_font = unscaled_font;
- _cairo_unscaled_font_reference (unscaled_font);
font->glyphs = calloc (face->num_glyphs + 1, sizeof (ft_subset_glyph_t));
if (font->glyphs == NULL)
goto fail2;
@@ -457,7 +460,7 @@ static int
cairo_pdf_ft_font_write_generic_table (cairo_pdf_ft_font_t *font,
unsigned long tag)
{
- char *buffer;
+ unsigned char *buffer;
unsigned long size;
size = 0;
@@ -475,7 +478,7 @@ cairo_pdf_ft_font_write_glyf_table (cairo_pdf_ft_font_t *font,
unsigned long start_offset, index, size;
TT_Header *header;
unsigned long begin, end;
- char *buffer;
+ unsigned char *buffer;
int i;
union {
unsigned char *bytes;
@@ -814,7 +817,7 @@ _cairo_pdf_document_new_object (cairo_pdf_document_t *document)
{
cairo_pdf_object_t object;
- object.offset = ftell (document->file);
+ object.offset = _cairo_output_stream_get_position (document->output_stream);
if (_cairo_array_append (&document->objects, &object, 1) == NULL)
return 0;
@@ -828,7 +831,7 @@ _cairo_pdf_document_update_object (cairo_pdf_document_t *document,
cairo_pdf_object_t *object;
object = _cairo_array_index (&document->objects, id - 1);
- object->offset = ftell (document->file);
+ object->offset = _cairo_output_stream_get_position (document->output_stream);
}
static void
@@ -899,37 +902,70 @@ _cairo_pdf_surface_add_font (cairo_pdf_surface_t *surface, unsigned int id)
_cairo_array_append (&surface->fonts, &resource, 1);
}
-cairo_surface_t *
-cairo_pdf_surface_create (FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch)
+static cairo_surface_t *
+_cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *stream,
+ double width,
+ double height)
{
cairo_pdf_document_t *document;
cairo_surface_t *surface;
- document = _cairo_pdf_document_create (file,
- width_inches,
- height_inches,
- x_pixels_per_inch,
- y_pixels_per_inch);
+ document = _cairo_pdf_document_create (stream, width, height);
if (document == NULL)
return NULL;
- surface = _cairo_pdf_surface_create_for_document (document,
- width_inches,
- height_inches);
+ surface = _cairo_pdf_surface_create_for_document (document, width, height);
+ document->owner = surface;
_cairo_pdf_document_destroy (document);
return surface;
}
+cairo_surface_t *
+cairo_pdf_surface_create_for_stream (cairo_write_func_t write,
+ void *closure,
+ double width,
+ double height)
+{
+ cairo_output_stream_t *stream;
+
+ stream = _cairo_output_stream_create (write, closure);
+ if (stream == NULL)
+ return NULL;
+
+ return _cairo_pdf_surface_create_for_stream_internal (stream, width, height);
+}
+
+cairo_surface_t *
+cairo_pdf_surface_create (const char *filename,
+ double width,
+ double height)
+{
+ cairo_output_stream_t *stream;
+
+ stream = _cairo_output_stream_create_for_file (filename);
+ if (stream == NULL)
+ return NULL;
+
+ return _cairo_pdf_surface_create_for_stream_internal (stream, width, height);
+}
+
+void
+cairo_pdf_surface_set_dpi (cairo_surface_t *surface,
+ double x_dpi,
+ double y_dpi)
+{
+ cairo_pdf_surface_t *pdf_surface = (cairo_pdf_surface_t *) surface;
+
+ pdf_surface->document->x_dpi = x_dpi;
+ pdf_surface->document->y_dpi = y_dpi;
+}
+
static cairo_surface_t *
_cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document,
- double width_inches,
- double height_inches)
+ double width,
+ double height)
{
cairo_pdf_surface_t *surface;
@@ -939,8 +975,8 @@ _cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document,
_cairo_surface_init (&surface->base, &cairo_pdf_surface_backend);
- surface->width_inches = width_inches;
- surface->height_inches = height_inches;
+ surface->width = width;
+ surface->height = height;
_cairo_pdf_document_reference (document);
surface->document = document;
@@ -987,10 +1023,12 @@ _cairo_pdf_surface_create_similar (void *abstract_src,
static cairo_pdf_stream_t *
_cairo_pdf_document_open_stream (cairo_pdf_document_t *document,
- const char *extra_entries)
+ const char *fmt,
+ ...)
{
- FILE *file = document->file;
+ cairo_output_stream_t *output_stream = document->output_stream;
cairo_pdf_stream_t *stream;
+ va_list ap;
stream = malloc (sizeof (cairo_pdf_stream_t));
if (stream == NULL) {
@@ -1000,17 +1038,23 @@ _cairo_pdf_document_open_stream (cairo_pdf_document_t *document,
stream->id = _cairo_pdf_document_new_object (document);
stream->length_id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Length %d 0 R\r\n"
- "%s"
- ">>\r\n"
- "stream\r\n",
- stream->id,
- stream->length_id,
- extra_entries);
+ _cairo_output_stream_printf (output_stream,
+ "%d 0 obj\r\n"
+ "<< /Length %d 0 R\r\n",
+ stream->id,
+ stream->length_id);
+
+ if (fmt != NULL) {
+ va_start (ap, fmt);
+ _cairo_output_stream_vprintf (output_stream, fmt, ap);
+ va_end (ap);
+ }
- stream->start_offset = ftell (file);
+ _cairo_output_stream_printf (output_stream,
+ ">>\r\n"
+ "stream\r\n");
+
+ stream->start_offset = _cairo_output_stream_get_position (output_stream);
document->current_stream = stream;
@@ -1020,7 +1064,7 @@ _cairo_pdf_document_open_stream (cairo_pdf_document_t *document,
static void
_cairo_pdf_document_close_stream (cairo_pdf_document_t *document)
{
- FILE *file = document->file;
+ cairo_output_stream_t *output_stream = document->output_stream;
long length;
cairo_pdf_stream_t *stream;
@@ -1028,44 +1072,41 @@ _cairo_pdf_document_close_stream (cairo_pdf_document_t *document)
if (stream == NULL)
return;
- length = ftell(file) - stream->start_offset;
- fprintf (file,
- "\r\n"
- "endstream\r\n"
- "endobj\r\n");
+ length = _cairo_output_stream_get_position (output_stream) -
+ stream->start_offset;
+ _cairo_output_stream_printf (output_stream,
+ "endstream\r\n"
+ "endobj\r\n");
_cairo_pdf_document_update_object (document, stream->length_id);
- fprintf (file,
- "%d 0 obj\r\n"
- " %ld\r\n"
- "endobj\r\n",
- stream->length_id,
- length);
+ _cairo_output_stream_printf (output_stream,
+ "%d 0 obj\r\n"
+ " %ld\r\n"
+ "endobj\r\n",
+ stream->length_id,
+ length);
document->current_stream = NULL;
}
-static void
-_cairo_pdf_surface_destroy (void *abstract_surface)
+static cairo_status_t
+_cairo_pdf_surface_finish (void *abstract_surface)
{
+ cairo_status_t status;
cairo_pdf_surface_t *surface = abstract_surface;
cairo_pdf_document_t *document = surface->document;
if (surface->current_stream == document->current_stream)
_cairo_pdf_document_close_stream (document);
- _cairo_pdf_document_destroy (document);
+ if (document->owner == &surface->base)
+ status = _cairo_pdf_document_finish (document);
+ else
+ status = CAIRO_STATUS_SUCCESS;
- free (surface);
-}
+ _cairo_pdf_document_destroy (document);
-/* XXX: We should re-work this interface to return both X/Y ppi values. */
-static double
-_cairo_pdf_surface_pixels_per_inch (void *abstract_surface)
-{
- cairo_pdf_surface_t *surface = abstract_surface;
-
- return surface->document->y_ppi;
+ return status;
}
static void
@@ -1073,71 +1114,29 @@ _cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface)
{
cairo_pdf_document_t *document = surface->document;
cairo_pdf_stream_t *stream;
- FILE *file = document->file;
- char extra[200];
+ cairo_output_stream_t *output = document->output_stream;
if (document->current_stream == NULL ||
document->current_stream != surface->current_stream) {
_cairo_pdf_document_close_stream (document);
- snprintf (extra, sizeof extra,
- " /Type /XObject\r\n"
- " /Subtype /Form\r\n"
- " /BBox [ 0 0 %f %f ]\r\n",
- surface->width_inches * document->x_ppi,
- surface->height_inches * document->y_ppi);
- stream = _cairo_pdf_document_open_stream (document, extra);
+ stream = _cairo_pdf_document_open_stream (document,
+ " /Type /XObject\r\n"
+ " /Subtype /Form\r\n"
+ " /BBox [ 0 0 %f %f ]\r\n",
+ surface->width,
+ surface->height);
+
_cairo_pdf_surface_add_stream (surface, stream);
/* If this is the first stream we open for this surface,
* output the cairo to PDF transformation matrix. */
if (_cairo_array_num_elements (&surface->streams) == 1)
- fprintf (file, "1 0 0 -1 0 %f cm\r\n",
- document->height_inches * document->y_ppi);
+ _cairo_output_stream_printf (output,
+ "1 0 0 -1 0 %f cm\r\n",
+ document->height);
}
}
-static cairo_status_t
-_cairo_pdf_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static void
-_cairo_pdf_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_pdf_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect,
- void **image_extra)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static void
-_cairo_pdf_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_pdf_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
static void *
compress_dup (const void *data, unsigned long data_size,
unsigned long *compressed_size)
@@ -1159,9 +1158,8 @@ static unsigned int
emit_image_data (cairo_pdf_document_t *document,
cairo_image_surface_t *image)
{
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
cairo_pdf_stream_t *stream;
- char entries[200];
char *rgb, *compressed;
int i, x, y;
unsigned long rgb_size, compressed_size;
@@ -1191,18 +1189,19 @@ emit_image_data (cairo_pdf_document_t *document,
_cairo_pdf_document_close_stream (document);
- snprintf (entries, sizeof entries,
- " /Type /XObject\r\n"
- " /Subtype /Image\r\n"
- " /Width %d\r\n"
- " /Height %d\r\n"
- " /ColorSpace /DeviceRGB\r\n"
- " /BitsPerComponent 8\r\n"
- " /Filter /FlateDecode\r\n",
- image->width, image->height);
-
- stream = _cairo_pdf_document_open_stream (document, entries);
- fwrite (compressed, 1, compressed_size, file);
+ stream = _cairo_pdf_document_open_stream (document,
+ " /Type /XObject\r\n"
+ " /Subtype /Image\r\n"
+ " /Width %d\r\n"
+ " /Height %d\r\n"
+ " /ColorSpace /DeviceRGB\r\n"
+ " /BitsPerComponent 8\r\n"
+ " /Filter /FlateDecode\r\n",
+ image->width, image->height);
+
+ _cairo_output_stream_write (output, compressed, compressed_size);
+ _cairo_output_stream_printf (output,
+ "\r\n");
_cairo_pdf_document_close_stream (document);
free (rgb);
@@ -1216,7 +1215,7 @@ _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst,
cairo_surface_pattern_t *pattern)
{
cairo_pdf_document_t *document = dst->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
unsigned id;
cairo_matrix_t i2u;
cairo_status_t status;
@@ -1239,17 +1238,17 @@ _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst,
_cairo_pdf_surface_ensure_stream (dst);
- cairo_matrix_copy (&i2u, &pattern->base.matrix);
+ i2u = pattern->base.matrix;
cairo_matrix_invert (&i2u);
cairo_matrix_translate (&i2u, 0, image->height);
cairo_matrix_scale (&i2u, image->width, -image->height);
- fprintf (file,
- "q %f %f %f %f %f %f cm /res%d Do Q\r\n",
- i2u.m[0][0], i2u.m[0][1],
- i2u.m[1][0], i2u.m[1][1],
- i2u.m[2][0], i2u.m[2][1],
- id);
+ _cairo_output_stream_printf (output,
+ "q %f %f %f %f %f %f cm /res%d Do Q\r\n",
+ i2u.xx, i2u.yx,
+ i2u.xy, i2u.yy,
+ i2u.x0, i2u.y0,
+ id);
bail:
_cairo_surface_release_source_image (src, image, image_extra);
@@ -1272,7 +1271,7 @@ _cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst,
cairo_surface_pattern_t *pattern)
{
cairo_pdf_document_t *document = dst->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
cairo_matrix_t i2u;
cairo_pdf_stream_t *stream;
int num_streams, i;
@@ -1282,30 +1281,28 @@ _cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst,
src = (cairo_pdf_surface_t *) pattern->surface;
- cairo_matrix_copy (&i2u, &src->base.matrix);
+ i2u = src->base.matrix;
cairo_matrix_invert (&i2u);
- cairo_matrix_scale (&i2u,
- 1.0 / (src->width_inches * document->x_ppi),
- 1.0 / (src->height_inches * document->y_ppi));
+ cairo_matrix_scale (&i2u, 1.0 / src->width, 1.0 / src->height);
- fprintf (file,
- "q %f %f %f %f %f %f cm",
- i2u.m[0][0], i2u.m[0][1],
- i2u.m[1][0], i2u.m[1][1],
- i2u.m[2][0], i2u.m[2][1]);
+ _cairo_output_stream_printf (output,
+ "q %f %f %f %f %f %f cm",
+ i2u.xx, i2u.yx,
+ i2u.xy, i2u.yy,
+ i2u.x0, i2u.y0);
num_streams = _cairo_array_num_elements (&src->streams);
for (i = 0; i < num_streams; i++) {
_cairo_array_copy_element (&src->streams, i, &stream);
- fprintf (file,
- " /res%d Do",
- stream->id);
+ _cairo_output_stream_printf (output,
+ " /res%d Do",
+ stream->id);
_cairo_pdf_surface_add_xobject (dst, stream->id);
}
- fprintf (file, " Q\r\n");
+ _cairo_output_stream_printf (output, " Q\r\n");
return CAIRO_STATUS_SUCCESS;
}
@@ -1348,20 +1345,20 @@ _cairo_pdf_surface_fill_rectangles (void *abstract_surface,
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
int i;
_cairo_pdf_surface_ensure_stream (surface);
- fprintf (file,
- "%f %f %f rg\r\n",
- color->red, color->green, color->blue);
+ _cairo_output_stream_printf (output,
+ "%f %f %f rg\r\n",
+ color->red, color->green, color->blue);
for (i = 0; i < num_rects; i++) {
- fprintf (file,
- "%d %d %d %d re f\r\n",
- rects[i].x, rects[i].y,
- rects[i].width, rects[i].height);
+ _cairo_output_stream_printf (output,
+ "%d %d %d %d re f\r\n",
+ rects[i].x, rects[i].y,
+ rects[i].width, rects[i].height);
}
return CAIRO_STATUS_SUCCESS;
@@ -1372,17 +1369,17 @@ emit_solid_pattern (cairo_pdf_surface_t *surface,
cairo_solid_pattern_t *pattern)
{
cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
unsigned int alpha;
- alpha = _cairo_pdf_surface_add_alpha (surface, pattern->base.alpha);
+ alpha = _cairo_pdf_surface_add_alpha (surface, pattern->color.alpha);
_cairo_pdf_surface_ensure_stream (surface);
- fprintf (file,
- "%f %f %f rg /a%d gs\r\n",
- pattern->red,
- pattern->green,
- pattern->blue,
- alpha);
+ _cairo_output_stream_printf (output,
+ "%f %f %f rg /a%d gs\r\n",
+ pattern->color.red,
+ pattern->color.green,
+ pattern->color.blue,
+ alpha);
}
static void
@@ -1390,12 +1387,11 @@ emit_surface_pattern (cairo_pdf_surface_t *dst,
cairo_surface_pattern_t *pattern)
{
cairo_pdf_document_t *document = dst->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
cairo_pdf_stream_t *stream;
cairo_image_surface_t *image;
void *image_extra;
cairo_status_t status;
- char entries[250];
unsigned int id, alpha;
cairo_matrix_t pm;
@@ -1414,36 +1410,33 @@ emit_surface_pattern (cairo_pdf_surface_t *dst,
/* BBox must be smaller than XStep by YStep or acroread wont
* display the pattern. */
- cairo_matrix_set_identity (&pm);
+ cairo_matrix_init_identity (&pm);
cairo_matrix_scale (&pm, image->width, image->height);
- cairo_matrix_copy (&pm, &pattern->base.matrix);
+ pm = pattern->base.matrix;
cairo_matrix_invert (&pm);
- snprintf (entries, sizeof entries,
- " /BBox [ 0 0 256 256 ]\r\n"
- " /XStep 256\r\n"
- " /YStep 256\r\n"
- " /PatternType 1\r\n"
- " /TilingType 1\r\n"
- " /PaintType 1\r\n"
- " /Resources << /XObject << /res%d %d 0 R >> >>\r\n"
- " /Matrix [ %f %f %f %f %f %f ]\r\n",
- id, id,
- pm.m[0][0], pm.m[0][1],
- pm.m[1][0], pm.m[1][1],
- pm.m[2][0], pm.m[2][1]);
+ stream = _cairo_pdf_document_open_stream (document,
+ " /BBox [ 0 0 256 256 ]\r\n"
+ " /XStep 256\r\n"
+ " /YStep 256\r\n"
+ " /PatternType 1\r\n"
+ " /TilingType 1\r\n"
+ " /PaintType 1\r\n"
+ " /Resources << /XObject << /res%d %d 0 R >> >>\r\n",
+ id, id);
- stream = _cairo_pdf_document_open_stream (document, entries);
- /* FIXME: emit code to show surface here. */
+ _cairo_output_stream_printf (output,
+ " /res%d Do\r\n",
+ id);
_cairo_pdf_surface_add_pattern (dst, stream->id);
_cairo_pdf_surface_ensure_stream (dst);
alpha = _cairo_pdf_surface_add_alpha (dst, 1.0);
- fprintf (file,
- "/Pattern cs /res%d scn /a%d gs\r\n",
- stream->id, alpha);
+ _cairo_output_stream_printf (output,
+ "/Pattern cs /res%d scn /a%d gs\r\n",
+ stream->id, alpha);
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
}
@@ -1452,33 +1445,37 @@ static unsigned int
emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern)
{
cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
unsigned int function_id;
+ char stops[2][3];
function_id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /FunctionType 0\r\n"
- " /Domain [ 0.0 1.0 ]\r\n"
- " /Size [ 2 ]\r\n"
- " /BitsPerSample 8\r\n"
- " /Range [ 0.0 1.0 0.0 1.0 0.0 1.0 ]\r\n"
- " /Length 6\r\n"
- ">>\r\n"
- "stream\r\n",
- function_id);
-
- fputc (pattern->stops[0].color.red * 0xff, file);
- fputc (pattern->stops[0].color.green * 0xff, file);
- fputc (pattern->stops[0].color.blue * 0xff, file);
- fputc (pattern->stops[1].color.red * 0xff, file);
- fputc (pattern->stops[1].color.green * 0xff, file);
- fputc (pattern->stops[1].color.blue * 0xff, file);
-
- fprintf (file,
- "\r\n"
- "endstream\r\n"
- "endobj\r\n");
+
+ _cairo_output_stream_printf (output,
+ "%d 0 obj\r\n"
+ "<< /FunctionType 0\r\n"
+ " /Domain [ 0.0 1.0 ]\r\n"
+ " /Size [ 2 ]\r\n"
+ " /BitsPerSample 8\r\n"
+ " /Range [ 0.0 1.0 0.0 1.0 0.0 1.0 ]\r\n"
+ " /Length 6\r\n"
+ ">>\r\n"
+ "stream\r\n",
+ function_id);
+
+ stops[0][0] = pattern->stops[0].color.red * 0xff + 0.5;
+ stops[0][1] = pattern->stops[0].color.green * 0xff + 0.5;
+ stops[0][2] = pattern->stops[0].color.blue * 0xff + 0.5;
+ stops[1][0] = pattern->stops[1].color.red * 0xff + 0.5;
+ stops[1][1] = pattern->stops[1].color.green * 0xff + 0.5;
+ stops[1][2] = pattern->stops[1].color.blue * 0xff + 0.5;
+
+ _cairo_output_stream_write (output, stops, sizeof (stops));
+
+ _cairo_output_stream_printf (output,
+ "\r\n"
+ "endstream\r\n"
+ "endobj\r\n");
return function_id;
}
@@ -1487,7 +1484,7 @@ static void
emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *pattern)
{
cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
unsigned int function_id, pattern_id, alpha;
double x0, y0, x1, y1;
cairo_matrix_t p2u;
@@ -1496,7 +1493,7 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *patte
function_id = emit_pattern_stops (surface, &pattern->base);
- cairo_matrix_copy (&p2u, &pattern->base.base.matrix);
+ p2u = pattern->base.base.matrix;
cairo_matrix_invert (&p2u);
x0 = pattern->point0.x;
@@ -1507,24 +1504,24 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *patte
cairo_matrix_transform_point (&p2u, &x1, &y1);
pattern_id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Type /Pattern\r\n"
- " /PatternType 2\r\n"
- " /Matrix [ 1 0 0 -1 0 %f ]\r\n"
- " /Shading\r\n"
- " << /ShadingType 2\r\n"
- " /ColorSpace /DeviceRGB\r\n"
- " /Coords [ %f %f %f %f ]\r\n"
- " /Function %d 0 R\r\n"
- " /Extend [ true true ]\r\n"
- " >>\r\n"
- ">>\r\n"
- "endobj\r\n",
- pattern_id,
- document->height_inches * document->y_ppi,
- x0, y0, x1, y1,
- function_id);
+ _cairo_output_stream_printf (output,
+ "%d 0 obj\r\n"
+ "<< /Type /Pattern\r\n"
+ " /PatternType 2\r\n"
+ " /Matrix [ 1 0 0 -1 0 %f ]\r\n"
+ " /Shading\r\n"
+ " << /ShadingType 2\r\n"
+ " /ColorSpace /DeviceRGB\r\n"
+ " /Coords [ %f %f %f %f ]\r\n"
+ " /Function %d 0 R\r\n"
+ " /Extend [ true true ]\r\n"
+ " >>\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ pattern_id,
+ document->height,
+ x0, y0, x1, y1,
+ function_id);
_cairo_pdf_surface_add_pattern (surface, pattern_id);
@@ -1532,16 +1529,16 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *patte
alpha = _cairo_pdf_surface_add_alpha (surface, 1.0);
/* Use pattern */
- fprintf (file,
- "/Pattern cs /res%d scn /a%d gs\r\n",
- pattern_id, alpha);
+ _cairo_output_stream_printf (output,
+ "/Pattern cs /res%d scn /a%d gs\r\n",
+ pattern_id, alpha);
}
static void
emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *pattern)
{
cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
unsigned int function_id, pattern_id, alpha;
double x0, y0, x1, y1, r0, r1;
cairo_matrix_t p2u;
@@ -1550,7 +1547,7 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *patte
function_id = emit_pattern_stops (surface, &pattern->base);
- cairo_matrix_copy (&p2u, &pattern->base.base.matrix);
+ p2u = pattern->base.base.matrix;
cairo_matrix_invert (&p2u);
x0 = pattern->center0.x;
@@ -1574,24 +1571,24 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *patte
* behavoir, not yet sure how to implement the cairo mirror and
* repeat behaviour. */
pattern_id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Type /Pattern\r\n"
- " /PatternType 2\r\n"
- " /Matrix [ 1 0 0 -1 0 %f ]\r\n"
- " /Shading\r\n"
- " << /ShadingType 3\r\n"
- " /ColorSpace /DeviceRGB\r\n"
- " /Coords [ %f %f %f %f %f %f ]\r\n"
- " /Function %d 0 R\r\n"
- " /Extend [ true true ]\r\n"
- " >>\r\n"
- ">>\r\n"
- "endobj\r\n",
- pattern_id,
- document->height_inches * document->y_ppi,
- x0, y0, r0, x1, y1, r1,
- function_id);
+ _cairo_output_stream_printf (output,
+ "%d 0 obj\r\n"
+ "<< /Type /Pattern\r\n"
+ " /PatternType 2\r\n"
+ " /Matrix [ 1 0 0 -1 0 %f ]\r\n"
+ " /Shading\r\n"
+ " << /ShadingType 3\r\n"
+ " /ColorSpace /DeviceRGB\r\n"
+ " /Coords [ %f %f %f %f %f %f ]\r\n"
+ " /Function %d 0 R\r\n"
+ " /Extend [ true true ]\r\n"
+ " >>\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ pattern_id,
+ document->height,
+ x0, y0, r0, x1, y1, r1,
+ function_id);
_cairo_pdf_surface_add_pattern (surface, pattern_id);
@@ -1599,9 +1596,9 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *patte
alpha = _cairo_pdf_surface_add_alpha (surface, 1.0);
/* Use pattern */
- fprintf (file,
- "/Pattern cs /res%d scn /a%d gs\r\n",
- pattern_id, alpha);
+ _cairo_output_stream_printf (output,
+ "/Pattern cs /res%d scn /a%d gs\r\n",
+ pattern_id, alpha);
}
static void
@@ -1635,6 +1632,104 @@ intersect (cairo_line_t *line, cairo_fixed_t y)
_cairo_fixed_to_double (line->p2.y - line->p1.y);
}
+typedef struct
+{
+ cairo_output_stream_t *output_stream;
+} pdf_path_info_t;
+
+static cairo_status_t
+_cairo_pdf_path_move_to (void *closure, cairo_point_t *point)
+{
+ pdf_path_info_t *info = closure;
+
+ _cairo_output_stream_printf (info->output_stream,
+ "%f %f m ",
+ _cairo_fixed_to_double (point->x),
+ _cairo_fixed_to_double (point->y));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_path_line_to (void *closure, cairo_point_t *point)
+{
+ pdf_path_info_t *info = closure;
+
+ _cairo_output_stream_printf (info->output_stream,
+ "%f %f l ",
+ _cairo_fixed_to_double (point->x),
+ _cairo_fixed_to_double (point->y));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_path_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d)
+{
+ pdf_path_info_t *info = closure;
+
+ _cairo_output_stream_printf (info->output_stream,
+ "%f %f %f %f %f %f c ",
+ _cairo_fixed_to_double (b->x),
+ _cairo_fixed_to_double (b->y),
+ _cairo_fixed_to_double (c->x),
+ _cairo_fixed_to_double (c->y),
+ _cairo_fixed_to_double (d->x),
+ _cairo_fixed_to_double (d->y));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_path_close_path (void *closure)
+{
+ pdf_path_info_t *info = closure;
+
+ _cairo_output_stream_printf (info->output_stream,
+ "h\r\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_fill_path (cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ void *abstract_dst,
+ cairo_path_fixed_t *path)
+{
+ cairo_pdf_surface_t *surface = abstract_dst;
+ cairo_pdf_document_t *document = surface->document;
+ cairo_status_t status;
+ pdf_path_info_t info;
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ emit_pattern (surface, pattern);
+
+ /* After the above switch the current stream should belong to this
+ * surface, so no need to _cairo_pdf_surface_ensure_stream() */
+ assert (document->current_stream != NULL &&
+ document->current_stream == surface->current_stream);
+
+ info.output_stream = document->output_stream;
+
+ status = _cairo_path_fixed_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_pdf_path_move_to,
+ _cairo_pdf_path_line_to,
+ _cairo_pdf_path_curve_to,
+ _cairo_pdf_path_close_path,
+ &info);
+
+ _cairo_output_stream_printf (document->output_stream,
+ "f\r\n");
+
+ return status;
+}
+
static cairo_int_status_t
_cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator,
cairo_pattern_t *pattern,
@@ -1650,7 +1745,7 @@ _cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator,
{
cairo_pdf_surface_t *surface = abstract_dst;
cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
int i;
emit_pattern (surface, pattern);
@@ -1668,16 +1763,16 @@ _cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator,
right_x1 = intersect (&traps[i].right, traps[i].top);
right_x2 = intersect (&traps[i].right, traps[i].bottom);
- fprintf (file,
- "%f %f m %f %f l %f %f l %f %f l h\r\n",
- left_x1, _cairo_fixed_to_double (traps[i].top),
- left_x2, _cairo_fixed_to_double (traps[i].bottom),
- right_x2, _cairo_fixed_to_double (traps[i].bottom),
- right_x1, _cairo_fixed_to_double (traps[i].top));
+ _cairo_output_stream_printf (output,
+ "%f %f m %f %f l %f %f l %f %f l h\r\n",
+ left_x1, _cairo_fixed_to_double (traps[i].top),
+ left_x2, _cairo_fixed_to_double (traps[i].bottom),
+ right_x2, _cairo_fixed_to_double (traps[i].bottom),
+ right_x1, _cairo_fixed_to_double (traps[i].top));
}
- fprintf (file,
- "f\r\n");
+ _cairo_output_stream_printf (output,
+ "f\r\n");
return CAIRO_STATUS_SUCCESS;
}
@@ -1706,21 +1801,33 @@ _cairo_pdf_surface_show_page (void *abstract_surface)
}
static cairo_int_status_t
-_cairo_pdf_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
+_cairo_pdf_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t *rectangle)
{
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ cairo_pdf_surface_t *surface = abstract_surface;
+
+ rectangle->x = 0;
+ rectangle->y = 0;
+
+ /* XXX: The conversion to integers here is pretty bogus, (not to
+ * mention the aribitray limitation of width to a short(!). We
+ * may need to come up with a better interface for get_size.
+ */
+ rectangle->width = (int) ceil (surface->width);
+ rectangle->height = (int) ceil (surface->height);
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_pdf_font_t *
_cairo_pdf_document_get_font (cairo_pdf_document_t *document,
- cairo_font_t *font)
+ cairo_scaled_font_t *scaled_font)
{
cairo_unscaled_font_t *unscaled_font;
cairo_pdf_font_t *pdf_font;
unsigned int num_fonts, i;
- unscaled_font = _cairo_ft_font_get_unscaled_font (font);
+ unscaled_font = _cairo_ft_scaled_font_get_unscaled_font (scaled_font);
num_fonts = _cairo_array_num_elements (&document->fonts);
for (i = 0; i < num_fonts; i++) {
@@ -1743,8 +1850,8 @@ _cairo_pdf_document_get_font (cairo_pdf_document_t *document,
return pdf_font;
}
-static cairo_status_t
-_cairo_pdf_surface_show_glyphs (cairo_font_t *font,
+static cairo_int_status_t
+_cairo_pdf_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_operator_t operator,
cairo_pattern_t *pattern,
void *abstract_surface,
@@ -1759,32 +1866,34 @@ _cairo_pdf_surface_show_glyphs (cairo_font_t *font,
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
cairo_pdf_font_t *pdf_font;
int i, index;
- pdf_font = _cairo_pdf_document_get_font (document, font);
+ pdf_font = _cairo_pdf_document_get_font (document, scaled_font);
if (pdf_font == NULL)
return CAIRO_STATUS_NO_MEMORY;
emit_pattern (surface, pattern);
- fprintf (file, "BT /res%u 1 Tf", pdf_font->font_id);
+ _cairo_output_stream_printf (output,
+ "BT /res%u 1 Tf", pdf_font->font_id);
for (i = 0; i < num_glyphs; i++) {
index = cairo_pdf_font_use_glyph (pdf_font, glyphs[i].index);
- fprintf (file,
- " %f %f %f %f %f %f Tm (\\%o) Tj",
- font->scale.matrix[0][0],
- font->scale.matrix[0][1],
- font->scale.matrix[1][0],
- -font->scale.matrix[1][1],
- glyphs[i].x,
- glyphs[i].y,
- index);
+ _cairo_output_stream_printf (output,
+ " %f %f %f %f %f %f Tm (\\%o) Tj",
+ scaled_font->scale.xx,
+ scaled_font->scale.yx,
+ scaled_font->scale.xy,
+ -scaled_font->scale.yy,
+ glyphs[i].x,
+ glyphs[i].y,
+ index);
}
- fprintf (file, " ET\r\n");
+ _cairo_output_stream_printf (output,
+ " ET\r\n");
_cairo_pdf_surface_add_font (surface, pdf_font->font_id);
@@ -1793,28 +1902,27 @@ _cairo_pdf_surface_show_glyphs (cairo_font_t *font,
static const cairo_surface_backend_t cairo_pdf_surface_backend = {
_cairo_pdf_surface_create_similar,
- _cairo_pdf_surface_destroy,
- _cairo_pdf_surface_pixels_per_inch,
- _cairo_pdf_surface_acquire_source_image,
- _cairo_pdf_surface_release_source_image,
- _cairo_pdf_surface_acquire_dest_image,
- _cairo_pdf_surface_release_dest_image,
- _cairo_pdf_surface_clone_similar,
+ _cairo_pdf_surface_finish,
+ NULL, /* acquire_source_image */
+ NULL, /* release_source_image */
+ NULL, /* acquire_dest_image */
+ NULL, /* release_dest_image */
+ NULL, /* clone_similar */
_cairo_pdf_surface_composite,
_cairo_pdf_surface_fill_rectangles,
_cairo_pdf_surface_composite_trapezoids,
_cairo_pdf_surface_copy_page,
_cairo_pdf_surface_show_page,
- _cairo_pdf_surface_set_clip_region,
- _cairo_pdf_surface_show_glyphs
+ NULL, /* set_clip_region */
+ _cairo_pdf_surface_get_extents,
+ _cairo_pdf_surface_show_glyphs,
+ _cairo_pdf_surface_fill_path
};
static cairo_pdf_document_t *
-_cairo_pdf_document_create (FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch)
+_cairo_pdf_document_create (cairo_output_stream_t *output_stream,
+ double width,
+ double height)
{
cairo_pdf_document_t *document;
@@ -1822,12 +1930,14 @@ _cairo_pdf_document_create (FILE *file,
if (document == NULL)
return NULL;
- document->file = file;
+ document->output_stream = output_stream;
document->refcount = 1;
- document->width_inches = width_inches;
- document->height_inches = height_inches;
- document->x_ppi = x_pixels_per_inch;
- document->y_ppi = y_pixels_per_inch;
+ document->owner = NULL;
+ document->finished = FALSE;
+ document->width = width;
+ document->height = height;
+ document->x_dpi = DEFAULT_DPI;
+ document->y_dpi = DEFAULT_DPI;
_cairo_array_init (&document->objects, sizeof (cairo_pdf_object_t));
_cairo_array_init (&document->pages, sizeof (unsigned int));
@@ -1840,7 +1950,8 @@ _cairo_pdf_document_create (FILE *file,
_cairo_array_init (&document->fonts, sizeof (cairo_pdf_font_t *));
/* Document header */
- fprintf (file, "%%PDF-1.4\r\n");
+ _cairo_output_stream_printf (output_stream,
+ "%%PDF-1.4\r\n");
return document;
}
@@ -1848,17 +1959,17 @@ _cairo_pdf_document_create (FILE *file,
static unsigned int
_cairo_pdf_document_write_info (cairo_pdf_document_t *document)
{
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
unsigned int id;
id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Creator (cairographics.org)\r\n"
- " /Producer (cairographics.org)\r\n"
- ">>\r\n"
- "endobj\r\n",
- id);
+ _cairo_output_stream_printf (output,
+ "%d 0 obj\r\n"
+ "<< /Creator (cairographics.org)\r\n"
+ " /Producer (cairographics.org)\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ id);
return id;
}
@@ -1866,40 +1977,40 @@ _cairo_pdf_document_write_info (cairo_pdf_document_t *document)
static void
_cairo_pdf_document_write_pages (cairo_pdf_document_t *document)
{
- FILE *file = document->file;
+ cairo_output_stream_t *stream = document->output_stream;
unsigned int page_id;
int num_pages, i;
_cairo_pdf_document_update_object (document, document->pages_id);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Type /Pages\r\n"
- " /Kids [ ",
- document->pages_id);
+ _cairo_output_stream_printf (stream,
+ "%d 0 obj\r\n"
+ "<< /Type /Pages\r\n"
+ " /Kids [ ",
+ document->pages_id);
num_pages = _cairo_array_num_elements (&document->pages);
for (i = 0; i < num_pages; i++) {
_cairo_array_copy_element (&document->pages, i, &page_id);
- fprintf (file, "%d 0 R ", page_id);
+ _cairo_output_stream_printf (stream, "%d 0 R ", page_id);
}
- fprintf (file, "]\r\n");
- fprintf (file, " /Count %d\r\n", num_pages);
+ _cairo_output_stream_printf (stream, "]\r\n");
+ _cairo_output_stream_printf (stream, " /Count %d\r\n", num_pages);
/* TODO: Figure out wich other defaults to be inherited by /Page
* objects. */
- fprintf (file,
- " /MediaBox [ 0 0 %f %f ]\r\n"
- ">>\r\n"
- "endobj\r\n",
- document->width_inches * document->x_ppi,
- document->height_inches * document->y_ppi);
+ _cairo_output_stream_printf (stream,
+ " /MediaBox [ 0 0 %f %f ]\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ document->width,
+ document->height);
}
static cairo_status_t
_cairo_pdf_document_write_fonts (cairo_pdf_document_t *document)
{
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
cairo_pdf_font_t *font;
int num_fonts, i, j;
const char *data;
@@ -1923,76 +2034,76 @@ _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document)
}
stream_id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Filter /FlateDecode\r\n"
- " /Length %lu\r\n"
- " /Length1 %lu\r\n"
- ">>\r\n"
- "stream\r\n",
- stream_id,
- compressed_size,
- data_size);
- fwrite (compressed, 1, compressed_size, file);
- fprintf (file,
- "\r\n"
- "endstream\r\n"
- "endobj\r\n");
+ _cairo_output_stream_printf (output,
+ "%d 0 obj\r\n"
+ "<< /Filter /FlateDecode\r\n"
+ " /Length %lu\r\n"
+ " /Length1 %lu\r\n"
+ ">>\r\n"
+ "stream\r\n",
+ stream_id,
+ compressed_size,
+ data_size);
+ _cairo_output_stream_write (output, compressed, compressed_size);
+ _cairo_output_stream_printf (output,
+ "\r\n"
+ "endstream\r\n"
+ "endobj\r\n");
free (compressed);
descriptor_id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Type /FontDescriptor\r\n"
- " /FontName /7%s\r\n"
- " /Flags 4\r\n"
- " /FontBBox [ %ld %ld %ld %ld ]\r\n"
- " /ItalicAngle 0\r\n"
- " /Ascent %ld\r\n"
- " /Descent %ld\r\n"
- " /CapHeight 500\r\n"
- " /StemV 80\r\n"
- " /StemH 80\r\n"
- " /FontFile2 %u 0 R\r\n"
- ">>\r\n"
- "endobj\r\n",
- descriptor_id,
- font->base_font,
- font->x_min,
- font->y_min,
- font->x_max,
- font->y_max,
- font->ascent,
- font->descent,
- stream_id);
+ _cairo_output_stream_printf (output,
+ "%d 0 obj\r\n"
+ "<< /Type /FontDescriptor\r\n"
+ " /FontName /7%s\r\n"
+ " /Flags 4\r\n"
+ " /FontBBox [ %ld %ld %ld %ld ]\r\n"
+ " /ItalicAngle 0\r\n"
+ " /Ascent %ld\r\n"
+ " /Descent %ld\r\n"
+ " /CapHeight 500\r\n"
+ " /StemV 80\r\n"
+ " /StemH 80\r\n"
+ " /FontFile2 %u 0 R\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ descriptor_id,
+ font->base_font,
+ font->x_min,
+ font->y_min,
+ font->x_max,
+ font->y_max,
+ font->ascent,
+ font->descent,
+ stream_id);
_cairo_pdf_document_update_object (document, font->font_id);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Type /Font\r\n"
- " /Subtype /TrueType\r\n"
- " /BaseFont /%s\r\n"
- " /FirstChar 0\r\n"
- " /LastChar %d\r\n"
- " /FontDescriptor %d 0 R\r\n"
- " /Widths ",
- font->font_id,
- font->base_font,
- font->num_glyphs,
- descriptor_id);
-
- fprintf (file,
- "[");
+ _cairo_output_stream_printf (output,
+ "%d 0 obj\r\n"
+ "<< /Type /Font\r\n"
+ " /Subtype /TrueType\r\n"
+ " /BaseFont /%s\r\n"
+ " /FirstChar 0\r\n"
+ " /LastChar %d\r\n"
+ " /FontDescriptor %d 0 R\r\n"
+ " /Widths ",
+ font->font_id,
+ font->base_font,
+ font->num_glyphs,
+ descriptor_id);
+
+ _cairo_output_stream_printf (output,
+ "[");
for (j = 0; j < font->num_glyphs; j++)
- fprintf (file,
- " %d",
- font->widths[j]);
+ _cairo_output_stream_printf (output,
+ " %d",
+ font->widths[j]);
- fprintf (file,
- " ]\r\n"
- ">>\r\n"
- "endobj\r\n");
+ _cairo_output_stream_printf (output,
+ " ]\r\n"
+ ">>\r\n"
+ "endobj\r\n");
fail:
cairo_pdf_ft_font_destroy (font);
@@ -2004,17 +2115,17 @@ _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document)
static unsigned int
_cairo_pdf_document_write_catalog (cairo_pdf_document_t *document)
{
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
unsigned int id;
id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Type /Catalog\r\n"
- " /Pages %d 0 R\r\n"
- ">>\r\n"
- "endobj\r\n",
- id, document->pages_id);
+ _cairo_output_stream_printf (output,
+ "%d 0 obj\r\n"
+ "<< /Type /Catalog\r\n"
+ " /Pages %d 0 R\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ id, document->pages_id);
return id;
}
@@ -2022,23 +2133,27 @@ _cairo_pdf_document_write_catalog (cairo_pdf_document_t *document)
static long
_cairo_pdf_document_write_xref (cairo_pdf_document_t *document)
{
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
cairo_pdf_object_t *object;
int num_objects, i;
long offset;
+ char buffer[11];
num_objects = _cairo_array_num_elements (&document->objects);
- offset = ftell(file);
- fprintf (document->file,
- "xref\r\n"
- "%d %d\r\n",
- 0, num_objects + 1);
+ offset = _cairo_output_stream_get_position (output);
+ _cairo_output_stream_printf (output,
+ "xref\r\n"
+ "%d %d\r\n",
+ 0, num_objects + 1);
- fprintf (file, "0000000000 65535 f\r\n");
+ _cairo_output_stream_printf (output,
+ "0000000000 65535 f\r\n");
for (i = 0; i < num_objects; i++) {
object = _cairo_array_index (&document->objects, i);
- fprintf (file, "%010ld 00000 n\r\n", object->offset);
+ snprintf (buffer, sizeof buffer, "%010ld", object->offset);
+ _cairo_output_stream_printf (output,
+ "%s 00000 n\r\n", buffer);
}
return offset;
@@ -2053,14 +2168,26 @@ _cairo_pdf_document_reference (cairo_pdf_document_t *document)
static void
_cairo_pdf_document_destroy (cairo_pdf_document_t *document)
{
- FILE *file = document->file;
- long offset;
- unsigned int info_id, catalog_id;
-
document->refcount--;
if (document->refcount > 0)
return;
+ _cairo_pdf_document_finish (document);
+
+ free (document);
+}
+
+static cairo_status_t
+_cairo_pdf_document_finish (cairo_pdf_document_t *document)
+{
+ cairo_status_t status;
+ cairo_output_stream_t *output = document->output_stream;
+ long offset;
+ unsigned int info_id, catalog_id;
+
+ if (document->finished)
+ return CAIRO_STATUS_SUCCESS;
+
_cairo_pdf_document_close_stream (document);
_cairo_pdf_document_write_pages (document);
_cairo_pdf_document_write_fonts (document);
@@ -2068,23 +2195,28 @@ _cairo_pdf_document_destroy (cairo_pdf_document_t *document)
catalog_id = _cairo_pdf_document_write_catalog (document);
offset = _cairo_pdf_document_write_xref (document);
- fprintf (file,
- "trailer\r\n"
- "<< /Size %d\r\n"
- " /Root %d 0 R\r\n"
- " /Info %d 0 R\r\n"
- ">>\r\n",
- document->next_available_id,
- catalog_id,
- info_id);
-
- fprintf (file,
- "startxref\r\n"
- "%ld\r\n"
- "%%%%EOF\r\n",
- offset);
+ _cairo_output_stream_printf (output,
+ "trailer\r\n"
+ "<< /Size %d\r\n"
+ " /Root %d 0 R\r\n"
+ " /Info %d 0 R\r\n"
+ ">>\r\n",
+ document->next_available_id,
+ catalog_id,
+ info_id);
+
+ _cairo_output_stream_printf (output,
+ "startxref\r\n"
+ "%ld\r\n"
+ "%%%%EOF\r\n",
+ offset);
+
+ status = _cairo_output_stream_get_status (output);
+ _cairo_output_stream_destroy (output);
+
+ document->finished = TRUE;
- free (document);
+ return status;
}
static cairo_status_t
@@ -2093,130 +2225,105 @@ _cairo_pdf_document_add_page (cairo_pdf_document_t *document,
{
cairo_pdf_stream_t *stream;
cairo_pdf_resource_t *res;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
unsigned int page_id;
double alpha;
int num_streams, num_alphas, num_resources, i;
+ assert (!document->finished);
+
_cairo_pdf_document_close_stream (document);
page_id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Type /Page\r\n"
- " /Parent %d 0 R\r\n"
- " /Contents [",
- page_id,
- document->pages_id);
+ _cairo_output_stream_printf (output,
+ "%d 0 obj\r\n"
+ "<< /Type /Page\r\n"
+ " /Parent %d 0 R\r\n"
+ " /Contents [",
+ page_id,
+ document->pages_id);
num_streams = _cairo_array_num_elements (&surface->streams);
for (i = 0; i < num_streams; i++) {
_cairo_array_copy_element (&surface->streams, i, &stream);
- fprintf (file,
- " %d 0 R",
- stream->id);
+ _cairo_output_stream_printf (output,
+ " %d 0 R",
+ stream->id);
}
- fprintf (file,
- " ]\r\n"
- " /Resources <<\r\n");
+ _cairo_output_stream_printf (output,
+ " ]\r\n"
+ " /Resources <<\r\n");
num_resources = _cairo_array_num_elements (&surface->fonts);
if (num_resources > 0) {
- fprintf (file,
- " /Font <<");
+ _cairo_output_stream_printf (output,
+ " /Font <<");
for (i = 0; i < num_resources; i++) {
res = _cairo_array_index (&surface->fonts, i);
- fprintf (file,
- " /res%d %d 0 R",
- res->id, res->id);
+ _cairo_output_stream_printf (output,
+ " /res%d %d 0 R",
+ res->id, res->id);
}
- fprintf (file,
- " >>\r\n");
+ _cairo_output_stream_printf (output,
+ " >>\r\n");
}
num_alphas = _cairo_array_num_elements (&surface->alphas);
if (num_alphas > 0) {
- fprintf (file,
- " /ExtGState <<\r\n");
+ _cairo_output_stream_printf (output,
+ " /ExtGState <<\r\n");
for (i = 0; i < num_alphas; i++) {
_cairo_array_copy_element (&surface->alphas, i, &alpha);
- fprintf (file,
- " /a%d << /ca %f >>\r\n",
- i, alpha);
+ _cairo_output_stream_printf (output,
+ " /a%d << /ca %f >>\r\n",
+ i, alpha);
}
- fprintf (file,
- " >>\r\n");
+ _cairo_output_stream_printf (output,
+ " >>\r\n");
}
num_resources = _cairo_array_num_elements (&surface->patterns);
if (num_resources > 0) {
- fprintf (file,
- " /Pattern <<");
+ _cairo_output_stream_printf (output,
+ " /Pattern <<");
for (i = 0; i < num_resources; i++) {
res = _cairo_array_index (&surface->patterns, i);
- fprintf (file,
- " /res%d %d 0 R",
- res->id, res->id);
+ _cairo_output_stream_printf (output,
+ " /res%d %d 0 R",
+ res->id, res->id);
}
- fprintf (file,
- " >>\r\n");
+ _cairo_output_stream_printf (output,
+ " >>\r\n");
}
num_resources = _cairo_array_num_elements (&surface->xobjects);
if (num_resources > 0) {
- fprintf (file,
- " /XObject <<");
+ _cairo_output_stream_printf (output,
+ " /XObject <<");
for (i = 0; i < num_resources; i++) {
res = _cairo_array_index (&surface->xobjects, i);
- fprintf (file,
- " /res%d %d 0 R",
- res->id, res->id);
+ _cairo_output_stream_printf (output,
+ " /res%d %d 0 R",
+ res->id, res->id);
}
- fprintf (file,
- " >>\r\n");
+ _cairo_output_stream_printf (output,
+ " >>\r\n");
}
- fprintf (file,
- " >>\r\n"
- ">>\r\n"
- "endobj\r\n");
+ _cairo_output_stream_printf (output,
+ " >>\r\n"
+ ">>\r\n"
+ "endobj\r\n");
_cairo_array_append (&document->pages, &page_id, 1);
return CAIRO_STATUS_SUCCESS;
}
-
-void
-cairo_set_target_pdf (cairo_t *cr,
- FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch)
-{
- cairo_surface_t *surface;
-
- surface = cairo_pdf_surface_create (file,
- width_inches,
- height_inches,
- x_pixels_per_inch,
- y_pixels_per_inch);
-
- if (surface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface (cr, surface);
-
- /* cairo_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy (surface);
-}
diff --git a/src/cairo-pdf.h b/src/cairo-pdf.h
index 701a7b4a7..61bf7a841 100644
--- a/src/cairo-pdf.h
+++ b/src/cairo-pdf.h
@@ -39,29 +39,30 @@
#include <cairo.h>
-#ifdef CAIRO_HAS_PDF_SURFACE
-
-#include <stdio.h>
+#if CAIRO_HAS_PDF_SURFACE
CAIRO_BEGIN_DECLS
-void
-cairo_set_target_pdf (cairo_t *cr,
- FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch);
-
+cairo_surface_t *
+cairo_pdf_surface_create (const char *filename,
+ double width_in_points,
+ double height_in_points);
cairo_surface_t *
-cairo_pdf_surface_create (FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch);
+cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func,
+ void *closure,
+ double width_in_points,
+ double height_in_points);
+
+void
+cairo_pdf_surface_set_dpi (cairo_surface_t *surface,
+ double x_dpi,
+ double y_dpi);
CAIRO_END_DECLS
+#else /* CAIRO_HAS_PDF_SURFACE */
+# error Cairo was not compiled with support for the pdf backend
#endif /* CAIRO_HAS_PDF_SURFACE */
+
#endif /* CAIRO_PDF_H */
diff --git a/src/cairo-pen.c b/src/cairo-pen.c
index 6ecaa00b3..18b9ddb59 100644
--- a/src/cairo-pen.c
+++ b/src/cairo-pen.c
@@ -36,6 +36,8 @@
#include "cairoint.h"
+#include "cairo-gstate-private.h"
+
static int
_cairo_pen_vertices_needed (double tolerance, double radius, cairo_matrix_t *matrix);
@@ -372,8 +374,8 @@ _cairo_pen_vertices_needed (double tolerance,
double radius,
cairo_matrix_t *matrix)
{
- double a = matrix->m[0][0], c = matrix->m[0][1];
- double b = matrix->m[1][0], d = matrix->m[1][1];
+ double a = matrix->xx, b = matrix->yx;
+ double c = matrix->xy, d = matrix->yy;
double i = a*a + c*c;
double j = b*b + d*d;
diff --git a/src/cairo-png.c b/src/cairo-png.c
new file mode 100644
index 000000000..ecb23ca45
--- /dev/null
+++ b/src/cairo-png.c
@@ -0,0 +1,465 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2003 University of Southern California
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Kristian Høgsberg <krh@redhat.com>
+ */
+
+#include <png.h>
+#include "cairoint.h"
+
+static void
+unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
+{
+ int i;
+
+ for (i = 0; i < row_info->rowbytes; i += 4) {
+ uint8_t *b = &data[i];
+ uint32_t pixel;
+ uint8_t alpha;
+
+ memcpy (&pixel, b, sizeof (uint32_t));
+ alpha = (pixel & 0xff000000) >> 24;
+ if (alpha == 0) {
+ b[0] = b[1] = b[2] = b[3] = 0;
+ } else {
+ b[0] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
+ b[1] = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
+ b[2] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
+ b[3] = alpha;
+ }
+ }
+}
+
+static cairo_status_t
+write_png (cairo_surface_t *surface,
+ png_rw_ptr write_func,
+ void *closure)
+{
+ int i;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_image_surface_t *image;
+ void *image_extra;
+ png_struct *png;
+ png_info *info;
+ png_time pt;
+ png_byte **rows;
+ png_color_16 white;
+ int png_color_type;
+ int depth;
+
+ status = _cairo_surface_acquire_source_image (surface,
+ &image,
+ &image_extra);
+
+ if (status == CAIRO_STATUS_NO_MEMORY)
+ return CAIRO_STATUS_NO_MEMORY;
+ else if (status != CAIRO_STATUS_SUCCESS)
+ return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
+
+ rows = malloc (image->height * sizeof(png_byte*));
+ if (rows == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL1;
+ }
+
+ for (i = 0; i < image->height; i++)
+ rows[i] = (png_byte *) image->data + i * image->stride;
+
+ png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (png == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL2;
+ }
+
+ info = png_create_info_struct (png);
+ if (info == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL3;
+ }
+
+ if (setjmp (png_jmpbuf (png))) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL3;
+ }
+
+ png_set_write_fn (png, closure, write_func, NULL);
+
+ switch (image->format) {
+ case CAIRO_FORMAT_ARGB32:
+ depth = 8;
+ png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ break;
+ case CAIRO_FORMAT_RGB24:
+ depth = 8;
+ png_color_type = PNG_COLOR_TYPE_RGB;
+ break;
+ case CAIRO_FORMAT_A8:
+ depth = 8;
+ png_color_type = PNG_COLOR_TYPE_GRAY;
+ break;
+ case CAIRO_FORMAT_A1:
+ depth = 1;
+ png_color_type = PNG_COLOR_TYPE_GRAY;
+ break;
+ default:
+ status = CAIRO_STATUS_NULL_POINTER;
+ goto BAIL3;
+ }
+
+ png_set_IHDR (png, info,
+ image->width,
+ image->height, depth,
+ png_color_type,
+ PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+
+ white.red = 0xff;
+ white.blue = 0xff;
+ white.green = 0xff;
+ png_set_bKGD (png, info, &white);
+
+ png_convert_from_time_t (&pt, time (NULL));
+ png_set_tIME (png, info, &pt);
+
+ png_set_write_user_transform_fn (png, unpremultiply_data);
+ if (image->format == CAIRO_FORMAT_ARGB32 ||
+ image->format == CAIRO_FORMAT_RGB24)
+ png_set_bgr (png);
+ if (image->format == CAIRO_FORMAT_RGB24)
+ png_set_filler (png, 0, PNG_FILLER_AFTER);
+
+ png_write_info (png, info);
+ png_write_image (png, rows);
+ png_write_end (png, info);
+
+BAIL3:
+ png_destroy_write_struct (&png, &info);
+BAIL2:
+ free (rows);
+BAIL1:
+ _cairo_surface_release_source_image (surface, image, image_extra);
+
+ return status;
+}
+
+static void
+stdio_write_func (png_structp png, png_bytep data, png_size_t size)
+{
+ FILE *fp;
+
+ fp = png_get_io_ptr (png);
+ if (fwrite (data, 1, size, fp) != size)
+ png_error(png, "Write Error");
+}
+
+/**
+ * cairo_surface_write_to_png:
+ * @surface: a #cairo_surface_t with pixel contents
+ * @filename: the name of a file to write to
+ *
+ * Writes the contents of @surface to a new file @filename as a PNG
+ * image.
+ *
+ * Return value: CAIRO_STATUS_SUCCESS if the PNG file was written
+ * successfully. Otherwise, CAIRO_STATUS_NO_MEMORY if memory could not
+ * be allocated for the operation or
+ * CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
+ * pixel contents, or CAIRO_STATUS_WRITE_ERROR if an I/O error occurs
+ * while attempting to write the file.
+ **/
+cairo_status_t
+cairo_surface_write_to_png (cairo_surface_t *surface,
+ const char *filename)
+{
+ FILE *fp;
+ cairo_status_t status;
+
+ fp = fopen (filename, "wb");
+ if (fp == NULL)
+ return CAIRO_STATUS_WRITE_ERROR;
+
+ status = write_png (surface, stdio_write_func, fp);
+
+ if (fclose (fp) && CAIRO_OK (status))
+ status = CAIRO_STATUS_WRITE_ERROR;
+
+ return status;
+}
+
+struct png_write_closure_t {
+ cairo_write_func_t write_func;
+ void *closure;
+};
+
+static void
+stream_write_func (png_structp png, png_bytep data, png_size_t size)
+{
+ struct png_write_closure_t *png_closure;
+
+ png_closure = png_get_io_ptr (png);
+ if (!CAIRO_OK (png_closure->write_func (png_closure->closure, data, size)))
+ png_error(png, "Write Error");
+}
+
+/**
+ * cairo_surface_write_to_png_stream:
+ * @surface: a #cairo_surface_t with pixel contents
+ * @write_func: a #cairo_write_func_t
+ * @closure: closure data for the write function
+ *
+ * Writes the image surface to the write function.
+ *
+ * Return value: CAIRO_STATUS_SUCCESS if the PNG file was written
+ * successfully. Otherwise, CAIRO_STATUS_NO_MEMORY is returned if
+ * memory could not be allocated for the operation,
+ * CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
+ * pixel contents.
+ **/
+cairo_status_t
+cairo_surface_write_to_png_stream (cairo_surface_t *surface,
+ cairo_write_func_t write_func,
+ void *closure)
+{
+ struct png_write_closure_t png_closure;
+
+ png_closure.write_func = write_func;
+ png_closure.closure = closure;
+
+ return write_png (surface, stream_write_func, &png_closure);
+}
+
+static void
+premultiply_data (png_structp png,
+ png_row_infop row_info,
+ png_bytep data)
+{
+ int i;
+
+ for (i = 0; i < row_info->rowbytes; i += 4) {
+ uint8_t *base = &data[i];
+ uint8_t blue = base[0];
+ uint8_t green = base[1];
+ uint8_t red = base[2];
+ uint8_t alpha = base[3];
+ uint32_t p;
+
+ red = ((unsigned) red * (unsigned) alpha + 127) / 255;
+ green = ((unsigned) green * (unsigned) alpha + 127) / 255;
+ blue = ((unsigned) blue * (unsigned) alpha + 127) / 255;
+ p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
+ memcpy (base, &p, sizeof (uint32_t));
+ }
+}
+
+static cairo_surface_t *
+read_png (png_rw_ptr read_func,
+ void *closure)
+{
+ cairo_surface_t *surface;
+ png_byte *data;
+ int i;
+ png_struct *png;
+ png_info *info;
+ png_uint_32 png_width, png_height, stride;
+ int depth, color_type, interlace;
+ unsigned int pixel_size;
+ png_byte **row_pointers;
+
+ surface = NULL;
+ data = NULL;
+ row_pointers = NULL;
+
+ /* XXX: Perhaps we'll want some other error handlers? */
+ png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
+ NULL,
+ NULL,
+ NULL);
+ if (png == NULL)
+ return NULL;
+
+ info = png_create_info_struct (png);
+ if (info == NULL)
+ goto BAIL;
+
+ png_set_read_fn (png, closure, read_func);
+
+ if (setjmp (png_jmpbuf (png)))
+ goto BAIL;
+
+ png_read_info (png, info);
+
+ png_get_IHDR (png, info,
+ &png_width, &png_height, &depth,
+ &color_type, &interlace, NULL, NULL);
+ stride = 4 * png_width;
+
+ /* convert palette/gray image to rgb */
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_palette_to_rgb (png);
+
+ /* expand gray bit depth if needed */
+ if (color_type == PNG_COLOR_TYPE_GRAY && depth < 8)
+ png_set_gray_1_2_4_to_8 (png);
+ /* transform transparency to alpha */
+ if (png_get_valid(png, info, PNG_INFO_tRNS))
+ png_set_tRNS_to_alpha (png);
+
+ if (depth == 16)
+ png_set_strip_16 (png);
+
+ if (depth < 8)
+ png_set_packing (png);
+
+ /* convert grayscale to RGB */
+ if (color_type == PNG_COLOR_TYPE_GRAY
+ || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb (png);
+
+ if (interlace != PNG_INTERLACE_NONE)
+ png_set_interlace_handling (png);
+
+ png_set_bgr (png);
+ png_set_filler (png, 0xff, PNG_FILLER_AFTER);
+
+ png_set_read_user_transform_fn (png, premultiply_data);
+
+ png_read_update_info (png, info);
+
+ pixel_size = 4;
+ data = malloc (png_width * png_height * pixel_size);
+ if (data == NULL)
+ goto BAIL;
+
+ row_pointers = malloc (png_height * sizeof(char *));
+ if (row_pointers == NULL)
+ goto BAIL;
+
+ for (i = 0; i < png_height; i++)
+ row_pointers[i] = &data[i * png_width * pixel_size];
+
+ png_read_image (png, row_pointers);
+ png_read_end (png, info);
+
+ surface = cairo_image_surface_create_for_data (data,
+ CAIRO_FORMAT_ARGB32,
+ png_width, png_height, stride);
+ _cairo_image_surface_assume_ownership_of_data ((cairo_image_surface_t*)surface);
+ data = NULL;
+
+ BAIL:
+ free (row_pointers);
+ free (data);
+ png_destroy_read_struct (&png, NULL, NULL);
+
+ return surface;
+}
+
+static void
+stdio_read_func (png_structp png, png_bytep data, png_size_t size)
+{
+ FILE *fp;
+
+ fp = png_get_io_ptr (png);
+ if (fread (data, 1, size, fp) != size)
+ png_error(png, "Read Error");
+}
+
+/**
+ * cairo_image_surface_create_from_png:
+ * @filename: name of PNG file to load
+ *
+ * Creates a new image surface and initializes the contents to the
+ * given PNG file.
+ *
+ * Return value: a new #cairo_surface_t initialized with the contents
+ * of the PNG file or %NULL if the file is not a valid PNG file or
+ * memory could not be allocated for the operation.
+ **/
+cairo_surface_t *
+cairo_image_surface_create_from_png (const char *filename)
+{
+ FILE *fp;
+ cairo_surface_t *surface;
+
+ fp = fopen (filename, "rb");
+ if (fp == NULL)
+ return NULL;
+
+ surface = read_png (stdio_read_func, fp);
+
+ fclose (fp);
+
+ return surface;
+}
+
+struct png_read_closure_t {
+ cairo_read_func_t read_func;
+ void *closure;
+};
+
+static void
+stream_read_func (png_structp png, png_bytep data, png_size_t size)
+{
+ struct png_read_closure_t *png_closure;
+
+ png_closure = png_get_io_ptr (png);
+ if (!CAIRO_OK (png_closure->read_func (png_closure->closure, data, size)))
+ png_error(png, "Read Error");
+}
+
+/**
+ * cairo_image_surface_create_from_png_stream:
+ * @read_func: function called to read the data of the file
+ * @closure: data to pass to @read_func.
+ *
+ * Creates a new image surface from PNG data read incrementally
+ * via the @read_func function.
+ *
+ * Return value: a new #cairo_surface_t initialized with the contents
+ * of the PNG file or %NULL if the data read is not a valid PNG image or
+ * memory could not be allocated for the operation.
+ **/
+cairo_surface_t *
+cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
+ void *closure)
+{
+ struct png_read_closure_t png_closure;
+
+ png_closure.read_func = read_func;
+ png_closure.closure = closure;
+
+ return read_png (stream_read_func, &closure);
+}
+
diff --git a/src/cairo-private.h b/src/cairo-private.h
new file mode 100644
index 000000000..a43c8ef7f
--- /dev/null
+++ b/src/cairo-private.h
@@ -0,0 +1,51 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@redhat.com>
+ */
+
+#ifndef CAIRO_PRIVATE_H
+#define CAIRO_PRIVATE_H
+
+#include "cairo-gstate-private.h"
+#include "cairo-path-fixed-private.h"
+
+struct _cairo {
+ unsigned int ref_count;
+
+ cairo_gstate_t *gstate;
+ cairo_path_fixed_t path;
+
+ cairo_status_t status;
+};
+
+#endif /* CAIRO_PRIVATE_H */
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 4a45fc679..a79703e1d 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -42,74 +42,34 @@
static const cairo_surface_backend_t cairo_ps_surface_backend;
-/**
- * cairo_set_target_ps:
- * @cr: a #cairo_t
- * @file: an open, writeable file
- * @width_inches: width of the output page, in inches
- * @height_inches: height of the output page, in inches
- * @x_pixels_per_inch: X resolution to use for image fallbacks;
- * not all Cairo drawing can be represented in a postscript
- * file, so Cairo will write out images for some portions
- * of the output.
- * @y_pixels_per_inch: Y resolution to use for image fallbacks.
- *
- * Directs output for a #cairo_t to a postscript file. The file must
- * be kept open until the #cairo_t is destroyed or set to have a
- * different target, and then must be closed by the application.
- **/
-void
-cairo_set_target_ps (cairo_t *cr,
- FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch)
-{
- cairo_surface_t *surface;
-
- surface = cairo_ps_surface_create (file,
- width_inches, height_inches,
- x_pixels_per_inch, y_pixels_per_inch);
- if (surface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface (cr, surface);
-
- /* cairo_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy (surface);
-}
-
typedef struct cairo_ps_surface {
cairo_surface_t base;
/* PS-specific fields */
- FILE *file;
+ cairo_output_stream_t *stream;
- double width_inches;
- double height_inches;
- double x_ppi;
- double y_ppi;
+ double width_in_points;
+ double height_in_points;
+ double x_dpi;
+ double y_dpi;
int pages;
cairo_image_surface_t *image;
} cairo_ps_surface_t;
+#define PS_SURFACE_DPI_DEFAULT 300.0
+
static void
_cairo_ps_surface_erase (cairo_ps_surface_t *surface);
-cairo_surface_t *
-cairo_ps_surface_create (FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch)
+static cairo_surface_t *
+_cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
+ double width_in_points,
+ double height_in_points)
{
cairo_ps_surface_t *surface;
- int width, height;
+ int width_in_pixels, height_in_pixels;
time_t now = time (0);
surface = malloc (sizeof (cairo_ps_surface_t));
@@ -118,20 +78,21 @@ cairo_ps_surface_create (FILE *file,
_cairo_surface_init (&surface->base, &cairo_ps_surface_backend);
- surface->file = file;
+ surface->stream = stream;
- surface->width_inches = width_inches;
- surface->height_inches = height_inches;
- surface->x_ppi = x_pixels_per_inch;
- surface->y_ppi = x_pixels_per_inch;
+ surface->width_in_points = width_in_points;
+ surface->height_in_points = height_in_points;
+ surface->x_dpi = PS_SURFACE_DPI_DEFAULT;
+ surface->y_dpi = PS_SURFACE_DPI_DEFAULT;
surface->pages = 0;
- width = (int) (x_pixels_per_inch * width_inches + 1.0);
- height = (int) (y_pixels_per_inch * height_inches + 1.0);
+ width_in_pixels = (int) (surface->x_dpi * width_in_points / 72.0 + 1.0);
+ height_in_pixels = (int) (surface->y_dpi * height_in_points / 72.0 + 1.0);
surface->image = (cairo_image_surface_t *)
- cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ width_in_pixels, height_in_pixels);
if (surface->image == NULL) {
free (surface);
return NULL;
@@ -140,26 +101,61 @@ cairo_ps_surface_create (FILE *file,
_cairo_ps_surface_erase (surface);
/* Document header */
- fprintf (file,
- "%%!PS-Adobe-3.0\n"
- "%%%%Creator: Cairo (http://cairographics.org)\n");
- fprintf (file,
- "%%%%CreationDate: %s",
- ctime (&now));
- fprintf (file,
- "%%%%BoundingBox: %d %d %d %d\n",
- 0, 0, (int) (surface->width_inches * 72.0), (int) (surface->height_inches * 72.0));
+ _cairo_output_stream_printf (surface->stream,
+ "%%!PS-Adobe-3.0\n"
+ "%%%%Creator: Cairo (http://cairographics.org)\n");
+ _cairo_output_stream_printf (surface->stream,
+ "%%%%CreationDate: %s",
+ ctime (&now));
+ _cairo_output_stream_printf (surface->stream,
+ "%%%%BoundingBox: %f %f %f %f\n",
+ 0.0, 0.0,
+ surface->width_in_points,
+ surface->height_in_points);
/* The "/FlateDecode filter" currently used is a feature of LanguageLevel 3 */
- fprintf (file,
- "%%%%DocumentData: Clean7Bit\n"
- "%%%%LanguageLevel: 3\n");
- fprintf (file,
- "%%%%Orientation: Portrait\n"
- "%%%%EndComments\n");
+ _cairo_output_stream_printf (surface->stream,
+ "%%%%DocumentData: Clean7Bit\n"
+ "%%%%LanguageLevel: 3\n");
+ _cairo_output_stream_printf (surface->stream,
+ "%%%%Orientation: Portrait\n"
+ "%%%%EndComments\n");
return &surface->base;
}
+cairo_surface_t *
+cairo_ps_surface_create (const char *filename,
+ double width_in_points,
+ double height_in_points)
+{
+ cairo_output_stream_t *stream;
+
+ stream = _cairo_output_stream_create_for_file (filename);
+ if (stream == NULL)
+ return NULL;
+
+ return _cairo_ps_surface_create_for_stream_internal (stream,
+ width_in_points,
+ height_in_points);
+}
+
+cairo_surface_t *
+cairo_ps_surface_create_for_stream (cairo_write_func_t write_func,
+ void *closure,
+ double width_in_points,
+ double height_in_points)
+{
+ cairo_output_stream_t *stream;
+
+ stream = _cairo_output_stream_create (write_func, closure);
+ if (stream == NULL)
+ return NULL;
+
+ return _cairo_ps_surface_create_for_stream_internal (stream,
+ width_in_points,
+ height_in_points);
+}
+
static cairo_surface_t *
_cairo_ps_surface_create_similar (void *abstract_src,
cairo_format_t format,
@@ -170,44 +166,31 @@ _cairo_ps_surface_create_similar (void *abstract_src,
return NULL;
}
-static void
-_cairo_ps_surface_destroy (void *abstract_surface)
+static cairo_status_t
+_cairo_ps_surface_finish (void *abstract_surface)
{
cairo_ps_surface_t *surface = abstract_surface;
/* Document footer */
- fprintf (surface->file, "%%%%EOF\n");
+ _cairo_output_stream_printf (surface->stream,
+ "%%%%EOF\n");
cairo_surface_destroy (&surface->image->base);
- free (surface);
+ return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_ps_surface_erase (cairo_ps_surface_t *surface)
{
- cairo_color_t transparent;
-
- _cairo_color_init (&transparent);
- _cairo_color_set_rgb (&transparent, 0., 0., 0.);
- _cairo_color_set_alpha (&transparent, 0.);
_cairo_surface_fill_rectangle (&surface->image->base,
- CAIRO_OPERATOR_SRC,
- &transparent,
+ CAIRO_OPERATOR_SOURCE,
+ CAIRO_COLOR_TRANSPARENT,
0, 0,
surface->image->width,
surface->image->height);
}
-/* XXX: We should re-work this interface to return both X/Y ppi values. */
-static double
-_cairo_ps_surface_pixels_per_inch (void *abstract_surface)
-{
- cairo_ps_surface_t *surface = abstract_surface;
-
- return surface->y_ppi;
-}
-
static cairo_status_t
_cairo_ps_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
@@ -220,13 +203,6 @@ _cairo_ps_surface_acquire_source_image (void *abstract_surfac
return CAIRO_STATUS_SUCCESS;
}
-static void
-_cairo_ps_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
-}
-
static cairo_status_t
_cairo_ps_surface_acquire_dest_image (void *abstract_surface,
cairo_rectangle_t *interest_rect,
@@ -246,66 +222,6 @@ _cairo_ps_surface_acquire_dest_image (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
-static void
-_cairo_ps_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_ps_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_composite (cairo_operator_t operator,
- cairo_pattern_t *src,
- cairo_pattern_t *mask,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_fill_rectangles (void *abstract_surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *generic_src,
- void *abstract_dst,
- int x_src,
- int y_src,
- int x_dst,
- int y_dst,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
static cairo_int_status_t
_cairo_ps_surface_copy_page (void *abstract_surface)
{
@@ -313,13 +229,13 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
cairo_ps_surface_t *surface = abstract_surface;
int width = surface->image->width;
int height = surface->image->height;
- FILE *file = surface->file;
+ cairo_output_stream_t *stream = surface->stream;
int i, x, y;
cairo_solid_pattern_t white_pattern;
- char *rgb, *compressed;
- long rgb_size, compressed_size;
+ unsigned char *rgb, *compressed;
+ unsigned long rgb_size, compressed_size;
rgb_size = 3 * width * height;
rgb = malloc (rgb_size);
@@ -338,9 +254,9 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
/* PostScript can not represent the alpha channel, so we blend the
current image over a white RGB surface to eliminate it. */
- _cairo_pattern_init_solid (&white_pattern, 1.0, 1.0, 1.0);
+ _cairo_pattern_init_solid (&white_pattern, CAIRO_COLOR_WHITE);
- _cairo_surface_composite (CAIRO_OPERATOR_OVER_REVERSE,
+ _cairo_surface_composite (CAIRO_OPERATOR_DEST_OVER,
&white_pattern.base,
NULL,
&surface->image->base,
@@ -364,34 +280,34 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
compress (compressed, &compressed_size, rgb, rgb_size);
/* Page header */
- fprintf (file, "%%%%Page: %d\n", ++surface->pages);
+ _cairo_output_stream_printf (stream, "%%%%Page: %d\n", ++surface->pages);
- fprintf (file, "gsave\n");
+ _cairo_output_stream_printf (stream, "gsave\n");
/* Image header goop */
- fprintf (file, "%g %g translate\n", 0.0, surface->height_inches * 72.0);
- fprintf (file, "%g %g scale\n", 72.0 / surface->x_ppi, 72.0 / surface->y_ppi);
- fprintf (file, "/DeviceRGB setcolorspace\n");
- fprintf (file, "<<\n");
- fprintf (file, " /ImageType 1\n");
- fprintf (file, " /Width %d\n", width);
- fprintf (file, " /Height %d\n", height);
- fprintf (file, " /BitsPerComponent 8\n");
- fprintf (file, " /Decode [ 0 1 0 1 0 1 ]\n");
- fprintf (file, " /DataSource currentfile /FlateDecode filter\n");
- fprintf (file, " /ImageMatrix [ 1 0 0 -1 0 1 ]\n");
- fprintf (file, ">>\n");
- fprintf (file, "image\n");
+ _cairo_output_stream_printf (stream, "%f %f translate\n",
+ 0.0, surface->height_in_points);
+ _cairo_output_stream_printf (stream, "/DeviceRGB setcolorspace\n");
+ _cairo_output_stream_printf (stream, "<<\n");
+ _cairo_output_stream_printf (stream, " /ImageType 1\n");
+ _cairo_output_stream_printf (stream, " /Width %d\n", width);
+ _cairo_output_stream_printf (stream, " /Height %d\n", height);
+ _cairo_output_stream_printf (stream, " /BitsPerComponent 8\n");
+ _cairo_output_stream_printf (stream, " /Decode [ 0 1 0 1 0 1 ]\n");
+ _cairo_output_stream_printf (stream, " /DataSource currentfile /FlateDecode filter\n");
+ _cairo_output_stream_printf (stream, " /ImageMatrix [ 1 0 0 -1 0 1 ]\n");
+ _cairo_output_stream_printf (stream, ">>\n");
+ _cairo_output_stream_printf (stream, "image\n");
/* Compressed image data */
- fwrite (compressed, 1, compressed_size, file);
+ _cairo_output_stream_write (stream, compressed, compressed_size);
- fprintf (file, "showpage\n");
+ _cairo_output_stream_printf (stream, "showpage\n");
- fprintf (file, "grestore\n");
+ _cairo_output_stream_printf (stream, "grestore\n");
/* Page footer */
- fprintf (file, "%%%%EndPage\n");
+ _cairo_output_stream_printf (stream, "%%%%EndPage\n");
free (compressed);
BAIL1:
@@ -424,20 +340,39 @@ _cairo_ps_surface_set_clip_region (void *abstract_surface,
return _cairo_image_surface_set_clip_region (surface->image, region);
}
+static cairo_int_status_t
+_cairo_ps_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t *rectangle)
+{
+ cairo_ps_surface_t *surface = abstract_surface;
+
+ rectangle->x = 0;
+ rectangle->y = 0;
+
+ /* XXX: The conversion to integers here is pretty bogus, (not to
+ * mention the aribitray limitation of width to a short(!). We
+ * may need to come up with a better interface for get_size.
+ */
+ rectangle->width = (surface->width_in_points + 0.5);
+ rectangle->height = (surface->height_in_points + 0.5);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static const cairo_surface_backend_t cairo_ps_surface_backend = {
_cairo_ps_surface_create_similar,
- _cairo_ps_surface_destroy,
- _cairo_ps_surface_pixels_per_inch,
+ _cairo_ps_surface_finish,
_cairo_ps_surface_acquire_source_image,
- _cairo_ps_surface_release_source_image,
+ NULL, /* release_source_image */
_cairo_ps_surface_acquire_dest_image,
- _cairo_ps_surface_release_dest_image,
- _cairo_ps_surface_clone_similar,
- _cairo_ps_surface_composite,
- _cairo_ps_surface_fill_rectangles,
- _cairo_ps_surface_composite_trapezoids,
+ NULL, /* release_dest_image */
+ NULL, /* clone_similar */
+ NULL, /* composite */
+ NULL, /* fill_rectangles */
+ NULL, /* composite_trapezoids */
_cairo_ps_surface_copy_page,
_cairo_ps_surface_show_page,
_cairo_ps_surface_set_clip_region,
+ _cairo_ps_surface_get_extents,
NULL /* show_glyphs */
};
diff --git a/src/cairo-ps.h b/src/cairo-ps.h
index 88382920e..ea2d53d09 100644
--- a/src/cairo-ps.h
+++ b/src/cairo-ps.h
@@ -39,30 +39,34 @@
#include <cairo.h>
-#ifdef CAIRO_HAS_PS_SURFACE
+#if CAIRO_HAS_PS_SURFACE
#include <stdio.h>
CAIRO_BEGIN_DECLS
-void
-cairo_set_target_ps (cairo_t *cr,
- FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch);
-
/* PS-surface functions */
cairo_surface_t *
-cairo_ps_surface_create (FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch);
+cairo_ps_surface_create (const char *filename,
+ double width_in_points,
+ double height_in_points);
+
+cairo_surface_t *
+cairo_ps_surface_create_for_stream (cairo_write_func_t write_func,
+ void *closure,
+ double width_in_points,
+ double height_in_points);
+
+void
+cairo_ps_surface_set_dpi (cairo_surface_t *surface,
+ double x_dpi,
+ double y_dpi);
CAIRO_END_DECLS
+#else /* CAIRO_HAS_PS_SURFACE */
+# error Cairo was not compiled with support for the ps backend
#endif /* CAIRO_HAS_PS_SURFACE */
+
#endif /* CAIRO_PS_H */
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 01b345cdc..292f5b491 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -34,359 +34,224 @@
*/
#include "cairoint.h"
+#include "cairo-private.h"
#include "cairo-quartz.h"
-#pragma mark Types
-
typedef struct cairo_quartz_surface {
- cairo_surface_t base;
-
- CGContextRef context;
-
- int width;
- int height;
-
- cairo_image_surface_t *image;
-
- CGImageRef cgImage;
-} cairo_quartz_surface_t;
-
-
-
-
+ cairo_surface_t base;
-#pragma mark Private functions
+ CGContextRef context;
+ int width;
+ int height;
+ cairo_image_surface_t *image;
+ CGImageRef cgImage;
+} cairo_quartz_surface_t;
-void ImageDataReleaseFunc(void *info, const void *data, size_t size)
-{
- if (data != NULL)
- {
- free((void *)data);
- }
-}
-
-
-
-
-#pragma mark Public functions
-
-
-
-
-
-void
-cairo_set_target_quartz_context( cairo_t *cr,
- CGContextRef context,
- int width,
- int height)
+static void
+ImageDataReleaseFunc(void *info, const void *data, size_t size)
{
- cairo_surface_t *surface;
-
-
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
-
- surface = cairo_quartz_surface_create(context, width, height);
- if (surface == NULL)
- {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
+ if (data != NULL) {
+ free((void *) data);
}
-
- cairo_set_target_surface(cr, surface);
-
- /* cairo_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy(surface);
}
-
-static cairo_surface_t *
-_cairo_quartz_surface_create_similar( void *abstract_src,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
+static cairo_surface_t *_cairo_quartz_surface_create_similar(void
+ *abstract_src,
+ cairo_format_t
+ format,
+ int drawable,
+ int width,
+ int height)
{
return NULL;
}
-
-static void
-_cairo_quartz_surface_destroy(void *abstract_surface)
+static cairo_status_t
+_cairo_quartz_surface_finish(void *abstract_surface)
{
cairo_quartz_surface_t *surface = abstract_surface;
-
-
- if (surface->cgImage)
- {
- CGImageRelease(surface->cgImage);
- }
-
- free(surface);
-}
+ if (surface->image)
+ cairo_surface_destroy(&surface->image->base);
+ if (surface->cgImage)
+ CGImageRelease(surface->cgImage);
-static double
-_cairo_quartz_surface_pixels_per_inch(void *abstract_surface)
-{
-
-
- // TODO - get this from CGDirectDisplay somehow?
- return 96.0;
+ return CAIRO_STATUS_SUCCESS;
}
-
-static cairo_image_surface_t *
-_cairo_quartz_surface_get_image(void *abstract_surface)
+static cairo_status_t
+_cairo_quartz_surface_acquire_source_image(void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
{
- cairo_quartz_surface_t *surface = abstract_surface;
- CGColorSpaceRef colorSpace;
- void *imageData;
- UInt32 imageDataSize, rowBytes;
- CGDataProviderRef dataProvider;
-
-
+ cairo_quartz_surface_t *surface = abstract_surface;
+ CGColorSpaceRef colorSpace;
+ void *imageData;
+ UInt32 imageDataSize, rowBytes;
+ CGDataProviderRef dataProvider;
+
// We keep a cached (cairo_image_surface_t *) in the cairo_quartz_surface_t
// struct. If the window is ever drawn to without going through Cairo, then
// we would need to refetch the pixel data from the window into the cached
// image surface.
- if (surface->image)
- {
+ if (surface->image) {
cairo_surface_reference(&surface->image->base);
- return surface->image;
+ *image_out = surface->image;
+ return CAIRO_STATUS_SUCCESS;
}
-
+
colorSpace = CGColorSpaceCreateDeviceRGB();
-
-
+
+
rowBytes = surface->width * 4;
imageDataSize = rowBytes * surface->height;
imageData = malloc(imageDataSize);
-
- dataProvider = CGDataProviderCreateWithData(NULL, imageData, imageDataSize, ImageDataReleaseFunc);
-
- surface->cgImage = CGImageCreate( surface->width,
- surface->height,
- 8,
- 32,
- rowBytes,
- colorSpace,
- kCGImageAlphaPremultipliedFirst,
- dataProvider,
- NULL,
- false,
- kCGRenderingIntentDefault);
-
-
+
+ dataProvider =
+ CGDataProviderCreateWithData(NULL, imageData, imageDataSize,
+ ImageDataReleaseFunc);
+
+ surface->cgImage = CGImageCreate(surface->width,
+ surface->height,
+ 8,
+ 32,
+ rowBytes,
+ colorSpace,
+ kCGImageAlphaPremultipliedFirst,
+ dataProvider,
+ NULL,
+ false, kCGRenderingIntentDefault);
+
CGColorSpaceRelease(colorSpace);
CGDataProviderRelease(dataProvider);
-
-
+
surface->image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data( imageData,
- CAIRO_FORMAT_ARGB32,
- surface->width,
- surface->height,
- rowBytes);
-
-
+ cairo_image_surface_create_for_data(imageData,
+ CAIRO_FORMAT_ARGB32,
+ surface->width,
+ surface->height, rowBytes);
+
+
// Set the image surface Cairo state to match our own.
_cairo_image_surface_set_repeat(surface->image, surface->base.repeat);
- _cairo_image_surface_set_matrix(surface->image, &(surface->base.matrix));
-
-
- return surface->image;
-}
+ _cairo_image_surface_set_matrix(surface->image,
+ &(surface->base.matrix));
+ *image_out = surface->image;
+ *image_extra = NULL;
-static cairo_status_t
-_cairo_quartz_surface_set_image( void *abstract_surface,
- cairo_image_surface_t *image)
-{
- cairo_quartz_surface_t *surface = abstract_surface;
- cairo_status_t status;
-
-
- if (surface->image == image)
- {
- CGRect rect;
-
-
- rect = CGRectMake(0, 0, surface->width, surface->height);
-
- CGContextDrawImage(surface->context, rect, surface->cgImage);
-
-
- status = CAIRO_STATUS_SUCCESS;
- }
- else
- {
- // TODO - set_image from something other than what we returned from get_image
- status = CAIRO_STATUS_NO_TARGET_SURFACE;
- }
-
-
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
-
static cairo_status_t
-_cairo_quartz_surface_set_matrix(void *abstract_surface, cairo_matrix_t *matrix)
+_cairo_quartz_surface_acquire_dest_image(void *abstract_surface,
+ cairo_rectangle_t * interest_rect,
+ cairo_image_surface_t **
+ image_out,
+ cairo_rectangle_t * image_rect,
+ void **image_extra)
{
cairo_quartz_surface_t *surface = abstract_surface;
- return _cairo_image_surface_set_matrix(surface->image, matrix);
-}
-
+ image_rect->x = 0;
+ image_rect->y = 0;
+ image_rect->width = surface->image->width;
+ image_rect->height = surface->image->height;
-static cairo_status_t
-_cairo_quartz_surface_set_filter(void *abstract_surface, cairo_filter_t filter)
-{
- cairo_quartz_surface_t *surface = abstract_surface;
+ *image_out = surface->image;
- return _cairo_image_surface_set_filter(surface->image, filter);
+ return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_quartz_surface_set_repeat(void *abstract_surface, int repeat)
+static void
+_cairo_quartz_surface_release_dest_image(void *abstract_surface,
+ cairo_rectangle_t *
+ intersect_rect,
+ cairo_image_surface_t * image,
+ cairo_rectangle_t * image_rect,
+ void *image_extra)
{
cairo_quartz_surface_t *surface = abstract_surface;
- return _cairo_image_surface_set_repeat(surface->image, repeat);
-}
-
+ if (surface->image == image) {
+ CGRect rect;
-static cairo_int_status_t
-_cairo_quartz_surface_composite( cairo_operator_t operator,
- cairo_surface_t *generic_src,
- cairo_surface_t *generic_mask,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-
-static cairo_int_status_t
-_cairo_quartz_surface_fill_rectangles( void *abstract_surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
+ rect = CGRectMake(0, 0, surface->width, surface->height);
+ CGContextDrawImage(surface->context, rect, surface->cgImage);
-static cairo_int_status_t
-_cairo_quartz_surface_composite_trapezoids( cairo_operator_t operator,
- cairo_surface_t *generic_src,
- void *abstract_dst,
- int xSrc,
- int ySrc,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ memset(surface->image->data, 0, surface->width * surface->height * 4);
+ }
}
-
static cairo_int_status_t
-_cairo_quartz_surface_copy_page(void *abstract_surface)
+_cairo_quartz_surface_set_clip_region(void *abstract_surface,
+ pixman_region16_t * region)
{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
+ cairo_quartz_surface_t *surface = abstract_surface;
-static cairo_int_status_t
-_cairo_quartz_surface_show_page(void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return _cairo_surface_set_clip_region(&surface->image->base, region);
}
-
static cairo_int_status_t
-_cairo_quartz_surface_set_clip_region( void *abstract_surface,
- pixman_region16_t *region)
+_cairo_quartz_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t * rectangle)
{
cairo_quartz_surface_t *surface = abstract_surface;
- return _cairo_image_surface_set_clip_region(surface->image, region);
-}
-
+ rectangle->x = 0;
+ rectangle->y = 0;
+ rectangle->width = surface->width;
+ rectangle->height = surface->height;
-static cairo_int_status_t
-_cairo_quartz_surface_create_pattern( void *abstract_surface,
- cairo_pattern_t *pattern,
- cairo_box_t *extents)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return CAIRO_STATUS_SUCCESS;
}
-
static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
_cairo_quartz_surface_create_similar,
- _cairo_quartz_surface_destroy,
- _cairo_quartz_surface_pixels_per_inch,
- _cairo_quartz_surface_get_image,
- _cairo_quartz_surface_set_image,
- _cairo_quartz_surface_set_matrix,
- _cairo_quartz_surface_set_filter,
- _cairo_quartz_surface_set_repeat,
- _cairo_quartz_surface_composite,
- _cairo_quartz_surface_fill_rectangles,
- _cairo_quartz_surface_composite_trapezoids,
- _cairo_quartz_surface_copy_page,
- _cairo_quartz_surface_show_page,
+ _cairo_quartz_surface_finish,
+ _cairo_quartz_surface_acquire_source_image,
+ NULL, /* release_source_image */
+ _cairo_quartz_surface_acquire_dest_image,
+ _cairo_quartz_surface_release_dest_image,
+ NULL, /* clone_similar */
+ NULL, /* composite */
+ NULL, /* fill_rectangles */
+ NULL, /* composite_trapezoids */
+ NULL, /* copy_page */
+ NULL, /* show_page */
_cairo_quartz_surface_set_clip_region,
- _cairo_quartz_surface_create_pattern
+ _cairo_quartz_surface_get_extents,
+ NULL /* show_glyphs */
};
-cairo_surface_t *
-cairo_quartz_surface_create( CGContextRef context,
- int width,
- int height)
+cairo_surface_t *cairo_quartz_surface_create(CGContextRef context,
+ int width, int height)
{
cairo_quartz_surface_t *surface;
-
-
+
surface = malloc(sizeof(cairo_quartz_surface_t));
if (surface == NULL)
return NULL;
-
+
_cairo_surface_init(&surface->base, &cairo_quartz_surface_backend);
-
-
- surface->context = context;
-
- surface->width = width;
- surface->height = height;
-
- surface->image = NULL;
-
- surface->cgImage = NULL;
-
-
- // Set up the image surface which Cairo draws into and we blit to & from.
- surface->image = _cairo_quartz_surface_get_image(surface);
-
-
- return (cairo_surface_t *)surface;
-}
+ surface->context = context;
+ surface->width = width;
+ surface->height = height;
+ surface->image = NULL;
+ surface->cgImage = NULL;
-DEPRECATE (cairo_surface_create_for_drawable, cairo_quartz_surface_create);
+ // Set up the image surface which Cairo draws into and we blit to & from.
+ void *foo;
+ _cairo_quartz_surface_acquire_source_image(surface, &surface->image, &foo);
+
+ return (cairo_surface_t *) surface;
+}
diff --git a/src/cairo-quartz.h b/src/cairo-quartz.h
index 5afd46426..6f59f6a79 100644
--- a/src/cairo-quartz.h
+++ b/src/cairo-quartz.h
@@ -39,18 +39,12 @@
#include <cairo.h>
-#ifdef CAIRO_HAS_QUARTZ_SURFACE
+#if CAIRO_HAS_QUARTZ_SURFACE
#include <Carbon/Carbon.h>
CAIRO_BEGIN_DECLS
-void
-cairo_set_target_quartz_context( cairo_t *cr,
- CGContextRef context,
- int width,
- int height);
-
cairo_surface_t *
cairo_quartz_surface_create ( CGContextRef context,
int width,
@@ -58,6 +52,9 @@ cairo_quartz_surface_create ( CGContextRef context,
CAIRO_END_DECLS
+#else /* CAIRO_HAS_QUARTZ_SURFACE */
+# error Cairo was not compiled with support for the quartz backend
#endif /* CAIRO_HAS_QUARTZ_SURFACE */
+
#endif /* CAIRO_QUARTZ_H */
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 330d58b1e..0bcf80cf8 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -38,6 +39,17 @@
#include "cairoint.h"
+struct _cairo_surface_save {
+ cairo_surface_save_t *next;
+ pixman_region16_t *clip_region;
+};
+
+static cairo_status_t
+_cairo_surface_set_clip_region_internal (cairo_surface_t *surface,
+ pixman_region16_t *region,
+ cairo_bool_t copy_region,
+ cairo_bool_t free_existing);
+
void
_cairo_surface_init (cairo_surface_t *surface,
const cairo_surface_backend_t *backend)
@@ -45,22 +57,122 @@ _cairo_surface_init (cairo_surface_t *surface,
surface->backend = backend;
surface->ref_count = 1;
+ surface->finished = FALSE;
- _cairo_matrix_init (&surface->matrix);
- surface->filter = CAIRO_FILTER_NEAREST;
+ _cairo_user_data_array_init (&surface->user_data);
+
+ cairo_matrix_init_identity (&surface->matrix);
+ surface->filter = CAIRO_FILTER_GOOD;
surface->repeat = 0;
+
+ surface->device_x_offset = 0;
+ surface->device_y_offset = 0;
+
+ surface->clip_region = NULL;
+
+ surface->saves = NULL;
+ surface->level = 0;
}
-cairo_surface_t *
-cairo_surface_create_for_image (char *data,
- cairo_format_t format,
- int width,
- int height,
- int stride)
+static cairo_status_t
+_cairo_surface_begin_internal (cairo_surface_t *surface,
+ cairo_bool_t reset_clip)
+{
+ cairo_surface_save_t *save;
+
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
+ save = malloc (sizeof (cairo_surface_save_t));
+ if (!save)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ if (surface->clip_region) {
+ if (reset_clip)
+ {
+ cairo_status_t status;
+
+ save->clip_region = surface->clip_region;
+ status = _cairo_surface_set_clip_region_internal (surface, NULL, FALSE, FALSE);
+ if (!CAIRO_OK (status)) {
+ free (save);
+ return status;
+ }
+ }
+ else
+ {
+ save->clip_region = pixman_region_create ();
+ pixman_region_copy (save->clip_region, surface->clip_region);
+ }
+ } else {
+ save->clip_region = NULL;
+ }
+
+ save->next = surface->saves;
+ surface->saves = save;
+ surface->level++;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/**
+ * _cairo_surface_begin:
+ * @surface: a #cairo_surface_t
+ *
+ * Must be called before beginning to use the surface. State
+ * of the surface like the clip region will be saved then restored
+ * on the matching call _cairo_surface_end().
+ */
+cairo_private cairo_status_t
+_cairo_surface_begin (cairo_surface_t *surface)
+{
+ return _cairo_surface_begin_internal (surface, FALSE);
+}
+
+/**
+ * _cairo_surface_begin_reset_clip:
+ * @surface: a #cairo_surface_t
+ *
+ * Must be called before beginning to use the surface. State
+ * of the surface like the clip region will be saved then restored
+ * on the matching call _cairo_surface_end().
+ *
+ * After the state is saved, the clip region is cleared. This
+ * combination of operations is a little artificial; the caller could
+ * simply call _cairo_surface_set_clip_region (surface, NULL); after
+ * _cairo_surface_save(). Combining the two saves a copy of the clip
+ * region, and also simplifies error handling for the caller.
+ **/
+cairo_private cairo_status_t
+_cairo_surface_begin_reset_clip (cairo_surface_t *surface)
+{
+ return _cairo_surface_begin_internal (surface, TRUE);
+}
+
+/**
+ * _cairo_surface_end:
+ * @surface: a #cairo_surface_t
+ *
+ * Restores any state saved by _cairo_surface_begin()
+ **/
+cairo_private cairo_status_t
+_cairo_surface_end (cairo_surface_t *surface)
{
- return cairo_image_surface_create_for_data (data, format, width, height, stride);
+ cairo_surface_save_t *save;
+ pixman_region16_t *clip_region;
+
+ if (!surface->saves)
+ return CAIRO_STATUS_BAD_NESTING;
+
+ save = surface->saves;
+ surface->saves = save->next;
+ surface->level--;
+
+ clip_region = save->clip_region;
+ free (save);
+
+ return _cairo_surface_set_clip_region_internal (surface, clip_region, FALSE, TRUE);
}
-slim_hidden_def(cairo_surface_create_for_image);
cairo_surface_t *
_cairo_surface_create_similar_scratch (cairo_surface_t *other,
@@ -82,24 +194,20 @@ cairo_surface_create_similar (cairo_surface_t *other,
int width,
int height)
{
- cairo_color_t empty;
-
if (other == NULL)
return NULL;
- _cairo_color_init (&empty);
- _cairo_color_set_rgb (&empty, 0., 0., 0.);
- _cairo_color_set_alpha (&empty, 0.);
-
- return _cairo_surface_create_similar_solid (other, format, width, height, &empty);
+ return _cairo_surface_create_similar_solid (other, format,
+ width, height,
+ CAIRO_COLOR_TRANSPARENT);
}
cairo_surface_t *
-_cairo_surface_create_similar_solid (cairo_surface_t *other,
- cairo_format_t format,
- int width,
- int height,
- cairo_color_t *color)
+_cairo_surface_create_similar_solid (cairo_surface_t *other,
+ cairo_format_t format,
+ int width,
+ int height,
+ const cairo_color_t *color)
{
cairo_status_t status;
cairo_surface_t *surface;
@@ -111,7 +219,7 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other,
surface = cairo_image_surface_create (format, width, height);
status = _cairo_surface_fill_rectangle (surface,
- CAIRO_OPERATOR_SRC, color,
+ CAIRO_OPERATOR_SOURCE, color,
0, 0, width, height);
if (status) {
cairo_surface_destroy (surface);
@@ -140,15 +248,134 @@ cairo_surface_destroy (cairo_surface_t *surface)
if (surface->ref_count)
return;
- if (surface->backend->destroy)
- surface->backend->destroy (surface);
+ cairo_surface_finish (surface);
+
+ _cairo_user_data_array_destroy (&surface->user_data);
+
+ free (surface);
}
slim_hidden_def(cairo_surface_destroy);
-double
-_cairo_surface_pixels_per_inch (cairo_surface_t *surface)
+/**
+ * cairo_surface_finish:
+ * @surface: the #cairo_surface_t to finish
+ *
+ * This function finishes the surface and drops all references to
+ * external resources. For example, for the Xlib backend it means
+ * that cairo will no longer access the drawable, which can be freed.
+ * After calling cairo_surface_finish() the only valid operations on a
+ * surface are getting and setting user data and referencing and
+ * destroying it. Further drawing the the surface will not affect the
+ * surface but set the surface status to
+ * CAIRO_STATUS_SURFACE_FINISHED.
+ *
+ * When the last call to cairo_surface_destroy() decreases the
+ * reference count to zero, cairo will call cairo_surface_finish() if
+ * it hasn't been called already, before freeing the resources
+ * associated with the surface.
+ *
+ * Return value: CAIRO_STATUS_SUCCESS if the surface was finished
+ * successfully, otherwise CAIRO_STATUS_NO_MEMORY or
+ * CAIRO_STATUS_WRITE_ERROR.
+ **/
+cairo_status_t
+cairo_surface_finish (cairo_surface_t *surface)
+{
+ cairo_status_t status;
+
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
+ if (surface->saves)
+ return CAIRO_STATUS_BAD_NESTING;
+
+ if (surface->clip_region) {
+ pixman_region_destroy (surface->clip_region);
+ surface->clip_region = NULL;
+ }
+
+ if (surface->backend->finish) {
+ status = surface->backend->finish (surface);
+ if (status)
+ return status;
+ }
+
+ surface->finished = TRUE;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/**
+ * cairo_surface_get_user_data:
+ * @surface: a #cairo_surface_t
+ * @key: the address of the #cairo_user_data_key_t the user data was
+ * attached to
+ *
+ * Return user data previously attached to @surface using the specified
+ * key. If no user data has been attached with the given key this
+ * function returns %NULL.
+ *
+ * Return value: the user data previously attached or %NULL.
+ **/
+void *
+cairo_surface_get_user_data (cairo_surface_t *surface,
+ const cairo_user_data_key_t *key)
{
- return surface->backend->pixels_per_inch (surface);
+ return _cairo_user_data_array_get_data (&surface->user_data,
+ key);
+}
+
+/**
+ * cairo_surface_set_user_data:
+ * @surface: a #cairo_surface_t
+ * @key: the address of a #cairo_user_data_key_t to attach the user data to
+ * @user_data: the user data to attach to the surface
+ * @destroy: a #cairo_destroy_func_t which will be called when the
+ * surface is destroyed or when new user data is attached using the
+ * same key.
+ *
+ * Attach user data to @surface. To remove user data from a surface,
+ * call this function with the key that was used to set it and %NULL
+ * for @data.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
+ * slot could not be allocated for the user data.
+ **/
+cairo_status_t
+cairo_surface_set_user_data (cairo_surface_t *surface,
+ const cairo_user_data_key_t *key,
+ void *user_data,
+ cairo_destroy_func_t destroy)
+{
+ return _cairo_user_data_array_set_data (&surface->user_data,
+ key, user_data, destroy);
+}
+
+/**
+ * cairo_surface_set_device_offset:
+ * @surface: a #cairo_surface_t
+ * @x_offset: the offset in the X direction, in device units
+ * @y_offset: the offset in the Y direction, in device units
+ *
+ * Sets an offset that is added to the device coordinates determined
+ * by the CTM when drawing to @surface. One use case for this function
+ * is when we want to create a #cairo_surface_t that redirects drawing
+ * for a portion of an onscreen surface to an offscreen surface in a
+ * way that is completely invisible to the user of the cairo
+ * API. Setting a transformation via cairo_translate() isn't
+ * sufficient to do this, since functions like
+ * cairo_device_to_user() will expose the hidden offset.
+ *
+ * Note that the offset only affects drawing to the surface, not using
+ * the surface in a surface pattern.
+ **/
+void
+cairo_surface_set_device_offset (cairo_surface_t *surface,
+ double x_offset,
+ double y_offset)
+{
+ surface->device_x_offset = x_offset;
+ surface->device_y_offset = y_offset;
}
/**
@@ -173,6 +400,8 @@ _cairo_surface_acquire_source_image (cairo_surface_t *surface,
cairo_image_surface_t **image_out,
void **image_extra)
{
+ assert (!surface->finished);
+
return surface->backend->acquire_source_image (surface, image_out, image_extra);
}
@@ -188,7 +417,10 @@ _cairo_surface_release_source_image (cairo_surface_t *surface,
cairo_image_surface_t *image,
void *image_extra)
{
- surface->backend->release_source_image (surface, image, image_extra);
+ assert (!surface->finished);
+
+ if (surface->backend->release_source_image)
+ surface->backend->release_source_image (surface, image, image_extra);
}
/**
@@ -226,6 +458,8 @@ _cairo_surface_acquire_dest_image (cairo_surface_t *surface,
cairo_rectangle_t *image_rect,
void **image_extra)
{
+ assert (!surface->finished);
+
return surface->backend->acquire_dest_image (surface, interest_rect,
image_out, image_rect, image_extra);
}
@@ -249,8 +483,11 @@ _cairo_surface_release_dest_image (cairo_surface_t *surface,
cairo_rectangle_t *image_rect,
void *image_extra)
{
- surface->backend->release_dest_image (surface, interest_rect,
- image, image_rect, image_extra);
+ assert (!surface->finished);
+
+ if (surface->backend->release_dest_image)
+ surface->backend->release_dest_image (surface, interest_rect,
+ image, image_rect, image_extra);
}
/**
@@ -278,9 +515,14 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
cairo_image_surface_t *image;
void *image_extra;
- status = surface->backend->clone_similar (surface, src, clone_out);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
+ if (surface->backend->clone_similar) {
+ status = surface->backend->clone_similar (surface, src, clone_out);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
if (status != CAIRO_STATUS_SUCCESS)
@@ -298,69 +540,6 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
return status;
}
-cairo_status_t
-cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
-{
- if (surface == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- return cairo_matrix_copy (&surface->matrix, matrix);
-}
-slim_hidden_def(cairo_surface_set_matrix);
-
-cairo_status_t
-cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
-{
- if (surface == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- return cairo_matrix_copy (matrix, &surface->matrix);
-}
-slim_hidden_def(cairo_surface_get_matrix);
-
-cairo_status_t
-cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter)
-{
- if (surface == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- surface->filter = filter;
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_filter_t
-cairo_surface_get_filter (cairo_surface_t *surface)
-{
- return surface->filter;
-}
-
-/* XXX: NYI
-cairo_status_t
-cairo_surface_clip_rectangle (cairo_surface_t *surface,
- int x, int y,
- int width, int height)
-{
-
-}
-*/
-
-/* XXX: NYI
-cairo_status_t
-cairo_surface_clip_restore (cairo_surface_t *surface);
-*/
-
-cairo_status_t
-cairo_surface_set_repeat (cairo_surface_t *surface, int repeat)
-{
- if (surface == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- surface->repeat = repeat;
-
- return CAIRO_STATUS_SUCCESS;
-}
-slim_hidden_def(cairo_surface_set_repeat);
-
typedef struct {
cairo_surface_t *dst;
cairo_rectangle_t extents;
@@ -444,14 +623,19 @@ _cairo_surface_composite (cairo_operator_t operator,
{
cairo_int_status_t status;
- status = dst->backend->composite (operator,
- src, mask, dst,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
+ if (dst->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
+ if (dst->backend->composite) {
+ status = dst->backend->composite (operator,
+ src, mask, dst,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
return _fallback_composite (operator,
src, mask, dst,
@@ -462,16 +646,19 @@ _cairo_surface_composite (cairo_operator_t operator,
}
cairo_status_t
-_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_surface_fill_rectangle (cairo_surface_t *surface,
+ cairo_operator_t operator,
+ const cairo_color_t *color,
+ int x,
+ int y,
+ int width,
+ int height)
{
cairo_rectangle_t rect;
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
rect.x = x;
rect.y = y;
rect.width = width;
@@ -505,15 +692,15 @@ _fallback_fill_rectangles (cairo_surface_t *surface,
y2 = rects[0].y + rects[0].height;
for (i = 1; i < num_rects; i++) {
- if (rects[0].x < x1)
- x1 = rects[0].x;
- if (rects[0].y < y1)
- y1 = rects[0].y;
-
- if (rects[0].x + rects[0].width > x2)
- x2 = rects[0].x + rects[0].width;
- if (rects[0].y + rects[0].height > y2)
- y2 = rects[0].y + rects[0].height;
+ if (rects[i].x < x1)
+ x1 = rects[i].x;
+ if (rects[i].y < y1)
+ y1 = rects[i].y;
+
+ if (rects[i].x + rects[i].width > x2)
+ x2 = rects[i].x + rects[i].width;
+ if (rects[i].y + rects[i].height > y2)
+ y2 = rects[i].y + rects[i].height;
}
status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
@@ -560,19 +747,37 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
{
cairo_int_status_t status;
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
if (num_rects == 0)
return CAIRO_STATUS_SUCCESS;
- status = surface->backend->fill_rectangles (surface,
- operator,
- color,
- rects, num_rects);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
+ if (surface->backend->fill_rectangles) {
+ status = surface->backend->fill_rectangles (surface,
+ operator,
+ color,
+ rects, num_rects);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
return _fallback_fill_rectangles (surface, operator, color, rects, num_rects);
}
+cairo_private cairo_int_status_t
+_cairo_surface_fill_path (cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *dst,
+ cairo_path_fixed_t *path)
+{
+ if (dst->backend->fill_path)
+ return dst->backend->fill_path (operator, pattern, dst, path);
+ else
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+
static cairo_status_t
_fallback_composite_trapezoids (cairo_operator_t operator,
cairo_pattern_t *pattern,
@@ -655,14 +860,19 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator,
{
cairo_int_status_t status;
- status = dst->backend->composite_trapezoids (operator,
- pattern, dst,
- src_x, src_y,
- dst_x, dst_y,
- width, height,
- traps, num_traps);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
+ if (dst->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
+ if (dst->backend->composite_trapezoids) {
+ status = dst->backend->composite_trapezoids (operator,
+ pattern, dst,
+ src_x, src_y,
+ dst_x, dst_y,
+ width, height,
+ traps, num_traps);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
return _fallback_composite_trapezoids (operator, pattern, dst,
src_x, src_y,
@@ -674,35 +884,116 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator,
cairo_status_t
_cairo_surface_copy_page (cairo_surface_t *surface)
{
- cairo_int_status_t status;
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
- status = surface->backend->copy_page (surface);
/* It's fine if some backends just don't support this. */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ if (surface->backend->copy_page == NULL)
return CAIRO_STATUS_SUCCESS;
- if (status)
- return status;
- return CAIRO_STATUS_SUCCESS;
+ return surface->backend->copy_page (surface);
}
cairo_status_t
_cairo_surface_show_page (cairo_surface_t *surface)
{
- cairo_int_status_t status;
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
- status = surface->backend->show_page (surface);
/* It's fine if some backends just don't support this. */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ if (surface->backend->show_page == NULL)
return CAIRO_STATUS_SUCCESS;
- if (status)
- return status;
- return CAIRO_STATUS_SUCCESS;
+ return surface->backend->show_page (surface);
}
-cairo_status_t
-_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region)
+static cairo_status_t
+_cairo_surface_set_clip_region_internal (cairo_surface_t *surface,
+ pixman_region16_t *region,
+ cairo_bool_t copy_region,
+ cairo_bool_t free_existing)
{
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
+ if (region == surface->clip_region)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (surface->backend->set_clip_region == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (surface->clip_region) {
+ if (free_existing)
+ pixman_region_destroy (surface->clip_region);
+ surface->clip_region = NULL;
+ }
+
+ if (region) {
+ if (copy_region) {
+ surface->clip_region = pixman_region_create ();
+ pixman_region_copy (surface->clip_region, region);
+ } else
+ surface->clip_region = region;
+ }
+
return surface->backend->set_clip_region (surface, region);
}
+
+cairo_status_t
+_cairo_surface_set_clip_region (cairo_surface_t *surface,
+ pixman_region16_t *region)
+{
+ return _cairo_surface_set_clip_region_internal (surface, region, TRUE, TRUE);
+}
+
+cairo_status_t
+_cairo_surface_get_clip_extents (cairo_surface_t *surface,
+ cairo_rectangle_t *rectangle)
+{
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
+ if (surface->clip_region) {
+ pixman_box16_t *box = pixman_region_extents (surface->clip_region);
+
+ rectangle->x = box->x1;
+ rectangle->y = box->y1;
+ rectangle->width = box->x2 - box->x1;
+ rectangle->height = box->y2 - box->y1;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return surface->backend->get_extents (surface, rectangle);
+}
+
+cairo_status_t
+_cairo_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *dst,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ cairo_status_t status;
+
+ if (dst->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
+ if (dst->backend->show_glyphs)
+ status = dst->backend->show_glyphs (scaled_font, operator, pattern, dst,
+ source_x, source_y,
+ dest_x, dest_y,
+ width, height,
+ glyphs, num_glyphs);
+ else
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return status;
+}
diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index 79c7e16b6..15dfc1bca 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -88,6 +88,43 @@ _cairo_traps_fini (cairo_traps_t *traps)
}
}
+/**
+ * _cairo_traps_init_box:
+ * @traps: a #cairo_traps_t
+ * @box: a box that will be converted to a single trapezoid
+ * to store in @traps.
+ *
+ * Initializes a cairo_traps_t to contain a single rectangular
+ * trapezoid.
+ **/
+cairo_status_t
+_cairo_traps_init_box (cairo_traps_t *traps,
+ cairo_box_t *box)
+{
+ cairo_status_t status;
+
+ _cairo_traps_init (traps);
+
+ status = _cairo_traps_grow_by (traps, 1);
+ if (status)
+ return status;
+
+ traps->num_traps = 1;
+
+ traps->traps[0].top = box->p1.y;
+ traps->traps[0].bottom = box->p2.y;
+ traps->traps[0].left.p1 = box->p1;
+ traps->traps[0].left.p2.x = box->p1.x;
+ traps->traps[0].left.p2.y = box->p2.y;
+ traps->traps[0].right.p1.x = box->p2.x;
+ traps->traps[0].right.p1.y = box->p1.y;
+ traps->traps[0].right.p2 = box->p2;
+
+ traps->extents = *box;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static cairo_status_t
_cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom,
cairo_line_t *left, cairo_line_t *right)
@@ -738,3 +775,65 @@ _cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents)
{
*extents = traps->extents;
}
+
+/**
+ * _cairo_traps_extract_region:
+ * @traps: a #cairo_traps_t
+ * @region: on return, %NULL is stored here if the trapezoids aren't
+ * exactly representable as a pixman region, otherwise a
+ * a pointer to such a region, newly allocated.
+ * (free with pixman region destroy)
+ *
+ * Determines if a set of trapezoids are exactly representable as a
+ * pixman region, and if so creates such a region.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
+ **/
+cairo_status_t
+_cairo_traps_extract_region (cairo_traps_t *traps,
+ pixman_region16_t **region)
+{
+ int i;
+
+ for (i = 0; i < traps->num_traps; i++)
+ if (!(traps->traps[i].left.p1.x == traps->traps[i].left.p2.x
+ && traps->traps[i].right.p1.x == traps->traps[i].right.p2.x
+ && traps->traps[i].left.p1.y == traps->traps[i].right.p1.y
+ && traps->traps[i].left.p2.y == traps->traps[i].right.p2.y
+ && _cairo_fixed_is_integer(traps->traps[i].left.p1.x)
+ && _cairo_fixed_is_integer(traps->traps[i].left.p1.y)
+ && _cairo_fixed_is_integer(traps->traps[i].left.p2.x)
+ && _cairo_fixed_is_integer(traps->traps[i].left.p2.y)
+ && _cairo_fixed_is_integer(traps->traps[i].right.p1.x)
+ && _cairo_fixed_is_integer(traps->traps[i].right.p1.y)
+ && _cairo_fixed_is_integer(traps->traps[i].right.p2.x)
+ && _cairo_fixed_is_integer(traps->traps[i].right.p2.y))) {
+ *region = NULL;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ *region = pixman_region_create ();
+
+ for (i = 0; i < traps->num_traps; i++) {
+ int x = _cairo_fixed_integer_part(traps->traps[i].left.p1.x);
+ int y = _cairo_fixed_integer_part(traps->traps[i].left.p1.y);
+ int width = _cairo_fixed_integer_part(traps->traps[i].right.p1.x) - x;
+ int height = _cairo_fixed_integer_part(traps->traps[i].left.p2.y) - y;
+
+ /* Sometimes we get degenerate trapezoids from the tesellator,
+ * if we call pixman_region_union_rect(), it bizarrly fails on such
+ * an empty rectangle, so skip them.
+ */
+ if (width == 0 || height == 0)
+ continue;
+
+ if (pixman_region_union_rect (*region, *region,
+ x, y, width, height) != PIXMAN_REGION_STATUS_SUCCESS) {
+ pixman_region_destroy (*region);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
diff --git a/src/cairo-unicode.c b/src/cairo-unicode.c
index 92201391a..8929baaac 100644
--- a/src/cairo-unicode.c
+++ b/src/cairo-unicode.c
@@ -117,14 +117,14 @@ static const char utf8_skip_data[256] = {
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
};
-#define UTF8_NEXT_CHAR(p) (char *)((p) + utf8_skip_data[*(unsigned char *)(p)])
+#define UTF8_NEXT_CHAR(p) ((p) + utf8_skip_data[*(unsigned char *)(p)])
/* Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
* If @p does not point to a valid UTF-8 encoded character, results are
* undefined.
**/
static uint32_t
-_utf8_get_char (const char *p)
+_utf8_get_char (const unsigned char *p)
{
int i, mask = 0, len;
uint32_t result;
@@ -142,8 +142,8 @@ _utf8_get_char (const char *p)
* and return (uint32_t)-2 on incomplete trailing character
*/
static uint32_t
-_utf8_get_char_extended (const char *p,
- long max_len)
+_utf8_get_char_extended (const unsigned char *p,
+ long max_len)
{
int i, len;
uint32_t wc = (unsigned char) *p;
@@ -220,14 +220,14 @@ _utf8_get_char_extended (const char *p,
* an invalid sequence was found.
**/
cairo_status_t
-_cairo_utf8_to_ucs4 (const char *str,
- int len,
- uint32_t **result,
- int *items_written)
+_cairo_utf8_to_ucs4 (const unsigned char *str,
+ int len,
+ uint32_t **result,
+ int *items_written)
{
uint32_t *str32 = NULL;
int n_chars, i;
- const char *in;
+ const unsigned char *in;
in = str;
n_chars = 0;
@@ -284,14 +284,14 @@ _cairo_utf8_to_ucs4 (const char *str,
* an invalid sequence was found.
**/
cairo_status_t
-_cairo_utf8_to_utf16 (const char *str,
- int len,
- uint16_t **result,
- int *items_written)
+_cairo_utf8_to_utf16 (const unsigned char *str,
+ int len,
+ uint16_t **result,
+ int *items_written)
{
uint16_t *str16 = NULL;
int n16, i;
- const char *in;
+ const unsigned char *in;
in = str;
n16 = 0;
diff --git a/src/cairo-wideint.h b/src/cairo-wideint.h
index abe36f9d4..3afea5a65 100644
--- a/src/cairo-wideint.h
+++ b/src/cairo-wideint.h
@@ -1,5 +1,5 @@
/*
- * $Id: cairo-wideint.h,v 1.6 2005-01-19 15:11:14 cworth Exp $
+ * $Id: cairo-wideint.h,v 1.10 2005-05-10 19:42:32 cworth Exp $
*
* Copyright © 2004 Keith Packard
*
@@ -38,7 +38,15 @@
#ifndef CAIRO_WIDEINT_H
#define CAIRO_WIDEINT_H
-#include <stdint.h>
+#if HAVE_STDINT_H
+# include <stdint.h>
+#elif HAVE_INTTYPES_H
+# include <inttypes.h>
+#elif HAVE_SYS_INT_TYPES_H
+# include <sys/int_types.h>
+#else
+#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.)
+#endif
/*
* 64-bit datatypes. Two separate implementations, one using
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index 02f0cffd6..78b3ca212 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -34,7 +34,7 @@
#include <string.h>
#include <stdio.h>
-
+#include "cairoint.h"
#include "cairo-win32-private.h"
#ifndef SPI_GETFONTSMOOTHINGTYPE
@@ -47,12 +47,12 @@
#define CLEARTYPE_QUALITY 5
#endif
-const cairo_font_backend_t cairo_win32_font_backend;
+const cairo_scaled_font_backend_t cairo_win32_scaled_font_backend;
#define LOGICAL_SCALE 32
typedef struct {
- cairo_font_t base;
+ cairo_scaled_font_t base;
LOGFONTW logfont;
@@ -93,73 +93,69 @@ typedef struct {
*/
int em_square;
- HFONT scaled_font;
- HFONT unscaled_font;
+ HFONT scaled_hfont;
+ HFONT unscaled_hfont;
-} cairo_win32_font_t;
+} cairo_win32_scaled_font_t;
#define NEARLY_ZERO(d) (fabs(d) < (1. / 65536.))
static void
-_compute_transform (cairo_win32_font_t *font,
- cairo_font_scale_t *sc)
+_compute_transform (cairo_win32_scaled_font_t *scaled_font,
+ cairo_matrix_t *sc)
{
- if (NEARLY_ZERO (sc->matrix[0][1]) && NEARLY_ZERO (sc->matrix[1][0])) {
- font->preserve_axes = TRUE;
- font->x_scale = sc->matrix[0][0];
- font->swap_x = (sc->matrix[0][0] < 0);
- font->y_scale = sc->matrix[1][1];
- font->swap_y = (sc->matrix[1][1] < 0);
- font->swap_axes = FALSE;
+ if (NEARLY_ZERO (sc->yx) && NEARLY_ZERO (sc->xy)) {
+ scaled_font->preserve_axes = TRUE;
+ scaled_font->x_scale = sc->xx;
+ scaled_font->swap_x = (sc->xx < 0);
+ scaled_font->y_scale = sc->yy;
+ scaled_font->swap_y = (sc->yy < 0);
+ scaled_font->swap_axes = FALSE;
- } else if (NEARLY_ZERO (sc->matrix[0][0]) && NEARLY_ZERO (sc->matrix[1][1])) {
- font->preserve_axes = TRUE;
- font->x_scale = sc->matrix[0][1];
- font->swap_x = (sc->matrix[0][1] < 0);
- font->y_scale = sc->matrix[1][0];
- font->swap_y = (sc->matrix[1][0] < 0);
- font->swap_axes = TRUE;
+ } else if (NEARLY_ZERO (sc->xx) && NEARLY_ZERO (sc->yy)) {
+ scaled_font->preserve_axes = TRUE;
+ scaled_font->x_scale = sc->yx;
+ scaled_font->swap_x = (sc->yx < 0);
+ scaled_font->y_scale = sc->xy;
+ scaled_font->swap_y = (sc->xy < 0);
+ scaled_font->swap_axes = TRUE;
} else {
- font->preserve_axes = FALSE;
- font->swap_x = font->swap_y = font->swap_axes = FALSE;
+ scaled_font->preserve_axes = FALSE;
+ scaled_font->swap_x = scaled_font->swap_y = scaled_font->swap_axes = FALSE;
}
- if (font->preserve_axes) {
- if (font->swap_x)
- font->x_scale = - font->x_scale;
- if (font->swap_y)
- font->y_scale = - font->y_scale;
+ if (scaled_font->preserve_axes) {
+ if (scaled_font->swap_x)
+ scaled_font->x_scale = - scaled_font->x_scale;
+ if (scaled_font->swap_y)
+ scaled_font->y_scale = - scaled_font->y_scale;
- font->logical_scale = LOGICAL_SCALE * font->y_scale;
- font->logical_size = LOGICAL_SCALE * floor (font->y_scale + 0.5);
+ scaled_font->logical_scale = LOGICAL_SCALE * scaled_font->y_scale;
+ scaled_font->logical_size = LOGICAL_SCALE * floor (scaled_font->y_scale + 0.5);
}
/* The font matrix has x and y "scale" components which we extract and
* use as character scale values.
*/
- cairo_matrix_set_affine (&font->logical_to_device,
- sc->matrix[0][0],
- sc->matrix[0][1],
- sc->matrix[1][0],
- sc->matrix[1][1],
- 0, 0);
-
- if (!font->preserve_axes) {
- _cairo_matrix_compute_scale_factors (&font->logical_to_device,
- &font->x_scale, &font->y_scale,
+ cairo_matrix_init (&scaled_font->logical_to_device,
+ sc->xx, sc->yx, sc->xy, sc->yy, 0, 0);
+
+ if (!scaled_font->preserve_axes) {
+ _cairo_matrix_compute_scale_factors (&scaled_font->logical_to_device,
+ &scaled_font->x_scale, &scaled_font->y_scale,
TRUE); /* XXX: Handle vertical text */
- font->logical_size = floor (LOGICAL_SCALE * font->y_scale + 0.5);
- font->logical_scale = LOGICAL_SCALE * font->y_scale;
+ scaled_font->logical_size = floor (LOGICAL_SCALE * scaled_font->y_scale + 0.5);
+ scaled_font->logical_scale = LOGICAL_SCALE * scaled_font->y_scale;
}
- cairo_matrix_scale (&font->logical_to_device,
- 1.0 / font->logical_scale, 1.0 / font->logical_scale);
+ cairo_matrix_scale (&scaled_font->logical_to_device,
+ 1.0 / scaled_font->logical_scale, 1.0 / scaled_font->logical_scale);
- font->device_to_logical = font->logical_to_device;
- if (!CAIRO_OK (cairo_matrix_invert (&font->device_to_logical)))
- cairo_matrix_set_identity (&font->device_to_logical);
+ scaled_font->device_to_logical = scaled_font->logical_to_device;
+ if (!CAIRO_OK (cairo_matrix_invert (&scaled_font->device_to_logical)))
+ cairo_matrix_init_identity (&scaled_font->device_to_logical);
}
static BYTE
@@ -202,53 +198,56 @@ _get_system_quality (void)
return DEFAULT_QUALITY;
}
-static cairo_font_t *
-_win32_font_create (LOGFONTW *logfont,
- cairo_font_scale_t *scale)
+static cairo_scaled_font_t *
+_win32_scaled_font_create (LOGFONTW *logfont,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm)
{
- cairo_win32_font_t *f;
+ cairo_win32_scaled_font_t *f;
+ cairo_matrix_t scale;
- f = malloc (sizeof(cairo_win32_font_t));
+ f = malloc (sizeof(cairo_win32_scaled_font_t));
if (f == NULL)
return NULL;
f->logfont = *logfont;
f->quality = _get_system_quality ();
f->em_square = 0;
- f->scaled_font = NULL;
- f->unscaled_font = NULL;
+ f->scaled_hfont = NULL;
+ f->unscaled_hfont = NULL;
- _compute_transform (f, scale);
-
- _cairo_font_init ((cairo_font_t *)f, scale, &cairo_win32_font_backend);
+ cairo_matrix_multiply (&scale, font_matrix, ctm);
+ _compute_transform (f, &scale);
+
+ _cairo_scaled_font_init (&f->base, font_matrix, ctm, &cairo_win32_scaled_font_backend);
- return (cairo_font_t *)f;
+ return &f->base;
}
static cairo_status_t
-_win32_font_set_world_transform (cairo_win32_font_t *font,
- HDC hdc)
+_win32_scaled_font_set_world_transform (cairo_win32_scaled_font_t *scaled_font,
+ HDC hdc)
{
XFORM xform;
- xform.eM11 = font->logical_to_device.m[0][0];
- xform.eM21 = font->logical_to_device.m[1][0];
- xform.eM12 = font->logical_to_device.m[0][1];
- xform.eM22 = font->logical_to_device.m[1][1];
- xform.eDx = font->logical_to_device.m[2][0];
- xform.eDy = font->logical_to_device.m[2][1];
+ xform.eM11 = scaled_font->logical_to_device.xx;
+ xform.eM21 = scaled_font->logical_to_device.xy;
+ xform.eM12 = scaled_font->logical_to_device.yx;
+ xform.eM22 = scaled_font->logical_to_device.yy;
+ xform.eDx = scaled_font->logical_to_device.x0;
+ xform.eDy = scaled_font->logical_to_device.y0;
if (!SetWorldTransform (hdc, &xform))
- return _cairo_win32_print_gdi_error ("_win32_font_set_world_transform");
+ return _cairo_win32_print_gdi_error ("_win32_scaled_font_set_world_transform");
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_win32_font_set_identity_transform (HDC hdc)
+_win32_scaled_font_set_identity_transform (HDC hdc)
{
if (!ModifyWorldTransform (hdc, NULL, MWT_IDENTITY))
- return _cairo_win32_print_gdi_error ("_win32_font_set_identity_transform");
+ return _cairo_win32_print_gdi_error ("_win32_scaled_font_set_identity_transform");
return CAIRO_STATUS_SUCCESS;
}
@@ -276,48 +275,48 @@ _get_global_font_dc (void)
}
static HFONT
-_win32_font_get_scaled_font (cairo_win32_font_t *font)
+_win32_scaled_font_get_scaled_hfont (cairo_win32_scaled_font_t *scaled_font)
{
- if (!font->scaled_font) {
- LOGFONTW logfont = font->logfont;
- logfont.lfHeight = font->logical_size;
+ if (!scaled_font->scaled_hfont) {
+ LOGFONTW logfont = scaled_font->logfont;
+ logfont.lfHeight = scaled_font->logical_size;
logfont.lfWidth = 0;
logfont.lfEscapement = 0;
logfont.lfOrientation = 0;
- logfont.lfQuality = font->quality;
+ logfont.lfQuality = scaled_font->quality;
- font->scaled_font = CreateFontIndirectW (&logfont);
- if (!font->scaled_font) {
- _cairo_win32_print_gdi_error ("_win32_font_get_scaled_font");
+ scaled_font->scaled_hfont = CreateFontIndirectW (&logfont);
+ if (!scaled_font->scaled_hfont) {
+ _cairo_win32_print_gdi_error ("_win32_scaled_font_get_scaled_hfont");
return NULL;
}
}
- return font->scaled_font;
+ return scaled_font->scaled_hfont;
}
static HFONT
-_win32_font_get_unscaled_font (cairo_win32_font_t *font,
- HDC hdc)
+_win32_scaled_font_get_unscaled_hfont (cairo_win32_scaled_font_t *scaled_font,
+ HDC hdc)
{
- if (!font->unscaled_font) {
+ if (!scaled_font->unscaled_hfont) {
OUTLINETEXTMETRIC *otm;
unsigned int otm_size;
- HFONT scaled_font;
+ HFONT scaled_hfont;
LOGFONTW logfont;
- scaled_font = _win32_font_get_scaled_font (font);
- if (!scaled_font)
+ scaled_hfont = _win32_scaled_font_get_scaled_hfont (scaled_font);
+ if (!scaled_hfont)
return NULL;
- if (!SelectObject (hdc, scaled_font)) {
- _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:SelectObject");
+ if (!SelectObject (hdc, scaled_hfont)) {
+ _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:SelectObject");
return NULL;
}
otm_size = GetOutlineTextMetrics (hdc, 0, NULL);
if (!otm_size) {
- _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:GetOutlineTextMetrics");
+ _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:GetOutlineTextMetrics");
return NULL;
}
@@ -326,48 +325,48 @@ _win32_font_get_unscaled_font (cairo_win32_font_t *font,
return NULL;
if (!GetOutlineTextMetrics (hdc, otm_size, otm)) {
- _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:GetOutlineTextMetrics");
+ _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:GetOutlineTextMetrics");
free (otm);
return NULL;
}
- font->em_square = otm->otmEMSquare;
+ scaled_font->em_square = otm->otmEMSquare;
free (otm);
- logfont = font->logfont;
- logfont.lfHeight = font->em_square;
+ logfont = scaled_font->logfont;
+ logfont.lfHeight = scaled_font->em_square;
logfont.lfWidth = 0;
logfont.lfEscapement = 0;
logfont.lfOrientation = 0;
- logfont.lfQuality = font->quality;
+ logfont.lfQuality = scaled_font->quality;
- font->unscaled_font = CreateFontIndirectW (&logfont);
- if (!font->unscaled_font) {
- _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:CreateIndirect");
+ scaled_font->unscaled_hfont = CreateFontIndirectW (&logfont);
+ if (!scaled_font->unscaled_hfont) {
+ _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:CreateIndirect");
return NULL;
}
}
- return font->unscaled_font;
+ return scaled_font->unscaled_hfont;
}
static cairo_status_t
-_cairo_win32_font_select_unscaled_font (cairo_font_t *font,
- HDC hdc)
+_cairo_win32_scaled_font_select_unscaled_font (cairo_scaled_font_t *scaled_font,
+ HDC hdc)
{
cairo_status_t status;
HFONT hfont;
HFONT old_hfont = NULL;
- hfont = _win32_font_get_unscaled_font ((cairo_win32_font_t *)font, hdc);
+ hfont = _win32_scaled_font_get_unscaled_hfont ((cairo_win32_scaled_font_t *)scaled_font, hdc);
if (!hfont)
return CAIRO_STATUS_NO_MEMORY;
old_hfont = SelectObject (hdc, hfont);
if (!old_hfont)
- return _cairo_win32_print_gdi_error ("_cairo_win32_font_select_unscaled_font");
+ return _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_select_unscaled_font");
- status = _win32_font_set_identity_transform (hdc);
+ status = _win32_scaled_font_set_identity_transform (hdc);
if (!CAIRO_OK (status)) {
SelectObject (hdc, old_hfont);
return status;
@@ -379,21 +378,22 @@ _cairo_win32_font_select_unscaled_font (cairo_font_t *font,
}
static void
-_cairo_win32_font_done_unscaled_font (cairo_font_t *font)
+_cairo_win32_scaled_font_done_unscaled_font (cairo_scaled_font_t *scaled_font)
{
}
/* implement the font backend interface */
static cairo_status_t
-_cairo_win32_font_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight,
- cairo_font_scale_t *scale,
- cairo_font_t **font_out)
+_cairo_win32_scaled_font_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ cairo_scaled_font_t **scaled_font_out)
{
LOGFONTW logfont;
- cairo_font_t *font;
+ cairo_scaled_font_t *scaled_font;
uint16_t *face_name;
int face_name_len;
cairo_status_t status;
@@ -451,47 +451,40 @@ _cairo_win32_font_create (const char *family,
if (!logfont.lfFaceName)
return CAIRO_STATUS_NO_MEMORY;
- font = _win32_font_create (&logfont, scale);
- if (!font)
+ scaled_font = _win32_scaled_font_create (&logfont, font_matrix, ctm);
+ if (!scaled_font)
return CAIRO_STATUS_NO_MEMORY;
- *font_out = font;
+ *scaled_font_out = scaled_font;
return CAIRO_STATUS_SUCCESS;
}
static void
-_cairo_win32_font_destroy_font (void *abstract_font)
+_cairo_win32_scaled_font_destroy (void *abstract_font)
{
- cairo_win32_font_t *font = abstract_font;
+ cairo_win32_scaled_font_t *scaled_font = abstract_font;
- if (font->scaled_font)
- DeleteObject (font->scaled_font);
+ if (scaled_font->scaled_hfont)
+ DeleteObject (scaled_font->scaled_hfont);
- if (font->unscaled_font)
- DeleteObject (font->unscaled_font);
-
- free (font);
-}
-
-static void
-_cairo_win32_font_destroy_unscaled_font (void *abstract_font)
-{
+ if (scaled_font->unscaled_hfont)
+ DeleteObject (scaled_font->unscaled_hfont);
}
static void
-_cairo_win32_font_get_glyph_cache_key (void *abstract_font,
- cairo_glyph_cache_key_t *key)
+_cairo_win32_scaled_font_get_glyph_cache_key (void *abstract_font,
+ cairo_glyph_cache_key_t *key)
{
}
static cairo_status_t
-_cairo_win32_font_text_to_glyphs (void *abstract_font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs)
+_cairo_win32_scaled_font_text_to_glyphs (void *abstract_font,
+ const char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs)
{
- cairo_win32_font_t *font = abstract_font;
+ cairo_win32_scaled_font_t *scaled_font = abstract_font;
uint16_t *utf16;
int n16;
GCP_RESULTSW gcp_results;
@@ -524,7 +517,7 @@ _cairo_win32_font_text_to_glyphs (void *abstract_font,
goto FAIL1;
}
- status = cairo_win32_font_select_font (&font->base, hdc);
+ status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
if (!CAIRO_OK (status))
goto FAIL1;
@@ -553,7 +546,7 @@ _cairo_win32_font_text_to_glyphs (void *abstract_font,
0,
&gcp_results,
GCP_DIACRITIC | GCP_LIGATE | GCP_GLYPHSHAPE | GCP_REORDER)) {
- status = _cairo_win32_print_gdi_error ("_cairo_win32_font_text_to_glyphs");
+ status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_text_to_glyphs");
goto FAIL2;
}
@@ -582,7 +575,7 @@ _cairo_win32_font_text_to_glyphs (void *abstract_font,
(*glyphs)[i].x = x_pos ;
(*glyphs)[i].y = 0;
- x_pos += dx[i] / font->logical_scale;
+ x_pos += dx[i] / scaled_font->logical_scale;
}
FAIL2:
@@ -591,7 +584,7 @@ _cairo_win32_font_text_to_glyphs (void *abstract_font,
if (dx)
free (dx);
- cairo_win32_font_done_font (&font->base);
+ cairo_win32_scaled_font_done_font (&scaled_font->base);
FAIL1:
free (utf16);
@@ -600,10 +593,10 @@ _cairo_win32_font_text_to_glyphs (void *abstract_font,
}
static cairo_status_t
-_cairo_win32_font_font_extents (void *abstract_font,
- cairo_font_extents_t *extents)
+_cairo_win32_scaled_font_font_extents (void *abstract_font,
+ cairo_font_extents_t *extents)
{
- cairo_win32_font_t *font = abstract_font;
+ cairo_win32_scaled_font_t *scaled_font = abstract_font;
cairo_status_t status;
TEXTMETRIC metrics;
HDC hdc;
@@ -612,21 +605,21 @@ _cairo_win32_font_font_extents (void *abstract_font,
if (!hdc)
return CAIRO_STATUS_NO_MEMORY;
- if (font->preserve_axes) {
+ if (scaled_font->preserve_axes) {
/* For 90-degree rotations (including 0), we get the metrics
* from the GDI in logical space, then convert back to font space
*/
- status = cairo_win32_font_select_font (&font->base, hdc);
+ status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
if (!CAIRO_OK (status))
return status;
GetTextMetrics (hdc, &metrics);
- cairo_win32_font_done_font (&font->base);
+ cairo_win32_scaled_font_done_font (&scaled_font->base);
- extents->ascent = metrics.tmAscent / font->logical_scale;
- extents->descent = metrics.tmDescent / font->logical_scale;
+ extents->ascent = metrics.tmAscent / scaled_font->logical_scale;
+ extents->descent = metrics.tmDescent / scaled_font->logical_scale;
- extents->height = (metrics.tmHeight + metrics.tmExternalLeading) / font->logical_scale;
- extents->max_x_advance = metrics.tmMaxCharWidth / font->logical_scale;
+ extents->height = (metrics.tmHeight + metrics.tmExternalLeading) / scaled_font->logical_scale;
+ extents->max_x_advance = metrics.tmMaxCharWidth / scaled_font->logical_scale;
extents->max_y_advance = 0;
} else {
@@ -635,16 +628,16 @@ _cairo_win32_font_font_extents (void *abstract_font,
* transformed font are inexplicably large and we want to
* avoid them.
*/
- status = _cairo_win32_font_select_unscaled_font (&font->base, hdc);
+ status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc);
if (!CAIRO_OK (status))
return status;
GetTextMetrics (hdc, &metrics);
- _cairo_win32_font_done_unscaled_font (&font->base);
+ _cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base);
- extents->ascent = (double)metrics.tmAscent / font->em_square;
- extents->descent = metrics.tmDescent * font->em_square;
- extents->height = (double)(metrics.tmHeight + metrics.tmExternalLeading) / font->em_square;
- extents->max_x_advance = (double)(metrics.tmMaxCharWidth) / font->em_square;
+ extents->ascent = (double)metrics.tmAscent / scaled_font->em_square;
+ extents->descent = metrics.tmDescent * scaled_font->em_square;
+ extents->height = (double)(metrics.tmHeight + metrics.tmExternalLeading) / scaled_font->em_square;
+ extents->max_x_advance = (double)(metrics.tmMaxCharWidth) / scaled_font->em_square;
extents->max_y_advance = 0;
}
@@ -653,12 +646,12 @@ _cairo_win32_font_font_extents (void *abstract_font,
}
static cairo_status_t
-_cairo_win32_font_glyph_extents (void *abstract_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
+_cairo_win32_scaled_font_glyph_extents (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
{
- cairo_win32_font_t *font = abstract_font;
+ cairo_win32_scaled_font_t *scaled_font = abstract_font;
static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
GLYPHMETRICS metrics;
cairo_status_t status;
@@ -674,39 +667,39 @@ _cairo_win32_font_glyph_extents (void *abstract_font,
*/
assert (num_glyphs == 1);
- if (font->preserve_axes) {
+ if (scaled_font->preserve_axes) {
/* If we aren't rotating / skewing the axes, then we get the metrics
* from the GDI in device space and convert to font space.
*/
- status = cairo_win32_font_select_font (&font->base, hdc);
+ status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
if (!CAIRO_OK (status))
return status;
GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX,
&metrics, 0, NULL, &matrix);
- cairo_win32_font_done_font (&font->base);
-
- if (font->swap_axes) {
- extents->x_bearing = - metrics.gmptGlyphOrigin.y / font->y_scale;
- extents->y_bearing = metrics.gmptGlyphOrigin.x / font->x_scale;
- extents->width = metrics.gmBlackBoxY / font->y_scale;
- extents->height = metrics.gmBlackBoxX / font->x_scale;
- extents->x_advance = metrics.gmCellIncY / font->x_scale;
- extents->y_advance = metrics.gmCellIncX / font->y_scale;
+ cairo_win32_scaled_font_done_font (&scaled_font->base);
+
+ if (scaled_font->swap_axes) {
+ extents->x_bearing = - metrics.gmptGlyphOrigin.y / scaled_font->y_scale;
+ extents->y_bearing = metrics.gmptGlyphOrigin.x / scaled_font->x_scale;
+ extents->width = metrics.gmBlackBoxY / scaled_font->y_scale;
+ extents->height = metrics.gmBlackBoxX / scaled_font->x_scale;
+ extents->x_advance = metrics.gmCellIncY / scaled_font->x_scale;
+ extents->y_advance = metrics.gmCellIncX / scaled_font->y_scale;
} else {
- extents->x_bearing = metrics.gmptGlyphOrigin.x / font->x_scale;
- extents->y_bearing = - metrics.gmptGlyphOrigin.y / font->y_scale;
- extents->width = metrics.gmBlackBoxX / font->x_scale;
- extents->height = metrics.gmBlackBoxY / font->y_scale;
- extents->x_advance = metrics.gmCellIncX / font->x_scale;
- extents->y_advance = metrics.gmCellIncY / font->y_scale;
+ extents->x_bearing = metrics.gmptGlyphOrigin.x / scaled_font->x_scale;
+ extents->y_bearing = - metrics.gmptGlyphOrigin.y / scaled_font->y_scale;
+ extents->width = metrics.gmBlackBoxX / scaled_font->x_scale;
+ extents->height = metrics.gmBlackBoxY / scaled_font->y_scale;
+ extents->x_advance = metrics.gmCellIncX / scaled_font->x_scale;
+ extents->y_advance = metrics.gmCellIncY / scaled_font->y_scale;
}
- if (font->swap_x) {
+ if (scaled_font->swap_x) {
extents->x_bearing = (- extents->x_bearing - extents->width);
extents->x_advance = - extents->x_advance;
}
- if (font->swap_y) {
+ if (scaled_font->swap_y) {
extents->y_bearing = (- extents->y_bearing - extents->height);
extents->y_advance = - extents->y_advance;
}
@@ -715,17 +708,17 @@ _cairo_win32_font_glyph_extents (void *abstract_font,
/* For all other transformations, we use the design metrics
* of the font.
*/
- status = _cairo_win32_font_select_unscaled_font (&font->base, hdc);
+ status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc);
GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX,
&metrics, 0, NULL, &matrix);
- _cairo_win32_font_done_unscaled_font (&font->base);
-
- extents->x_bearing = (double)metrics.gmptGlyphOrigin.x / font->em_square;
- extents->y_bearing = (double)metrics.gmptGlyphOrigin.y / font->em_square;
- extents->width = (double)metrics.gmBlackBoxX / font->em_square;
- extents->height = (double)metrics.gmBlackBoxY / font->em_square;
- extents->x_advance = (double)metrics.gmCellIncX / font->em_square;
- extents->y_advance = (double)metrics.gmCellIncY / font->em_square;
+ _cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base);
+
+ extents->x_bearing = (double)metrics.gmptGlyphOrigin.x / scaled_font->em_square;
+ extents->y_bearing = (double)metrics.gmptGlyphOrigin.y / scaled_font->em_square;
+ extents->width = (double)metrics.gmBlackBoxX / scaled_font->em_square;
+ extents->height = (double)metrics.gmBlackBoxY / scaled_font->em_square;
+ extents->x_advance = (double)metrics.gmCellIncX / scaled_font->em_square;
+ extents->y_advance = (double)metrics.gmCellIncY / scaled_font->em_square;
}
return CAIRO_STATUS_SUCCESS;
@@ -733,13 +726,13 @@ _cairo_win32_font_glyph_extents (void *abstract_font,
static cairo_status_t
-_cairo_win32_font_glyph_bbox (void *abstract_font,
- const cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox)
+_cairo_win32_scaled_font_glyph_bbox (void *abstract_font,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
{
static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
- cairo_win32_font_t *font = abstract_font;
+ cairo_win32_scaled_font_t *scaled_font = abstract_font;
int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
if (num_glyphs > 0) {
@@ -751,7 +744,7 @@ _cairo_win32_font_glyph_bbox (void *abstract_font,
if (!hdc)
return CAIRO_STATUS_NO_MEMORY;
- status = cairo_win32_font_select_font (&font->base, hdc);
+ status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
if (!CAIRO_OK (status))
return status;
@@ -772,7 +765,7 @@ _cairo_win32_font_glyph_bbox (void *abstract_font,
y2 = y - metrics.gmptGlyphOrigin.y + metrics.gmBlackBoxY;
}
- cairo_win32_font_done_font (&font->base);
+ cairo_win32_scaled_font_done_font (&scaled_font->base);
}
bbox->p1.x = _cairo_fixed_from_int (x1);
@@ -784,7 +777,7 @@ _cairo_win32_font_glyph_bbox (void *abstract_font,
}
typedef struct {
- cairo_win32_font_t *font;
+ cairo_win32_scaled_font_t *scaled_font;
HDC hdc;
cairo_array_t glyphs;
@@ -796,12 +789,12 @@ typedef struct {
} cairo_glyph_state_t;
static void
-_start_glyphs (cairo_glyph_state_t *state,
- cairo_win32_font_t *font,
- HDC hdc)
+_start_glyphs (cairo_glyph_state_t *state,
+ cairo_win32_scaled_font_t *scaled_font,
+ HDC hdc)
{
state->hdc = hdc;
- state->font = font;
+ state->scaled_font = scaled_font;
_cairo_array_init (&state->glyphs, sizeof (WCHAR));
_cairo_array_init (&state->dx, sizeof (int));
@@ -841,7 +834,7 @@ _add_glyph (cairo_glyph_state_t *state,
WCHAR glyph_index = index;
int logical_x, logical_y;
- cairo_matrix_transform_point (&state->font->device_to_logical, &user_x, &user_y);
+ cairo_matrix_transform_point (&state->scaled_font->device_to_logical, &user_x, &user_y);
logical_x = floor (user_x + 0.5);
logical_y = floor (user_y + 0.5);
@@ -881,13 +874,13 @@ _finish_glyphs (cairo_glyph_state_t *state)
}
static cairo_status_t
-_draw_glyphs_on_surface (cairo_win32_surface_t *surface,
- cairo_win32_font_t *font,
- COLORREF color,
- int x_offset,
- int y_offset,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
+_draw_glyphs_on_surface (cairo_win32_surface_t *surface,
+ cairo_win32_scaled_font_t *scaled_font,
+ COLORREF color,
+ int x_offset,
+ int y_offset,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
{
cairo_glyph_state_t state;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
@@ -896,7 +889,7 @@ _draw_glyphs_on_surface (cairo_win32_surface_t *surface,
if (!SaveDC (surface->dc))
return _cairo_win32_print_gdi_error ("_draw_glyphs_on_surface:SaveDC");
- status = cairo_win32_font_select_font (&font->base, surface->dc);
+ status = cairo_win32_scaled_font_select_font (&scaled_font->base, surface->dc);
if (!CAIRO_OK (status))
goto FAIL1;
@@ -904,7 +897,7 @@ _draw_glyphs_on_surface (cairo_win32_surface_t *surface,
SetTextAlign (surface->dc, TA_BASELINE | TA_LEFT);
SetBkMode (surface->dc, TRANSPARENT);
- _start_glyphs (&state, font, surface->dc);
+ _start_glyphs (&state, scaled_font, surface->dc);
for (i = 0; i < num_glyphs; i++) {
status = _add_glyph (&state, glyphs[i].index,
@@ -915,7 +908,7 @@ _draw_glyphs_on_surface (cairo_win32_surface_t *surface,
FAIL2:
_finish_glyphs (&state);
- cairo_win32_font_done_font (&font->base);
+ cairo_win32_scaled_font_done_font (&scaled_font->base);
FAIL1:
RestoreDC (surface->dc, 1);
@@ -986,20 +979,20 @@ _compute_a8_mask (cairo_win32_surface_t *mask_surface)
}
static cairo_status_t
-_cairo_win32_font_show_glyphs (void *abstract_font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *generic_surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
+_cairo_win32_scaled_font_show_glyphs (void *abstract_font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *generic_surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
{
- cairo_win32_font_t *font = abstract_font;
+ cairo_win32_scaled_font_t *scaled_font = abstract_font;
cairo_win32_surface_t *surface = (cairo_win32_surface_t *)generic_surface;
cairo_status_t status;
@@ -1009,8 +1002,7 @@ _cairo_win32_font_show_glyphs (void *abstract_font,
if (_cairo_surface_is_win32 (generic_surface) &&
surface->format == CAIRO_FORMAT_RGB24 &&
operator == CAIRO_OPERATOR_OVER &&
- pattern->type == CAIRO_PATTERN_SOLID &&
- _cairo_pattern_is_opaque (pattern)) {
+ _cairo_pattern_is_opaque_solid (pattern)) {
cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)pattern;
@@ -1019,11 +1011,12 @@ _cairo_win32_font_show_glyphs (void *abstract_font,
*/
COLORREF new_color;
- new_color = RGB (((int)(0xffff * solid_pattern->red)) >> 8,
- ((int)(0xffff * solid_pattern->green)) >> 8,
- ((int)(0xffff * solid_pattern->blue)) >> 8);
+ /* XXX Use the unpremultiplied or premultiplied color? */
+ new_color = RGB (((int)solid_pattern->color.red_short) >> 8,
+ ((int)solid_pattern->color.green_short) >> 8,
+ ((int)solid_pattern->color.blue_short) >> 8);
- status = _draw_glyphs_on_surface (surface, font, new_color,
+ status = _draw_glyphs_on_surface (surface, scaled_font, new_color,
0, 0,
glyphs, num_glyphs);
@@ -1050,11 +1043,11 @@ _cairo_win32_font_show_glyphs (void *abstract_font,
r.bottom = height;
FillRect (tmp_surface->dc, &r, GetStockObject (WHITE_BRUSH));
- _draw_glyphs_on_surface (tmp_surface, font, RGB (0, 0, 0),
+ _draw_glyphs_on_surface (tmp_surface, scaled_font, RGB (0, 0, 0),
dest_x, dest_y,
glyphs, num_glyphs);
- if (font->quality == CLEARTYPE_QUALITY) {
+ if (scaled_font->quality == CLEARTYPE_QUALITY) {
/* For ClearType, we need a 4-channel mask. If we are compositing on
* a surface with alpha, we need to compute the alpha channel of
* the mask (we just copy the green channel). But for a destination
@@ -1101,84 +1094,109 @@ _cairo_win32_font_show_glyphs (void *abstract_font,
}
static cairo_status_t
-_cairo_win32_font_glyph_path (void *abstract_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path)
+_cairo_win32_scaled_font_glyph_path (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_fixed_t *path)
{
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_win32_font_create_glyph (cairo_image_glyph_cache_entry_t *val)
-{
- return CAIRO_STATUS_NO_MEMORY;
-}
+const cairo_scaled_font_backend_t cairo_win32_scaled_font_backend = {
+ _cairo_win32_scaled_font_create,
+ _cairo_win32_scaled_font_destroy,
+ _cairo_win32_scaled_font_font_extents,
+ _cairo_win32_scaled_font_text_to_glyphs,
+ _cairo_win32_scaled_font_glyph_extents,
+ _cairo_win32_scaled_font_glyph_bbox,
+ _cairo_win32_scaled_font_show_glyphs,
+ _cairo_win32_scaled_font_glyph_path,
+ _cairo_win32_scaled_font_get_glyph_cache_key,
+};
+
+/* cairo_win32_font_face_t */
-const cairo_font_backend_t cairo_win32_font_backend = {
- _cairo_win32_font_create,
- _cairo_win32_font_destroy_font,
- _cairo_win32_font_destroy_unscaled_font,
- _cairo_win32_font_font_extents,
- _cairo_win32_font_text_to_glyphs,
- _cairo_win32_font_glyph_extents,
- _cairo_win32_font_glyph_bbox,
- _cairo_win32_font_show_glyphs,
- _cairo_win32_font_glyph_path,
- _cairo_win32_font_get_glyph_cache_key,
- _cairo_win32_font_create_glyph
+typedef struct _cairo_win32_font_face cairo_win32_font_face_t;
+
+struct _cairo_win32_font_face {
+ cairo_font_face_t base;
+ LOGFONTW logfont;
};
/* implement the platform-specific interface */
+static void
+_cairo_win32_font_face_destroy (void *abstract_face)
+{
+}
+
+static cairo_status_t
+_cairo_win32_font_face_create_font (void *abstract_face,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ cairo_scaled_font_t **font)
+{
+ cairo_win32_font_face_t *font_face = abstract_face;
+
+ *font = _win32_scaled_font_create (&font_face->logfont,
+ font_matrix, ctm);
+ if (*font)
+ return CAIRO_STATUS_SUCCESS;
+ else
+ return CAIRO_STATUS_NO_MEMORY;
+}
+
+static const cairo_font_face_backend_t _cairo_win32_font_face_backend = {
+ _cairo_win32_font_face_destroy,
+ _cairo_win32_font_face_create_font,
+};
+
/**
- * cairo_win32_font_create_for_logfontw:
+ * cairo_win32_scaled_font_create_for_logfontw:
* @logfont: A #LOGFONTW structure specifying the font to use.
* The lfHeight, lfWidth, lfOrientation and lfEscapement
- * fields of this structure are ignored; information from
- * @scale will be used instead.
- * @scale: The scale at which this font will be used. The
- * scale is given by multiplying the font matrix (see
- * cairo_transform_font()) by the current transformation matrix.
- * The translation elements of the resulting matrix are ignored.
+ * fields of this structure are ignored.
*
* Creates a new font for the Win32 font backend based on a
* #LOGFONT. This font can then be used with
- * cairo_set_font(), cairo_font_glyph_extents(), or FreeType backend
- * specific functions like cairo_win32_font_select_font().
+ * cairo_set_font_face() or cairo_font_create(). The #cairo_scaled_font_t
+ * returned from cairo_font_create() is also for the Win32 backend
+ * and can be used with functions such as cairo_win32_scaled_font_select_font().
*
- * Return value: a newly created #cairo_font_t. Free with
- * cairo_font_destroy() when you are done using it.
+ * Return value: a newly created #cairo_font_face_t. Free with
+ * cairo_font_face_destroy() when you are done using it.
**/
-cairo_font_t *
-cairo_win32_font_create_for_logfontw (LOGFONTW *logfont,
- cairo_matrix_t *scale)
+cairo_font_face_t *
+cairo_win32_font_face_create_for_logfontw (LOGFONTW *logfont)
{
- cairo_font_scale_t sc;
+ cairo_win32_font_face_t *font_face;
+
+ font_face = malloc (sizeof (cairo_win32_font_face_t));
+ if (!font_face)
+ return NULL;
+
+ font_face->logfont = *logfont;
- cairo_matrix_get_affine (scale,
- &sc.matrix[0][0], &sc.matrix[0][1],
- &sc.matrix[1][0], &sc.matrix[1][1],
- NULL, NULL);
+ _cairo_font_face_init (&font_face->base, &_cairo_win32_font_face_backend);
- return _win32_font_create (logfont, &sc);
+ return &font_face->base;
}
/**
- * cairo_win32_font_select_font:
- * @font: A #cairo_font_t from the Win32 font backend. Such an
- * object can be created with cairo_win32_font_create_for_logfontw().
+ * cairo_win32_scaled_font_select_font:
+ * @scaled_font: A #cairo_scaled_font_t from the Win32 font backend. Such an
+ * object can be created with cairo_win32_scaled_font_create_for_logfontw().
* @hdc: a device context
*
* Selects the font into the given device context and changes the
* map mode and world transformation of the device context to match
* that of the font. This function is intended for use when using
* layout APIs such as Uniscribe to do text layout with the
- * Cairo font. After finishing using the device context, you must call
- * cairo_win32_font_done_font() to release any resources allocated
+ * cairo font. After finishing using the device context, you must call
+ * cairo_win32_scaled_font_done_font() to release any resources allocated
* by this function.
*
- * See cairo_win32_font_get_scale_factor() for converting logical
+ * See cairo_win32_scaled_font_get_metrics_factor() for converting logical
* coordinates from the device context to font space.
*
* Normally, calls to SaveDC() and RestoreDC() would be made around
@@ -1189,30 +1207,30 @@ cairo_win32_font_create_for_logfontw (LOGFONTW *logfont,
* the device context is unchanged.
**/
cairo_status_t
-cairo_win32_font_select_font (cairo_font_t *font,
- HDC hdc)
+cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font,
+ HDC hdc)
{
cairo_status_t status;
HFONT hfont;
HFONT old_hfont = NULL;
int old_mode;
- hfont = _win32_font_get_scaled_font ((cairo_win32_font_t *)font);
+ hfont = _win32_scaled_font_get_scaled_hfont ((cairo_win32_scaled_font_t *)scaled_font);
if (!hfont)
return CAIRO_STATUS_NO_MEMORY;
old_hfont = SelectObject (hdc, hfont);
if (!old_hfont)
- return _cairo_win32_print_gdi_error ("cairo_win32_font_select_font");
+ return _cairo_win32_print_gdi_error ("cairo_win32_scaled_font_select_font");
old_mode = SetGraphicsMode (hdc, GM_ADVANCED);
if (!old_mode) {
- status = _cairo_win32_print_gdi_error ("cairo_win32_font_select_font");
+ status = _cairo_win32_print_gdi_error ("cairo_win32_scaled_font_select_font");
SelectObject (hdc, old_hfont);
return status;
}
- status = _win32_font_set_world_transform ((cairo_win32_font_t *)font, hdc);
+ status = _win32_scaled_font_set_world_transform ((cairo_win32_scaled_font_t *)scaled_font, hdc);
if (!CAIRO_OK (status)) {
SetGraphicsMode (hdc, old_mode);
SelectObject (hdc, old_hfont);
@@ -1225,28 +1243,30 @@ cairo_win32_font_select_font (cairo_font_t *font,
}
/**
- * cairo_win32_font_done_font:
- * @font: A #cairo_font_t from the Win32 font backend.
+ * cairo_win32_scaled_font_done_font:
+ * @scaled_font: A #cairo_scaled_font_t from the Win32 font backend.
*
- * Releases any resources allocated by cairo_win32_font_select_font()
+ * Releases any resources allocated by cairo_win32_scaled_font_select_font()
**/
void
-cairo_win32_font_done_font (cairo_font_t *font)
+cairo_win32_scaled_font_done_font (cairo_scaled_font_t *scaled_font)
{
}
/**
- * cairo_win32_font_get_scale_factor:
- * @font: a #cairo_font_t from the Win32 font backend
+ * cairo_win32_scaled_font_get_metrics_factor:
+ * @scaled_font: a #cairo_scaled_font_t from the Win32 font backend
*
* Gets a scale factor between logical coordinates in the coordinate
- * space used by cairo_win32_font_select_font() and font space coordinates.
+ * space used by cairo_win32_scaled_font_select_font() (that is, the
+ * coordinate system used by the Windows functions to return metrics) and
+ * font space coordinates.
*
* Return value: factor to multiply logical units by to get font space
* coordinates.
**/
double
-cairo_win32_font_get_scale_factor (cairo_font_t *font)
+cairo_win32_scaled_font_get_metrics_factor (cairo_scaled_font_t *scaled_font)
{
- return 1. / ((cairo_win32_font_t *)font)->logical_scale;
+ return 1. / ((cairo_win32_scaled_font_t *)scaled_font)->logical_scale;
}
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index dcfe6d044..9df86380b 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -1,6 +1,6 @@
/* Cairo - a vector graphics library with display and print output
*
- * Copyright © 2005 Red Hat, Inc.
+ * Copyright  2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -34,7 +34,7 @@
*/
#include <stdio.h>
-
+#include "cairoint.h"
#include "cairo-win32-private.h"
static const cairo_surface_backend_t cairo_win32_surface_backend;
@@ -46,7 +46,7 @@ static const cairo_surface_backend_t cairo_win32_surface_backend;
* Helper function to dump out a human readable form of the
* current error code.
*
- * Return value: A Cairo status code for the error code
+ * Return value: A cairo status code for the error code
**/
cairo_status_t
_cairo_win32_print_gdi_error (const char *context)
@@ -76,27 +76,6 @@ _cairo_win32_print_gdi_error (const char *context)
return CAIRO_STATUS_NO_MEMORY;
}
-void
-cairo_set_target_win32 (cairo_t *cr,
- HDC hdc)
-{
- cairo_surface_t *surface;
-
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
-
- surface = cairo_win32_surface_create (hdc);
- if (surface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface (cr, surface);
-
- /* cairo_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy (surface);
-}
-
static cairo_status_t
_create_dc_and_bitmap (cairo_win32_surface_t *surface,
HDC original_dc,
@@ -215,7 +194,7 @@ _create_dc_and_bitmap (cairo_win32_surface_t *surface,
*bits_out = bits;
if (rowstride_out) {
- /* Windows bitmaps are padded to 16-bit (word) boundaries */
+ /* Windows bitmaps are padded to 32-bit (dword) boundaries */
switch (format) {
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
@@ -223,11 +202,11 @@ _create_dc_and_bitmap (cairo_win32_surface_t *surface,
break;
case CAIRO_FORMAT_A8:
- *rowstride_out = (width + 1) & -2;
+ *rowstride_out = (width + 3) & ~3;
break;
case CAIRO_FORMAT_A1:
- *rowstride_out = ((width + 15) & -16) / 8;
+ *rowstride_out = ((width + 31) & ~31) / 8;
break;
}
}
@@ -345,8 +324,8 @@ _cairo_win32_surface_create_dib (cairo_format_t format,
width, height);
}
-static void
-_cairo_win32_surface_destroy (void *abstract_surface)
+static cairo_status_t
+_cairo_win32_surface_finish (void *abstract_surface)
{
cairo_win32_surface_t *surface = abstract_surface;
@@ -362,15 +341,8 @@ _cairo_win32_surface_destroy (void *abstract_surface)
DeleteObject (surface->bitmap);
DeleteDC (surface->dc);
}
-
- free (surface);
-}
-static double
-_cairo_win32_surface_pixels_per_inch (void *abstract_surface)
-{
- /* XXX: We should really get this value from somewhere */
- return 96.0;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@@ -433,10 +405,6 @@ _cairo_win32_surface_acquire_source_image (void *abstract_sur
surface->clip_rect.width,
surface->clip_rect.height, &local);
if (CAIRO_OK (status)) {
- cairo_surface_set_filter (&local->base, surface->base.filter);
- cairo_surface_set_matrix (&local->base, &surface->base.matrix);
- cairo_surface_set_repeat (&local->base, surface->base.repeat);
-
*image_out = (cairo_image_surface_t *)local->image;
*image_extra = local;
}
@@ -544,14 +512,6 @@ _cairo_win32_surface_release_dest_image (void *abstract_surfac
cairo_surface_destroy ((cairo_surface_t *)local);
}
-static cairo_status_t
-_cairo_win32_surface_clone_similar (void *surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
static cairo_int_status_t
_cairo_win32_surface_composite (cairo_operator_t operator,
cairo_pattern_t *pattern,
@@ -584,9 +544,9 @@ _cairo_win32_surface_composite (cairo_operator_t operator,
if (mask_pattern->type != CAIRO_PATTERN_SOLID)
return CAIRO_INT_STATUS_UNSUPPORTED;
- alpha = (int)(0xffff * pattern->alpha * mask_pattern->alpha) >> 8;
+ alpha = ((cairo_solid_pattern_t *)mask_pattern)->color.alpha_short >> 8;
} else {
- alpha = (int)(0xffff * pattern->alpha) >> 8;
+ alpha = 255;
}
src_surface_pattern = (cairo_surface_pattern_t *)pattern;
@@ -601,7 +561,7 @@ _cairo_win32_surface_composite (cairo_operator_t operator,
if (alpha == 255 &&
src->format == dst->format &&
- (operator == CAIRO_OPERATOR_SRC ||
+ (operator == CAIRO_OPERATOR_SOURCE ||
(src->format == CAIRO_FORMAT_RGB24 && operator == CAIRO_OPERATOR_OVER))) {
if (!BitBlt (dst->dc,
@@ -642,6 +602,81 @@ _cairo_win32_surface_composite (cairo_operator_t operator,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
+/* This big function tells us how to optimize operators for the
+ * case of solid destination and constant-alpha source
+ *
+ * NOTE: This function needs revisiting if we add support for
+ * super-luminescent colors (a == 0, r,g,b > 0)
+ */
+static enum { DO_CLEAR, DO_SOURCE, DO_NOTHING, DO_UNSUPPORTED }
+categorize_solid_dest_operator (cairo_operator_t operator,
+ unsigned short alpha)
+{
+ enum { SOURCE_TRANSPARENT, SOURCE_LIGHT, SOURCE_SOLID, SOURCE_OTHER } source;
+
+ if (alpha >= 0xff00)
+ source = SOURCE_SOLID;
+ else if (alpha < 0x100)
+ source = SOURCE_TRANSPARENT;
+ else
+ source = SOURCE_OTHER;
+
+ switch (operator) {
+ case CAIRO_OPERATOR_CLEAR: /* 0 0 */
+ case CAIRO_OPERATOR_OUT: /* 1 - Ab 0 */
+ return DO_CLEAR;
+ break;
+
+ case CAIRO_OPERATOR_SOURCE: /* 1 0 */
+ case CAIRO_OPERATOR_IN: /* Ab 0 */
+ return DO_SOURCE;
+ break;
+
+ case CAIRO_OPERATOR_OVER: /* 1 1 - Aa */
+ case CAIRO_OPERATOR_ATOP: /* Ab 1 - Aa */
+ if (source == SOURCE_SOLID)
+ return DO_SOURCE;
+ else if (source == SOURCE_TRANSPARENT)
+ return DO_NOTHING;
+ else
+ return DO_UNSUPPORTED;
+ break;
+
+ case CAIRO_OPERATOR_DEST_OUT: /* 0 1 - Aa */
+ case CAIRO_OPERATOR_XOR: /* 1 - Ab 1 - Aa */
+ if (source == SOURCE_SOLID)
+ return DO_CLEAR;
+ else if (source == SOURCE_TRANSPARENT)
+ return DO_NOTHING;
+ else
+ return DO_UNSUPPORTED;
+ break;
+
+ case CAIRO_OPERATOR_DEST: /* 0 1 */
+ case CAIRO_OPERATOR_DEST_OVER:/* 1 - Ab 1 */
+ case CAIRO_OPERATOR_SATURATE: /* min(1,(1-Ab)/Aa) 1 */
+ return DO_NOTHING;
+ break;
+
+ case CAIRO_OPERATOR_DEST_IN: /* 0 Aa */
+ case CAIRO_OPERATOR_DEST_ATOP:/* 1 - Ab Aa */
+ if (source == SOURCE_SOLID)
+ return DO_NOTHING;
+ else if (source == SOURCE_TRANSPARENT)
+ return DO_CLEAR;
+ else
+ return DO_UNSUPPORTED;
+ break;
+
+ case CAIRO_OPERATOR_ADD: /* 1 1 */
+ if (source == SOURCE_TRANSPARENT)
+ return DO_NOTHING;
+ else
+ return DO_UNSUPPORTED;
+ break;
+ }
+}
+
static cairo_int_status_t
_cairo_win32_surface_fill_rectangles (void *abstract_surface,
cairo_operator_t operator,
@@ -660,17 +695,24 @@ _cairo_win32_surface_fill_rectangles (void *abstract_surface,
*/
if (surface->image)
return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* We could support possibly support more operators for color->alpha = 0xffff.
- * for CAIRO_OPERATOR_SRC, alpha doesn't matter since we know the destination
- * image doesn't have alpha. (surface->pixman_image is non-NULL for all
+
+ /* Optimize for no destination alpha (surface->pixman_image is non-NULL for all
* surfaces with alpha.)
*/
- if (operator != CAIRO_OPERATOR_SRC)
+ switch (categorize_solid_dest_operator (operator, color->alpha_short)) {
+ case DO_CLEAR:
+ new_color = RGB (0, 0, 0);
+ break;
+ case DO_SOURCE:
+ new_color = RGB (color->red_short >> 8, color->blue_short >> 8, color->green_short >> 8);
+ break;
+ case DO_NOTHING:
+ return CAIRO_STATUS_SUCCESS;
+ case DO_UNSUPPORTED:
+ default:
return CAIRO_INT_STATUS_UNSUPPORTED;
-
- new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8);
-
+ }
+
new_brush = CreateSolidBrush (new_color);
if (!new_brush)
return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
@@ -700,35 +742,6 @@ _cairo_win32_surface_fill_rectangles (void *abstract_surface,
}
static cairo_int_status_t
-_cairo_win32_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_copy_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
_cairo_win32_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
@@ -741,14 +754,14 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
if (surface->image)
_cairo_surface_set_clip_region (surface->image, region);
- /* The semantics we want is that any clip set by Cairo combines
+ /* The semantics we want is that any clip set by cairo combines
* is intersected with the clip on device context that the
* surface was created for. To implement this, we need to
* save the original clip when first setting a clip on surface.
*/
if (region == NULL) {
- /* Clear any clip set by Cairo, return to the original */
+ /* Clear any clip set by cairo, return to the original */
if (surface->set_clip) {
if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR)
@@ -845,21 +858,22 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
}
}
-static cairo_status_t
-_cairo_win32_surface_show_glyphs (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
+static cairo_int_status_t
+_cairo_win32_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t *rectangle)
{
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ cairo_win32_surface_t *surface = abstract_surface;
+ RECT clip_box;
+
+ if (GetClipBox (surface->dc, &clip_box) == ERROR)
+ return _cairo_win32_print_gdi_error ("_cairo_win3_surface_acquire_dest_image");
+
+ rectangle->x = clip_box.left;
+ rectangle->y = clip_box.top;
+ rectangle->width = clip_box.right - clip_box.left;
+ rectangle->height = clip_box.bottom - clip_box.top;
+
+ return CAIRO_STATUS_SUCCESS;
}
cairo_surface_t *
@@ -884,6 +898,7 @@ cairo_win32_surface_create (HDC hdc)
surface->dc = hdc;
surface->bitmap = NULL;
+ surface->saved_dc_bitmap = NULL;
surface->clip_rect.x = rect.left;
surface->clip_rect.y = rect.top;
@@ -914,18 +929,18 @@ _cairo_surface_is_win32 (cairo_surface_t *surface)
static const cairo_surface_backend_t cairo_win32_surface_backend = {
_cairo_win32_surface_create_similar,
- _cairo_win32_surface_destroy,
- _cairo_win32_surface_pixels_per_inch,
+ _cairo_win32_surface_finish,
_cairo_win32_surface_acquire_source_image,
_cairo_win32_surface_release_source_image,
_cairo_win32_surface_acquire_dest_image,
_cairo_win32_surface_release_dest_image,
- _cairo_win32_surface_clone_similar,
+ NULL, /* clone_similar */
_cairo_win32_surface_composite,
_cairo_win32_surface_fill_rectangles,
- _cairo_win32_surface_composite_trapezoids,
- _cairo_win32_surface_copy_page,
- _cairo_win32_surface_show_page,
+ NULL, /* composite_trapezoids */
+ NULL, /* copy_page */
+ NULL, /* show_page */
_cairo_win32_surface_set_clip_region,
- _cairo_win32_surface_show_glyphs
+ _cairo_win32_surface_get_extents,
+ NULL /* show_glyphs */
};
diff --git a/src/cairo-win32.h b/src/cairo-win32.h
index fab497aa4..93983456f 100644
--- a/src/cairo-win32.h
+++ b/src/cairo-win32.h
@@ -34,38 +34,36 @@
*/
#ifndef _CAIRO_WIN32_H_
+#define _CAIRO_WIN32_H_
#include <cairo.h>
-#ifdef CAIRO_HAS_WIN32_SURFACE
+#if CAIRO_HAS_WIN32_SURFACE
#include <windows.h>
CAIRO_BEGIN_DECLS
-void
-cairo_set_target_win32 (cairo_t *cr,
- HDC hdc);
-
cairo_surface_t *
cairo_win32_surface_create (HDC hdc);
-cairo_font_t *
-cairo_win32_font_create_for_logfontw (LOGFONTW *logfont,
- cairo_matrix_t *scale);
+cairo_font_face_t *
+cairo_win32_font_face_create_for_logfontw (LOGFONTW *logfont);
cairo_status_t
-cairo_win32_font_select_font (cairo_font_t *font,
- HDC hdc);
+cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font,
+ HDC hdc);
void
-cairo_win32_font_done_font (cairo_font_t *font);
+cairo_win32_scaled_font_done_font (cairo_scaled_font_t *scaled_font);
double
-cairo_win32_font_get_scale_factor (cairo_font_t *font);
-
-#endif /* CAIRO_HAS_WIN32_SURFACE */
+cairo_win32_scaled_font_get_metrics_factor (cairo_scaled_font_t *scaled_font);
CAIRO_END_DECLS
+#else /* CAIRO_HAS_WIN32_SURFACE */
+# error Cairo was not compiled with support for the win32 backend
+#endif /* CAIRO_HAS_WIN32_SURFACE */
+
#endif /* _CAIRO_WIN32_H_ */
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 0694b77a2..95568d608 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -36,12 +36,7 @@
#include "cairoint.h"
#include "cairo-xcb.h"
-
-cairo_surface_t *
-cairo_xcb_surface_create (XCBConnection *dpy,
- XCBDRAWABLE drawable,
- XCBVISUALTYPE *visual,
- cairo_format_t format);
+#include "cairo-xcb-xrender.h"
#define AllPlanes ((unsigned long)~0L)
@@ -71,10 +66,12 @@ format_from_visual(XCBConnection *c, XCBVISUALID visual)
return nil;
}
-static XCBRenderPICTFORMAT
-format_from_cairo(XCBConnection *c, cairo_format_t fmt)
+/* XXX: Why is this ridiculously complex compared to the equivalent
+ * function in cairo-xlib-surface.c */
+static XCBRenderPICTFORMINFO
+_format_from_cairo(XCBConnection *c, cairo_format_t fmt)
{
- XCBRenderPICTFORMAT ret = { 0 };
+ XCBRenderPICTFORMINFO ret = {{ 0 }};
struct tmpl_t {
XCBRenderDIRECTFORMAT direct;
CARD8 depth;
@@ -151,36 +148,20 @@ format_from_cairo(XCBConnection *c, cairo_format_t fmt)
if(t->alpha_mask && (t->alpha_mask != f->alpha_mask || t->alpha_shift != f->alpha_shift))
continue;
- ret = fi.data->id;
+ ret = *fi.data;
}
free(r);
return ret;
}
-void
-cairo_set_target_xcb (cairo_t *cr,
- XCBConnection *dpy,
- XCBDRAWABLE drawable,
- XCBVISUALTYPE *visual,
- cairo_format_t format)
-{
- cairo_surface_t *surface;
-
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
-
- surface = cairo_xcb_surface_create (dpy, drawable, visual, format);
- if (surface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface (cr, surface);
+/*
+ * Instead of taking two round trips for each blending request,
+ * assume that if a particular drawable fails GetImage that it will
+ * fail for a "while"; use temporary pixmaps to avoid the errors
+ */
- /* cairo_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy (surface);
-}
+#define CAIRO_ASSUME_PIXMAP 20
typedef struct cairo_xcb_surface {
cairo_surface_t base;
@@ -190,15 +171,19 @@ typedef struct cairo_xcb_surface {
XCBDRAWABLE drawable;
int owns_pixmap;
XCBVISUALTYPE *visual;
- cairo_format_t format;
+
+ int use_pixmap;
int render_major;
int render_minor;
int width;
int height;
+ int depth;
XCBRenderPICTURE picture;
+ XCBRenderPICTFORMINFO format;
+ int has_format;
} cairo_xcb_surface_t;
#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
@@ -222,6 +207,9 @@ typedef struct cairo_xcb_surface {
#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
+static void
+_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface);
+
static int
_CAIRO_FORMAT_DEPTH (cairo_format_t format)
{
@@ -239,46 +227,43 @@ _CAIRO_FORMAT_DEPTH (cairo_format_t format)
}
static cairo_surface_t *
-_cairo_xcb_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
+_cairo_xcb_surface_create_similar (void *abstract_src,
+ cairo_format_t format,
+ int drawable,
+ int width,
+ int height)
{
cairo_xcb_surface_t *src = abstract_src;
XCBConnection *dpy = src->dpy;
XCBDRAWABLE d;
cairo_xcb_surface_t *surface;
+ XCBRenderPICTFORMINFO xrender_format = _format_from_cairo (dpy, format);
- /* XXX: There's a pretty lame heuristic here. This assumes that
- * all non-Render X servers do not support depth-32 pixmaps, (and
- * that they do support depths 1, 8, and 24). Obviously, it would
- * be much better to check the depths that are actually
- * supported. */
- if (!dpy
- || (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)
- && format == CAIRO_FORMAT_ARGB32))
- {
- return NULL;
+ /* As a good first approximation, if the display doesn't have COMPOSITE,
+ * we're better off using image surfaces for all temporary operations
+ */
+ if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)) {
+ return cairo_image_surface_create (format, width, height);
}
d.pixmap = XCBPIXMAPNew (dpy);
XCBCreatePixmap (dpy, _CAIRO_FORMAT_DEPTH (format),
d.pixmap, src->drawable,
- width, height);
+ width <= 0 ? 1 : width,
+ height <= 0 ? 1 : height);
surface = (cairo_xcb_surface_t *)
- cairo_xcb_surface_create (dpy, d, NULL, format);
- surface->owns_pixmap = 1;
+ cairo_xcb_surface_create_with_xrender_format (dpy, d,
+ &xrender_format,
+ width, height);
- surface->width = width;
- surface->height = height;
+ surface->owns_pixmap = TRUE;
return &surface->base;
}
-static void
-_cairo_xcb_surface_destroy (void *abstract_surface)
+static cairo_status_t
+_cairo_xcb_surface_finish (void *abstract_surface)
{
cairo_xcb_surface_t *surface = abstract_surface;
if (surface->picture.xid)
@@ -290,20 +275,13 @@ _cairo_xcb_surface_destroy (void *abstract_surface)
if (surface->gc.xid)
XCBFreeGC (surface->dpy, surface->gc);
- surface->dpy = 0;
+ surface->dpy = NULL;
- free (surface);
-}
-
-static double
-_cairo_xcb_surface_pixels_per_inch (void *abstract_surface)
-{
- /* XXX: We should really get this value from somewhere like Xft.dpy */
- return 96.0;
+ return CAIRO_STATUS_SUCCESS;
}
static int
-bits_per_pixel(XCBConnection *c, int depth)
+_bits_per_pixel(XCBConnection *c, int depth)
{
XCBFORMAT *fmt = XCBConnSetupSuccessRepPixmapFormats(XCBGetSetup(c));
XCBFORMAT *fmtend = fmt + XCBConnSetupSuccessRepPixmapFormatsLength(XCBGetSetup(c));
@@ -322,12 +300,52 @@ bits_per_pixel(XCBConnection *c, int depth)
}
static int
-bytes_per_line(XCBConnection *c, int width, int bpp)
+_bytes_per_line(XCBConnection *c, int width, int bpp)
{
int bitmap_pad = XCBGetSetup(c)->bitmap_format_scanline_pad;
return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3;
}
+static cairo_bool_t
+_CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format)
+{
+ switch (masks->bpp) {
+ case 32:
+ if (masks->alpha_mask == 0xff000000 &&
+ masks->red_mask == 0x00ff0000 &&
+ masks->green_mask == 0x0000ff00 &&
+ masks->blue_mask == 0x000000ff)
+ {
+ *format = CAIRO_FORMAT_ARGB32;
+ return 1;
+ }
+ if (masks->alpha_mask == 0x00000000 &&
+ masks->red_mask == 0x00ff0000 &&
+ masks->green_mask == 0x0000ff00 &&
+ masks->blue_mask == 0x000000ff)
+ {
+ *format = CAIRO_FORMAT_RGB24;
+ return 1;
+ }
+ break;
+ case 8:
+ if (masks->alpha_mask == 0xff)
+ {
+ *format = CAIRO_FORMAT_A8;
+ return 1;
+ }
+ break;
+ case 1:
+ if (masks->alpha_mask == 0x1)
+ {
+ *format = CAIRO_FORMAT_A1;
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
static cairo_status_t
_get_image_surface (cairo_xcb_surface_t *surface,
cairo_rectangle_t *interest_rect,
@@ -335,18 +353,12 @@ _get_image_surface (cairo_xcb_surface_t *surface,
cairo_rectangle_t *image_rect)
{
cairo_image_surface_t *image;
- XCBGetGeometryRep *geomrep;
XCBGetImageRep *imagerep;
- int bpp;
+ int bpp, bytes_per_line;
int x1, y1, x2, y2;
-
- geomrep = XCBGetGeometryReply(surface->dpy, XCBGetGeometry(surface->dpy, surface->drawable), 0);
- if(!geomrep)
- return 0;
-
- surface->width = geomrep->width;
- surface->height = geomrep->height;
- free(geomrep);
+ unsigned char *data;
+ cairo_format_t format;
+ cairo_format_masks_t masks;
x1 = 0;
y1 = 0;
@@ -354,14 +366,21 @@ _get_image_surface (cairo_xcb_surface_t *surface,
y2 = surface->height;
if (interest_rect) {
- if (interest_rect->x > x1)
- x1 = interest_rect->x;
- if (interest_rect->y > y1)
- y1 = interest_rect->y;
- if (interest_rect->x + interest_rect->width < x2)
- x2 = interest_rect->x + interest_rect->width;
- if (interest_rect->y + interest_rect->height < y2)
- y2 = interest_rect->y + interest_rect->height;
+ cairo_rectangle_t rect;
+
+ rect.x = interest_rect->x;
+ rect.y = interest_rect->y;
+ rect.width = interest_rect->width;
+ rect.height = interest_rect->width;
+
+ if (rect.x > x1)
+ x1 = rect.x;
+ if (rect.y > y1)
+ y1 = rect.y;
+ if (rect.x + rect.width < x2)
+ x2 = rect.x + rect.width;
+ if (rect.y + rect.height < y2)
+ y2 = rect.y + rect.height;
if (x1 >= x2 || y1 >= y2) {
*image_out = NULL;
@@ -376,47 +395,132 @@ _get_image_surface (cairo_xcb_surface_t *surface,
image_rect->height = y2 - y1;
}
- imagerep = XCBGetImageReply(surface->dpy,
- XCBGetImage(surface->dpy, ZPixmap,
- surface->drawable,
- x1, y1,
- x2 - x1, y2 - y1,
- AllPlanes), 0);
- if(!imagerep)
- return 0;
+ /* XXX: This should try to use the XShm extension if available */
- bpp = bits_per_pixel(surface->dpy, imagerep->depth);
+ if (surface->use_pixmap == 0)
+ {
+ XCBGenericError *error;
+ imagerep = XCBGetImageReply(surface->dpy,
+ XCBGetImage(surface->dpy, ZPixmap,
+ surface->drawable,
+ x1, y1,
+ x2 - x1, y2 - y1,
+ AllPlanes), &error);
+
+ /* If we get an error, the surface must have been a window,
+ * so retry with the safe code path.
+ */
+ if (error)
+ surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
+ }
+ else
+ {
+ surface->use_pixmap--;
+ imagerep = NULL;
+ }
- if (surface->visual) {
- cairo_format_masks_t masks;
+ if (!imagerep)
+ {
+ /* XCBGetImage from a window is dangerous because it can
+ * produce errors if the window is unmapped or partially
+ * outside the screen. We could check for errors and
+ * retry, but to keep things simple, we just create a
+ * temporary pixmap
+ */
+ XCBDRAWABLE drawable;
+ drawable.pixmap = XCBPIXMAPNew (surface->dpy);
+ XCBCreatePixmap (surface->dpy,
+ surface->depth,
+ drawable.pixmap,
+ surface->drawable,
+ x2 - x1, y2 - y1);
+ _cairo_xcb_surface_ensure_gc (surface);
+
+ XCBCopyArea (surface->dpy, surface->drawable, drawable, surface->gc,
+ x1, y1, 0, 0, x2 - x1, y2 - y1);
+
+ imagerep = XCBGetImageReply(surface->dpy,
+ XCBGetImage(surface->dpy, ZPixmap,
+ drawable,
+ x1, y1,
+ x2 - x1, y2 - y1,
+ AllPlanes), 0);
+ XCBFreePixmap (surface->dpy, drawable.pixmap);
+
+ }
+ if (!imagerep)
+ return CAIRO_STATUS_NO_MEMORY;
- /* XXX: Add support here for pictures with external alpha? */
+ bpp = _bits_per_pixel(surface->dpy, imagerep->depth);
+ bytes_per_line = _bytes_per_line(surface->dpy, surface->width, bpp);
+ data = malloc (bytes_per_line * surface->height);
+ if (data == NULL) {
+ free (imagerep);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ memcpy (data, XCBGetImageData (imagerep), bytes_per_line * surface->height);
+ free (imagerep);
+
+ /*
+ * Compute the pixel format masks from either an XCBVISUALTYPE or
+ * a XCBRenderPCTFORMINFO, failing we assume the drawable is an
+ * alpha-only pixmap as it could only have been created that way
+ * through the cairo_xlib_surface_create_for_bitmap function.
+ */
+ if (surface->visual) {
masks.bpp = bpp;
masks.alpha_mask = 0;
masks.red_mask = surface->visual->red_mask;
masks.green_mask = surface->visual->green_mask;
masks.blue_mask = surface->visual->blue_mask;
-
- image = _cairo_image_surface_create_with_masks (XCBGetImageData(imagerep),
- &masks,
- x2 - x1,
- y2 - y1,
- bytes_per_line(surface->dpy, surface->width, bpp));
+ } else if (surface->has_format) {
+ masks.bpp = bpp;
+ masks.red_mask = surface->format.direct.red_mask << surface->format.direct.red_shift;
+ masks.green_mask = surface->format.direct.green_mask << surface->format.direct.green_shift;
+ masks.blue_mask = surface->format.direct.blue_mask << surface->format.direct.blue_shift;
+ masks.alpha_mask = surface->format.direct.alpha_mask << surface->format.direct.alpha_shift;
} else {
+ masks.bpp = bpp;
+ masks.red_mask = 0;
+ masks.green_mask = 0;
+ masks.blue_mask = 0;
+ if (surface->depth < 32)
+ masks.alpha_mask = (1 << surface->depth) - 1;
+ else
+ masks.alpha_mask = 0xffffffff;
+ }
+
+ /*
+ * Prefer to use a standard pixman format instead of the
+ * general masks case.
+ */
+ if (_CAIRO_MASK_FORMAT (&masks, &format)) {
image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data (XCBGetImageData(imagerep),
- surface->format,
+ cairo_image_surface_create_for_data (data,
+ format,
x2 - x1,
y2 - y1,
- bytes_per_line(surface->dpy, surface->width, bpp));
+ bytes_per_line);
+ } else {
+ /*
+ * XXX This can't work. We must convert the data to one of the
+ * supported pixman formats. Pixman needs another function
+ * which takes data in an arbitrary format and converts it
+ * to something supported by that library.
+ */
+ image = _cairo_image_surface_create_with_masks (data,
+ &masks,
+ x2 - x1,
+ y2 - y1,
+ bytes_per_line);
+
}
/* Let the surface take ownership of the data */
- /* XXX: Can probably come up with a cleaner API here. */
_cairo_image_surface_assume_ownership_of_data (image);
- /* FIXME: imagerep can't be freed correctly, I think. must copy. :-( */
-
+
_cairo_image_surface_set_repeat (image, surface->base.repeat);
_cairo_image_surface_set_matrix (image, &(surface->base.matrix));
@@ -443,8 +547,8 @@ _draw_image_surface (cairo_xcb_surface_t *surface,
int bpp, data_len;
_cairo_xcb_surface_ensure_gc (surface);
- bpp = bits_per_pixel(surface->dpy, image->depth);
- data_len = bytes_per_line(surface->dpy, image->width, bpp) * image->height;
+ bpp = _bits_per_pixel(surface->dpy, image->depth);
+ data_len = _bytes_per_line(surface->dpy, image->width, bpp) * image->height;
XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc,
image->width,
image->height,
@@ -465,13 +569,8 @@ _cairo_xcb_surface_acquire_source_image (void *abstract_surfa
cairo_status_t status;
status = _get_image_surface (surface, NULL, &image, NULL);
- if (status == CAIRO_STATUS_SUCCESS) {
- cairo_surface_set_filter (&image->base, surface->base.filter);
- cairo_surface_set_matrix (&image->base, &surface->base.matrix);
- cairo_surface_set_repeat (&image->base, surface->base.repeat);
-
+ if (status == CAIRO_STATUS_SUCCESS)
*image_out = image;
- }
return status;
}
@@ -562,13 +661,13 @@ _cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface,
if (!surface->picture.xid)
return CAIRO_STATUS_SUCCESS;
- xtransform.matrix11 = _cairo_fixed_from_double (matrix->m[0][0]);
- xtransform.matrix12 = _cairo_fixed_from_double (matrix->m[1][0]);
- xtransform.matrix13 = _cairo_fixed_from_double (matrix->m[2][0]);
+ xtransform.matrix11 = _cairo_fixed_from_double (matrix->xx);
+ xtransform.matrix12 = _cairo_fixed_from_double (matrix->xy);
+ xtransform.matrix13 = _cairo_fixed_from_double (matrix->x0);
- xtransform.matrix21 = _cairo_fixed_from_double (matrix->m[0][1]);
- xtransform.matrix22 = _cairo_fixed_from_double (matrix->m[1][1]);
- xtransform.matrix23 = _cairo_fixed_from_double (matrix->m[2][1]);
+ xtransform.matrix21 = _cairo_fixed_from_double (matrix->yx);
+ xtransform.matrix22 = _cairo_fixed_from_double (matrix->yy);
+ xtransform.matrix23 = _cairo_fixed_from_double (matrix->y0);
xtransform.matrix31 = 0;
xtransform.matrix32 = 0;
@@ -685,25 +784,25 @@ _render_operator (cairo_operator_t operator)
switch (operator) {
case CAIRO_OPERATOR_CLEAR:
return XCBRenderPictOpClear;
- case CAIRO_OPERATOR_SRC:
+ case CAIRO_OPERATOR_SOURCE:
return XCBRenderPictOpSrc;
- case CAIRO_OPERATOR_DST:
+ case CAIRO_OPERATOR_DEST:
return XCBRenderPictOpDst;
case CAIRO_OPERATOR_OVER:
return XCBRenderPictOpOver;
- case CAIRO_OPERATOR_OVER_REVERSE:
+ case CAIRO_OPERATOR_DEST_OVER:
return XCBRenderPictOpOverReverse;
case CAIRO_OPERATOR_IN:
return XCBRenderPictOpIn;
- case CAIRO_OPERATOR_IN_REVERSE:
+ case CAIRO_OPERATOR_DEST_IN:
return XCBRenderPictOpInReverse;
case CAIRO_OPERATOR_OUT:
return XCBRenderPictOpOut;
- case CAIRO_OPERATOR_OUT_REVERSE:
+ case CAIRO_OPERATOR_DEST_OUT:
return XCBRenderPictOpOutReverse;
case CAIRO_OPERATOR_ATOP:
return XCBRenderPictOpAtop;
- case CAIRO_OPERATOR_ATOP_REVERSE:
+ case CAIRO_OPERATOR_DEST_ATOP:
return XCBRenderPictOpAtopReverse;
case CAIRO_OPERATOR_XOR:
return XCBRenderPictOpXor;
@@ -840,6 +939,7 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator,
cairo_int_status_t status;
int render_reference_x, render_reference_y;
int render_src_x, render_src_y;
+ XCBRenderPICTFORMINFO render_format;
if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -863,13 +963,14 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator,
render_src_y = src_y + render_reference_y - dst_y;
/* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
- /* XXX: format_from_cairo is slow. should cache something. */
+ /* XXX: _format_from_cairo is slow. should cache something. */
+ render_format = _format_from_cairo (dst->dpy, CAIRO_FORMAT_A8),
status = _cairo_xcb_surface_set_attributes (src, &attributes);
if (CAIRO_OK (status))
XCBRenderTrapezoids (dst->dpy,
_render_operator (operator),
src->picture, dst->picture,
- format_from_cairo (dst->dpy, CAIRO_FORMAT_A8),
+ render_format.id,
render_src_x + attributes.x_offset,
render_src_y + attributes.y_offset,
num_traps, (XCBRenderTRAP *) traps);
@@ -880,29 +981,31 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator,
}
static cairo_int_status_t
-_cairo_xcb_surface_copy_page (void *abstract_surface)
+_cairo_xcb_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
{
+ /* XXX: FIXME */
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
-_cairo_xcb_surface_show_page (void *abstract_surface)
+_cairo_xcb_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t *rectangle)
{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
+ cairo_xcb_surface_t *surface = abstract_surface;
-static cairo_int_status_t
-_cairo_xcb_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- /* FIXME */
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ rectangle->x = 0;
+ rectangle->y = 0;
+
+ rectangle->width = surface->width;
+ rectangle->height = surface->height;
+
+ return CAIRO_STATUS_SUCCESS;
}
static const cairo_surface_backend_t cairo_xcb_surface_backend = {
_cairo_xcb_surface_create_similar,
- _cairo_xcb_surface_destroy,
- _cairo_xcb_surface_pixels_per_inch,
+ _cairo_xcb_surface_finish,
_cairo_xcb_surface_acquire_source_image,
_cairo_xcb_surface_release_source_image,
_cairo_xcb_surface_acquire_dest_image,
@@ -911,12 +1014,27 @@ static const cairo_surface_backend_t cairo_xcb_surface_backend = {
_cairo_xcb_surface_composite,
_cairo_xcb_surface_fill_rectangles,
_cairo_xcb_surface_composite_trapezoids,
- _cairo_xcb_surface_copy_page,
- _cairo_xcb_surface_show_page,
+ NULL, /* copy_page */
+ NULL, /* show_page */
_cairo_xcb_surface_set_clip_region,
+ _cairo_xcb_surface_get_extents,
NULL /* show_glyphs */
};
+/**
+ * _cairo_surface_is_xcb:
+ * @surface: a #cairo_surface_t
+ *
+ * Checks if a surface is a #cairo_xcb_surface_t
+ *
+ * Return value: True if the surface is an xcb surface
+ **/
+static cairo_bool_t
+_cairo_surface_is_xcb (cairo_surface_t *surface)
+{
+ return surface->backend == &cairo_xcb_surface_backend;
+}
+
static void
query_render_version (XCBConnection *c, cairo_xcb_surface_t *surface)
{
@@ -937,11 +1055,14 @@ query_render_version (XCBConnection *c, cairo_xcb_surface_t *surface)
free(r);
}
-cairo_surface_t *
-cairo_xcb_surface_create (XCBConnection *dpy,
- XCBDRAWABLE drawable,
- XCBVISUALTYPE *visual,
- cairo_format_t format)
+static cairo_surface_t *
+_cairo_xcb_surface_create_internal (XCBConnection *dpy,
+ XCBDRAWABLE drawable,
+ XCBVISUALTYPE *visual,
+ XCBRenderPICTFORMINFO *format,
+ int width,
+ int height,
+ int depth)
{
cairo_xcb_surface_t *surface;
@@ -952,27 +1073,199 @@ cairo_xcb_surface_create (XCBConnection *dpy,
_cairo_surface_init (&surface->base, &cairo_xcb_surface_backend);
surface->dpy = dpy;
+
surface->gc.xid = 0;
surface->drawable = drawable;
- surface->owns_pixmap = 0;
+ surface->owns_pixmap = FALSE;
surface->visual = visual;
- surface->format = format;
+ if (format) {
+ surface->format = *format;
+ surface->has_format = 1;
+ } else {
+ surface->format.id.xid = 0;
+ surface->has_format = 0;
+ }
+ surface->use_pixmap = 0;
+ surface->width = width;
+ surface->height = height;
+ surface->depth = depth;
+
+ if (format) {
+ surface->depth = format->depth;
+ } else if (visual) {
+ XCBSCREENIter roots;
+ XCBDEPTHIter depths;
+ XCBVISUALTYPEIter visuals;
+
+ /* This is ugly, but we have to walk over all visuals
+ * for the display to find the depth.
+ */
+ roots = XCBConnSetupSuccessRepRootsIter(XCBGetSetup(surface->dpy));
+ for(; roots.rem; XCBSCREENNext(&roots))
+ {
+ depths = XCBSCREENAllowedDepthsIter(roots.data);
+ for(; depths.rem; XCBDEPTHNext(&depths))
+ {
+ visuals = XCBDEPTHVisualsIter(depths.data);
+ for(; visuals.rem; XCBVISUALTYPENext(&visuals))
+ {
+ if(visuals.data->visual_id.id == visual->visual_id.id)
+ {
+ surface->depth = depths.data->depth;
+ goto found;
+ }
+ }
+ }
+ }
+ found:
+ ;
+ }
query_render_version(dpy, surface);
+ surface->picture.xid = 0;
+
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
{
- XCBRenderPICTFORMAT fmt;
- if(visual)
- fmt = format_from_visual (dpy, visual->visual_id);
- else
- fmt = format_from_cairo (dpy, format);
+ XCBRenderPICTFORMAT pict_format = {0};
+ XCBRenderPICTFORMINFO format_info;
+
surface->picture = XCBRenderPICTURENew(dpy);
- XCBRenderCreatePicture (dpy, surface->picture, drawable,
- fmt, 0, NULL);
+
+ if (!format) {
+ if (visual) {
+ pict_format = format_from_visual (dpy, visual->visual_id);
+ } else if (depth == 1) {
+ format_info = _format_from_cairo (dpy, CAIRO_FORMAT_A1);
+ pict_format = format_info.id;
+ }
+ XCBRenderCreatePicture (dpy, surface->picture, drawable,
+ pict_format, 0, NULL);
+ } else {
+ XCBRenderCreatePicture (dpy, surface->picture, drawable,
+ format->id, 0, NULL);
+ }
}
- else
- surface->picture.xid = 0;
return (cairo_surface_t *) surface;
}
+
+/**
+ * cairo_xcb_surface_create:
+ * @c: an XCB connection
+ * @drawable: an XCB drawable
+ * @visual: the visual to use for drawing to @drawable. The depth
+ * of the visual must match the depth of the drawable.
+ * Currently, only TrueColor visuals are fully supported.
+ * @width: the current width of @drawable.
+ * @height: the current height of @drawable.
+ *
+ * Creates an XCB surface that draws to the given drawable.
+ * The way that colors are represented in the drawable is specified
+ * by the provided visual.
+ *
+ * NOTE: If @drawable is a window, then the function
+ * cairo_xcb_surface_set_size must be called whenever the size of the
+ * window changes.
+ *
+ * Return value: the newly created surface
+ **/
+cairo_surface_t *
+cairo_xcb_surface_create (XCBConnection *c,
+ XCBDRAWABLE drawable,
+ XCBVISUALTYPE *visual,
+ int width,
+ int height)
+{
+ return _cairo_xcb_surface_create_internal (c, drawable,
+ visual, NULL,
+ width, height, 0);
+}
+
+/**
+ * cairo_xcb_surface_create_for_bitmap:
+ * @c: an XCB connection
+ * @bitmap: an XCB Pixmap (a depth-1 pixmap)
+ * @width: the current width of @bitmap
+ * @height: the current height of @bitmap
+ *
+ * Creates an XCB surface that draws to the given bitmap.
+ * This will be drawn to as a CAIRO_FORMAT_A1 object.
+ *
+ * Return value: the newly created surface
+ **/
+cairo_surface_t *
+cairo_xcb_surface_create_for_bitmap (XCBConnection *c,
+ XCBPIXMAP bitmap,
+ int width,
+ int height)
+{
+ XCBDRAWABLE drawable;
+ drawable.pixmap = bitmap;
+ return _cairo_xcb_surface_create_internal (c, drawable,
+ NULL, NULL,
+ width, height, 1);
+}
+
+/**
+ * cairo_xcb_surface_create_with_xrender_format:
+ * @c: an XCB connection
+ * @drawable: an XCB drawable
+ * @format: the picture format to use for drawing to @drawable. The
+ * depth of @format mush match the depth of the drawable.
+ * @width: the current width of @drawable
+ * @height: the current height of @drawable
+ *
+ * Creates an XCB surface that draws to the given drawable.
+ * The way that colors are represented in the drawable is specified
+ * by the provided picture format.
+ *
+ * NOTE: If @drawable is a Window, then the function
+ * cairo_xlib_surface_set_size must be called whenever the size of the
+ * window changes.
+ *
+ * Return value: the newly created surface.
+ **/
+cairo_surface_t *
+cairo_xcb_surface_create_with_xrender_format (XCBConnection *c,
+ XCBDRAWABLE drawable,
+ XCBRenderPICTFORMINFO *format,
+ int width,
+ int height)
+{
+ return _cairo_xcb_surface_create_internal (c, drawable,
+ NULL, format,
+ width, height, 0);
+}
+
+/**
+ * cairo_xcb_surface_set_size:
+ * @surface: a #cairo_surface_t for the XCB backend
+ * @width: the new width of the surface
+ * @height: the new height of the surface
+ *
+ * Informs cairo of the new size of the XCB drawable underlying the
+ * surface. For a surface created for a window (rather than a pixmap),
+ * this function must be called each time the size of the window
+ * changes. (For a subwindow, you are normally resizing the window
+ * yourself, but for a toplevel window, it is necessary to listen for
+ * ConfigureNotify events.)
+ *
+ * A pixmap can never change size, so it is never necessary to call
+ * this function on a surface created for a pixmap.
+ **/
+void
+cairo_xcb_surface_set_size (cairo_surface_t *surface,
+ int width,
+ int height)
+{
+ cairo_xcb_surface_t *xcb_surface = (cairo_xcb_surface_t *)surface;
+
+ /* XXX: How do we want to handle this error case? */
+ if (! _cairo_surface_is_xcb (surface))
+ return;
+
+ xcb_surface->width = width;
+ xcb_surface->height = height;
+}
+
diff --git a/src/cairo_fixed.c b/src/cairo-xcb-xrender.h
index a4faa1708..ef4baa991 100644
--- a/src/cairo_fixed.c
+++ b/src/cairo-xcb-xrender.h
@@ -1,6 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2003 University of Southern California
+ * Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -34,58 +34,29 @@
* Carl D. Worth <cworth@cworth.org>
*/
-#include "cairoint.h"
+#ifndef CAIRO_XCB_XRENDER_H
+#define CAIRO_XCB_XRENDER_H
-cairo_fixed_t
-_cairo_fixed_from_int (int i)
-{
- return i << 16;
-}
+#include <cairo.h>
-cairo_fixed_t
-_cairo_fixed_from_double (double d)
-{
- return (cairo_fixed_t) (d * 65536);
-}
+#if CAIRO_HAS_XCB_SURFACE
-cairo_fixed_t
-_cairo_fixed_from_26_6 (uint32_t i)
-{
- return i << 10;
-}
+#include <X11/XCB/xcb.h>
+#include <X11/XCB/render.h>
-double
-_cairo_fixed_to_double (cairo_fixed_t f)
-{
- return ((double) f) / 65536.0;
-}
+CAIRO_BEGIN_DECLS
-int
-_cairo_fixed_is_integer (cairo_fixed_t f)
-{
- return (f & 0xFFFF) == 0;
-}
+cairo_surface_t *
+cairo_xcb_surface_create_with_xrender_format (XCBConnection *c,
+ XCBDRAWABLE drawable,
+ XCBRenderPICTFORMINFO *format,
+ int width,
+ int height);
-int
-_cairo_fixed_integer_part (cairo_fixed_t f)
-{
- return f >> 16;
-}
+CAIRO_END_DECLS
-int
-_cairo_fixed_integer_floor (cairo_fixed_t f)
-{
- if (f >= 0)
- return f >> 16;
- else
- return -((-f - 1) >> 16) - 1;
-}
+#else /* CAIRO_HAS_XCB_SURFACE */
+# error Cairo was not compiled with support for the xcb backend
+#endif /* CAIRO_HAS_XCB_SURFACE */
-int
-_cairo_fixed_integer_ceil (cairo_fixed_t f)
-{
- if (f >= 0)
- return ((f - 1)>>16) + 1;
- else
- return - (-f >> 16);
-}
+#endif /* CAIRO_XCB_XRENDER_H */
diff --git a/src/cairo-xcb.h b/src/cairo-xcb.h
index a5c65f441..57a7aebd1 100644
--- a/src/cairo-xcb.h
+++ b/src/cairo-xcb.h
@@ -39,21 +39,34 @@
#include <cairo.h>
-#ifdef CAIRO_HAS_XCB_SURFACE
+#if CAIRO_HAS_XCB_SURFACE
#include <X11/XCB/xcb.h>
-#include <X11/XCB/render.h>
CAIRO_BEGIN_DECLS
+cairo_surface_t *
+cairo_xcb_surface_create (XCBConnection *c,
+ XCBDRAWABLE pixmap,
+ XCBVISUALTYPE *visual,
+ int width,
+ int height);
+
+cairo_surface_t *
+cairo_xcb_surface_create_for_bitmap (XCBConnection *c,
+ XCBPIXMAP bitmap,
+ int width,
+ int height);
+
void
-cairo_set_target_xcb (cairo_t *cr,
- XCBConnection *dpy,
- XCBDRAWABLE drawable,
- XCBVISUALTYPE *visual,
- cairo_format_t format);
+cairo_xcb_surface_set_size (cairo_surface_t *surface,
+ int width,
+ int height);
CAIRO_END_DECLS
+#else /* CAIRO_HAS_XCB_SURFACE */
+# error Cairo was not compiled with support for the xcb backend
#endif /* CAIRO_HAS_XCB_SURFACE */
+
#endif /* CAIRO_XCB_H */
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 3eaef57e5..41fb00c44 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -36,66 +36,47 @@
#include "cairoint.h"
#include "cairo-xlib.h"
+#include "cairo-xlib-xrender.h"
+#include "cairo-xlib-test.h"
+#include <X11/extensions/Xrender.h>
-/**
- * cairo_set_target_drawable:
- * @cr: a #cairo_t
- * @dpy: an X display
- * @drawable: a window or pixmap on the default screen of @dpy
- *
- * Directs output for a #cairo_t to an Xlib drawable. @drawable must
- * be a Window or Pixmap on the default screen of @dpy using the
- * default colormap and visual. Using this function is slow because
- * the function must retrieve information about @drawable from the X
- * server.
-
- * The combination of cairo_xlib_surface_create() and
- * cairo_set_target_surface() is somewhat more flexible, although
- * it still is slow.
- **/
-void
-cairo_set_target_drawable (cairo_t *cr,
- Display *dpy,
- Drawable drawable)
-{
- cairo_surface_t *surface;
+/* Xlib doesn't define a typedef, so define one ourselves */
+typedef int (*cairo_xlib_error_func_t) (Display *display,
+ XErrorEvent *event);
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
+typedef struct _cairo_xlib_surface cairo_xlib_surface_t;
- surface = cairo_xlib_surface_create (dpy, drawable,
- DefaultVisual (dpy, DefaultScreen (dpy)),
- 0,
- DefaultColormap (dpy, DefaultScreen (dpy)));
- if (surface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
+static void _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface);
- cairo_set_target_surface (cr, surface);
+/*
+ * Instead of taking two round trips for each blending request,
+ * assume that if a particular drawable fails GetImage that it will
+ * fail for a "while"; use temporary pixmaps to avoid the errors
+ */
- /* cairo_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy (surface);
-}
+#define CAIRO_ASSUME_PIXMAP 20
-typedef struct _cairo_xlib_surface {
+struct _cairo_xlib_surface {
cairo_surface_t base;
Display *dpy;
GC gc;
Drawable drawable;
- int owns_pixmap;
+ cairo_bool_t owns_pixmap;
Visual *visual;
- cairo_format_t format;
+
+ int use_pixmap;
int render_major;
int render_minor;
int width;
int height;
+ int depth;
Picture picture;
-} cairo_xlib_surface_t;
+ XRenderPictFormat *format;
+};
#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
(((surface)->render_major > major) || \
@@ -120,6 +101,25 @@ typedef struct _cairo_xlib_surface {
#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
+static cairo_bool_t cairo_xlib_render_disabled = FALSE;
+
+/**
+ * cairo_test_xlib_disable_render:
+ *
+ * Disables the use of the RENDER extension.
+ *
+ * <note>
+ * This function is <emphasis>only</emphasis> intended for internal
+ * testing use within the cairo distribution. It is not installed in
+ * any public header file.
+ * </note>
+ **/
+void
+cairo_test_xlib_disable_render (void)
+{
+ cairo_xlib_render_disabled = TRUE;
+}
+
static int
_CAIRO_FORMAT_DEPTH (cairo_format_t format)
{
@@ -136,15 +136,23 @@ _CAIRO_FORMAT_DEPTH (cairo_format_t format)
}
}
-static cairo_surface_t *
-_cairo_xlib_surface_create_with_size (Display *dpy,
- Drawable drawable,
- Visual *visual,
- cairo_format_t format,
- Colormap colormap,
- int width,
- int height);
-
+static XRenderPictFormat *
+_CAIRO_FORMAT_XRENDER_FORMAT(Display *dpy, cairo_format_t format)
+{
+ int pict_format;
+ switch (format) {
+ case CAIRO_FORMAT_A1:
+ pict_format = PictStandardA1; break;
+ case CAIRO_FORMAT_A8:
+ pict_format = PictStandardA8; break;
+ case CAIRO_FORMAT_RGB24:
+ pict_format = PictStandardRGB24; break;
+ case CAIRO_FORMAT_ARGB32:
+ default:
+ pict_format = PictStandardARGB32; break;
+ }
+ return XRenderFindStandardFormat (dpy, pict_format);
+}
static cairo_surface_t *
_cairo_xlib_surface_create_similar (void *abstract_src,
@@ -158,6 +166,9 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
int scr;
Pixmap pix;
cairo_xlib_surface_t *surface;
+ int depth = _CAIRO_FORMAT_DEPTH (format);
+ XRenderPictFormat *xrender_format = _CAIRO_FORMAT_XRENDER_FORMAT (dpy,
+ format);
/* As a good first approximation, if the display doesn't have COMPOSITE,
* we're better off using image surfaces for all temporary operations
@@ -170,22 +181,20 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
pix = XCreatePixmap (dpy, DefaultRootWindow (dpy),
width <= 0 ? 1 : width, height <= 0 ? 1 : height,
- _CAIRO_FORMAT_DEPTH (format));
+ depth);
surface = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_with_size (dpy, pix, NULL, format,
- DefaultColormap (dpy, scr),
- width, height);
- surface->owns_pixmap = 1;
-
- surface->width = width;
- surface->height = height;
+ cairo_xlib_surface_create_with_xrender_format (dpy, pix,
+ xrender_format,
+ width, height);
+
+ surface->owns_pixmap = TRUE;
return &surface->base;
}
-static void
-_cairo_xlib_surface_destroy (void *abstract_surface)
+static cairo_status_t
+_cairo_xlib_surface_finish (void *abstract_surface)
{
cairo_xlib_surface_t *surface = abstract_surface;
if (surface->picture)
@@ -197,16 +206,56 @@ _cairo_xlib_surface_destroy (void *abstract_surface)
if (surface->gc)
XFreeGC (surface->dpy, surface->gc);
- surface->dpy = 0;
+ surface->dpy = NULL;
+
+ return CAIRO_STATUS_SUCCESS;
+}
- free (surface);
+static int
+_noop_error_handler (Display *display,
+ XErrorEvent *event)
+{
+ return False; /* return value is ignored */
}
-static double
-_cairo_xlib_surface_pixels_per_inch (void *abstract_surface)
+static cairo_bool_t
+_CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format)
{
- /* XXX: We should really get this value from somewhere like Xft.dpy */
- return 96.0;
+ switch (masks->bpp) {
+ case 32:
+ if (masks->alpha_mask == 0xff000000 &&
+ masks->red_mask == 0x00ff0000 &&
+ masks->green_mask == 0x0000ff00 &&
+ masks->blue_mask == 0x000000ff)
+ {
+ *format = CAIRO_FORMAT_ARGB32;
+ return True;
+ }
+ if (masks->alpha_mask == 0x00000000 &&
+ masks->red_mask == 0x00ff0000 &&
+ masks->green_mask == 0x0000ff00 &&
+ masks->blue_mask == 0x000000ff)
+ {
+ *format = CAIRO_FORMAT_RGB24;
+ return True;
+ }
+ break;
+ case 8:
+ if (masks->alpha_mask == 0xff)
+ {
+ *format = CAIRO_FORMAT_A8;
+ return True;
+ }
+ break;
+ case 1:
+ if (masks->alpha_mask == 0x1)
+ {
+ *format = CAIRO_FORMAT_A1;
+ return True;
+ }
+ break;
+ }
+ return False;
}
static cairo_status_t
@@ -217,15 +266,9 @@ _get_image_surface (cairo_xlib_surface_t *surface,
{
cairo_image_surface_t *image;
XImage *ximage;
- Window root_ignore;
- int x_ignore, y_ignore, bwidth_ignore, depth_ignore;
int x1, y1, x2, y2;
-
- XGetGeometry (surface->dpy,
- surface->drawable,
- &root_ignore, &x_ignore, &y_ignore,
- &surface->width, &surface->height,
- &bwidth_ignore, &depth_ignore);
+ cairo_format_masks_t masks;
+ cairo_format_t format;
x1 = 0;
y1 = 0;
@@ -233,14 +276,21 @@ _get_image_surface (cairo_xlib_surface_t *surface,
y2 = surface->height;
if (interest_rect) {
- if (interest_rect->x > x1)
- x1 = interest_rect->x;
- if (interest_rect->y > y1)
- y1 = interest_rect->y;
- if (interest_rect->x + interest_rect->width < x2)
- x2 = interest_rect->x + interest_rect->width;
- if (interest_rect->y + interest_rect->height < y2)
- y2 = interest_rect->y + interest_rect->height;
+ cairo_rectangle_t rect;
+
+ rect.x = interest_rect->x;
+ rect.y = interest_rect->y;
+ rect.width = interest_rect->width;
+ rect.height = interest_rect->width;
+
+ if (rect.x > x1)
+ x1 = rect.x;
+ if (rect.y > y1)
+ y1 = rect.y;
+ if (rect.x + rect.width < x2)
+ x2 = rect.x + rect.width;
+ if (rect.y + rect.height < y2)
+ y2 = rect.y + rect.height;
if (x1 >= x2 || y1 >= y2) {
*image_out = NULL;
@@ -255,36 +305,118 @@ _get_image_surface (cairo_xlib_surface_t *surface,
image_rect->height = y2 - y1;
}
- /* XXX: This should try to use the XShm extension if availible */
- ximage = XGetImage (surface->dpy,
- surface->drawable,
- x1, y1,
- x2 - x1, y2 - y1,
- AllPlanes, ZPixmap);
+ /* XXX: This should try to use the XShm extension if available */
- if (surface->visual) {
- cairo_format_masks_t masks;
+ if (surface->use_pixmap == 0)
+ {
+ cairo_xlib_error_func_t old_handler;
- /* XXX: Add support here for pictures with external alpha? */
+ old_handler = XSetErrorHandler (_noop_error_handler);
+
+ ximage = XGetImage (surface->dpy,
+ surface->drawable,
+ x1, y1,
+ x2 - x1, y2 - y1,
+ AllPlanes, ZPixmap);
+ XSetErrorHandler (old_handler);
+
+ /* If we get an error, the surface must have been a window,
+ * so retry with the safe code path.
+ */
+ if (!ximage)
+ surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
+ }
+ else
+ {
+ surface->use_pixmap--;
+ ximage = 0;
+ }
+
+ if (!ximage)
+ {
+
+ /* XGetImage from a window is dangerous because it can
+ * produce errors if the window is unmapped or partially
+ * outside the screen. We could check for errors and
+ * retry, but to keep things simple, we just create a
+ * temporary pixmap
+ */
+ Pixmap pixmap = XCreatePixmap (surface->dpy,
+ surface->drawable,
+ x2 - x1, y2 - y1,
+ surface->depth);
+ _cairo_xlib_surface_ensure_gc (surface);
+
+ XCopyArea (surface->dpy, surface->drawable, pixmap, surface->gc,
+ x1, y1, x2 - x1, y2 - y1, 0, 0);
+
+ ximage = XGetImage (surface->dpy,
+ pixmap,
+ 0, 0,
+ x2 - x1, y2 - y1,
+ AllPlanes, ZPixmap);
+
+ XFreePixmap (surface->dpy, pixmap);
+ }
+ if (!ximage)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ /*
+ * Compute the pixel format masks from either a visual or a
+ * XRenderFormat, failing we assume the drawable is an
+ * alpha-only pixmap as it could only have been created
+ * that way through the cairo_xlib_surface_create_for_bitmap
+ * function.
+ */
+ if (surface->visual) {
masks.bpp = ximage->bits_per_pixel;
masks.alpha_mask = 0;
masks.red_mask = surface->visual->red_mask;
masks.green_mask = surface->visual->green_mask;
masks.blue_mask = surface->visual->blue_mask;
+ } else if (surface->format) {
+ masks.bpp = ximage->bits_per_pixel;
+ masks.red_mask = surface->format->direct.redMask << surface->format->direct.red;
+ masks.green_mask = surface->format->direct.greenMask << surface->format->direct.green;
+ masks.blue_mask = surface->format->direct.blueMask << surface->format->direct.blue;
+ masks.alpha_mask = surface->format->direct.alphaMask << surface->format->direct.alpha;
+ } else {
+ masks.bpp = ximage->bits_per_pixel;
+ masks.red_mask = 0;
+ masks.green_mask = 0;
+ masks.blue_mask = 0;
+ if (surface->depth < 32)
+ masks.alpha_mask = (1 << surface->depth) - 1;
+ else
+ masks.alpha_mask = 0xffffffff;
+ }
- image = _cairo_image_surface_create_with_masks (ximage->data,
+ /*
+ * Prefer to use a standard pixman format instead of the
+ * general masks case.
+ */
+ if (_CAIRO_MASK_FORMAT (&masks, &format))
+ {
+ image = (cairo_image_surface_t *) cairo_image_surface_create_for_data ((unsigned char *) ximage->data,
+ format,
+ ximage->width,
+ ximage->height,
+ ximage->bytes_per_line);
+ }
+ else
+ {
+ /*
+ * XXX This can't work. We must convert the data to one of the
+ * supported pixman formats. Pixman needs another function
+ * which takes data in an arbitrary format and converts it
+ * to something supported by that library.
+ */
+ image = _cairo_image_surface_create_with_masks ((unsigned char *) ximage->data,
&masks,
ximage->width,
ximage->height,
ximage->bytes_per_line);
- } else {
- image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data (ximage->data,
- surface->format,
- ximage->width,
- ximage->height,
- ximage->bytes_per_line);
}
/* Let the surface take ownership of the data */
@@ -303,10 +435,14 @@ _get_image_surface (cairo_xlib_surface_t *surface,
static void
_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
{
+ XGCValues gcv;
+
if (surface->gc)
return;
- surface->gc = XCreateGC (surface->dpy, surface->drawable, 0, NULL);
+ gcv.graphics_exposures = False;
+ surface->gc = XCreateGC (surface->dpy, surface->drawable,
+ GCGraphicsExposures, &gcv);
}
static cairo_status_t
@@ -318,6 +454,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
XImage *ximage;
unsigned bitmap_pad;
+ /* XXX this is wrong */
if (image->depth > 16)
bitmap_pad = 32;
else if (image->depth > 8)
@@ -330,7 +467,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
image->depth,
ZPixmap,
0,
- image->data,
+ (char *) image->data,
image->width,
image->height,
bitmap_pad,
@@ -362,13 +499,8 @@ _cairo_xlib_surface_acquire_source_image (void *abstract_surf
cairo_status_t status;
status = _get_image_surface (surface, NULL, &image, NULL);
- if (status == CAIRO_STATUS_SUCCESS) {
- cairo_surface_set_filter (&image->base, surface->base.filter);
- cairo_surface_set_matrix (&image->base, &surface->base.matrix);
- cairo_surface_set_repeat (&image->base, surface->base.repeat);
-
+ if (status == CAIRO_STATUS_SUCCESS)
*image_out = image;
- }
return status;
}
@@ -459,13 +591,13 @@ _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
if (!surface->picture)
return CAIRO_STATUS_SUCCESS;
- xtransform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
- xtransform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
- xtransform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
+ xtransform.matrix[0][0] = _cairo_fixed_from_double (matrix->xx);
+ xtransform.matrix[0][1] = _cairo_fixed_from_double (matrix->xy);
+ xtransform.matrix[0][2] = _cairo_fixed_from_double (matrix->x0);
- xtransform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
- xtransform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
- xtransform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
+ xtransform.matrix[1][0] = _cairo_fixed_from_double (matrix->yx);
+ xtransform.matrix[1][1] = _cairo_fixed_from_double (matrix->yy);
+ xtransform.matrix[1][2] = _cairo_fixed_from_double (matrix->y0);
xtransform.matrix[2][0] = 0;
xtransform.matrix[2][1] = 0;
@@ -585,26 +717,29 @@ _render_operator (cairo_operator_t operator)
switch (operator) {
case CAIRO_OPERATOR_CLEAR:
return PictOpClear;
- case CAIRO_OPERATOR_SRC:
+
+ case CAIRO_OPERATOR_SOURCE:
return PictOpSrc;
- case CAIRO_OPERATOR_DST:
- return PictOpDst;
case CAIRO_OPERATOR_OVER:
return PictOpOver;
- case CAIRO_OPERATOR_OVER_REVERSE:
- return PictOpOverReverse;
case CAIRO_OPERATOR_IN:
return PictOpIn;
- case CAIRO_OPERATOR_IN_REVERSE:
- return PictOpInReverse;
case CAIRO_OPERATOR_OUT:
return PictOpOut;
- case CAIRO_OPERATOR_OUT_REVERSE:
- return PictOpOutReverse;
case CAIRO_OPERATOR_ATOP:
return PictOpAtop;
- case CAIRO_OPERATOR_ATOP_REVERSE:
+
+ case CAIRO_OPERATOR_DEST:
+ return PictOpDst;
+ case CAIRO_OPERATOR_DEST_OVER:
+ return PictOpOverReverse;
+ case CAIRO_OPERATOR_DEST_IN:
+ return PictOpInReverse;
+ case CAIRO_OPERATOR_DEST_OUT:
+ return PictOpOutReverse;
+ case CAIRO_OPERATOR_DEST_ATOP:
return PictOpAtopReverse;
+
case CAIRO_OPERATOR_XOR:
return PictOpXor;
case CAIRO_OPERATOR_ADD:
@@ -651,10 +786,8 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
return status;
status = _cairo_xlib_surface_set_attributes (src, &src_attr);
- if (CAIRO_OK (status))
- {
- if (mask)
- {
+ if (CAIRO_OK (status)) {
+ if (mask) {
status = _cairo_xlib_surface_set_attributes (mask, &mask_attr);
if (CAIRO_OK (status))
XRenderComposite (dst->dpy,
@@ -668,9 +801,7 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
mask_y + mask_attr.y_offset,
dst_x, dst_y,
width, height);
- }
- else
- {
+ } else {
XRenderComposite (dst->dpy,
_render_operator (operator),
src->picture,
@@ -777,83 +908,75 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator,
}
static cairo_int_status_t
-_cairo_xlib_surface_copy_page (void *abstract_surface)
+_cairo_xlib_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
+ cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
-static cairo_int_status_t
-_cairo_xlib_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (region == NULL) {
+ if (surface->gc)
+ XSetClipMask (surface->dpy, surface->gc, None);
+
+ if (surface->picture) {
+ XRenderPictureAttributes pa;
+ pa.clip_mask = None;
+ XRenderChangePicture (surface->dpy, surface->picture,
+ CPClipMask, &pa);
+ }
+ } else {
+ pixman_box16_t *boxes;
+ XRectangle *rects = NULL;
+ int n_boxes, i;
+
+ n_boxes = pixman_region_num_rects (region);
+ if (n_boxes > 0) {
+ rects = malloc (sizeof(XRectangle) * n_boxes);
+ if (rects == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+ } else {
+ rects = NULL;
+ }
+
+ boxes = pixman_region_rects (region);
+
+ for (i = 0; i < n_boxes; i++) {
+ rects[i].x = boxes[i].x1;
+ rects[i].y = boxes[i].y1;
+ rects[i].width = boxes[i].x2 - boxes[i].x1;
+ rects[i].height = boxes[i].y2 - boxes[i].y1;
+ }
+
+ if (surface->gc)
+ XSetClipRectangles(surface->dpy, surface->gc,
+ 0, 0, rects, n_boxes, YXSorted);
+ if (surface->picture)
+ XRenderSetPictureClipRectangles (surface->dpy, surface->picture,
+ 0, 0, rects, n_boxes);
+
+ if (rects)
+ free (rects);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
-_cairo_xlib_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
+_cairo_xlib_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t *rectangle)
{
+ cairo_xlib_surface_t *surface = abstract_surface;
- Region xregion;
- XRectangle xr;
- XRectangle *rects = NULL;
- XGCValues gc_values;
- pixman_box16_t *box;
- cairo_xlib_surface_t *surf;
- int n, m;
-
- surf = (cairo_xlib_surface_t *) abstract_surface;
+ rectangle->x = 0;
+ rectangle->y = 0;
- if (region == NULL) {
- /* NULL region == reset the clip */
- xregion = XCreateRegion();
- xr.x = 0;
- xr.y = 0;
- xr.width = surf->width;
- xr.height = surf->height;
- XUnionRectWithRegion (&xr, xregion, xregion);
- rects = malloc(sizeof(XRectangle));
- if (rects == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- rects[0] = xr;
- m = 1;
+ rectangle->width = surface->width;
+ rectangle->height = surface->height;
- } else {
- n = pixman_region_num_rects (region);
- /* XXX: Are we sure these are the semantics we want for an
- * empty, (not null) region? */
- if (n == 0)
- return CAIRO_STATUS_SUCCESS;
- rects = malloc(sizeof(XRectangle) * n);
- if (rects == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- box = pixman_region_rects (region);
- xregion = XCreateRegion();
-
- m = n;
- for (; n > 0; --n, ++box) {
- xr.x = (short) box->x1;
- xr.y = (short) box->y1;
- xr.width = (unsigned short) (box->x2 - box->x1);
- xr.height = (unsigned short) (box->y2 - box->y1);
- rects[n-1] = xr;
- XUnionRectWithRegion (&xr, xregion, xregion);
- }
- }
-
- _cairo_xlib_surface_ensure_gc (surf);
- XGetGCValues(surf->dpy, surf->gc, GCGraphicsExposures, &gc_values);
- XSetGraphicsExposures(surf->dpy, surf->gc, False);
- XSetClipRectangles(surf->dpy, surf->gc, 0, 0, rects, m, Unsorted);
- free(rects);
- if (surf->picture)
- XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
- XDestroyRegion(xregion);
- XSetGraphicsExposures(surf->dpy, surf->gc, gc_values.graphics_exposures);
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_xlib_surface_show_glyphs (cairo_font_t *font,
+static cairo_int_status_t
+_cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_operator_t operator,
cairo_pattern_t *pattern,
void *abstract_surface,
@@ -868,8 +991,7 @@ _cairo_xlib_surface_show_glyphs (cairo_font_t *font,
static const cairo_surface_backend_t cairo_xlib_surface_backend = {
_cairo_xlib_surface_create_similar,
- _cairo_xlib_surface_destroy,
- _cairo_xlib_surface_pixels_per_inch,
+ _cairo_xlib_surface_finish,
_cairo_xlib_surface_acquire_source_image,
_cairo_xlib_surface_release_source_image,
_cairo_xlib_surface_acquire_dest_image,
@@ -878,23 +1000,37 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
_cairo_xlib_surface_composite,
_cairo_xlib_surface_fill_rectangles,
_cairo_xlib_surface_composite_trapezoids,
- _cairo_xlib_surface_copy_page,
- _cairo_xlib_surface_show_page,
+ NULL, /* copy_page */
+ NULL, /* show_page */
_cairo_xlib_surface_set_clip_region,
+ _cairo_xlib_surface_get_extents,
_cairo_xlib_surface_show_glyphs
};
+/**
+ * _cairo_surface_is_xlib:
+ * @surface: a #cairo_surface_t
+ *
+ * Checks if a surface is a #cairo_xlib_surface_t
+ *
+ * Return value: True if the surface is an xlib surface
+ **/
+static cairo_bool_t
+_cairo_surface_is_xlib (cairo_surface_t *surface)
+{
+ return surface->backend == &cairo_xlib_surface_backend;
+}
+
static cairo_surface_t *
-_cairo_xlib_surface_create_with_size (Display *dpy,
- Drawable drawable,
- Visual *visual,
- cairo_format_t format,
- Colormap colormap,
- int width,
- int height)
+_cairo_xlib_surface_create_internal (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ XRenderPictFormat *format,
+ int width,
+ int height,
+ int depth)
{
cairo_xlib_surface_t *surface;
- int render_standard;
surface = malloc (sizeof (cairo_xlib_surface_t));
if (surface == NULL)
@@ -902,76 +1038,180 @@ _cairo_xlib_surface_create_with_size (Display *dpy,
_cairo_surface_init (&surface->base, &cairo_xlib_surface_backend);
- surface->visual = visual;
- surface->format = format;
-
surface->dpy = dpy;
- surface->gc = 0;
+ surface->gc = NULL;
surface->drawable = drawable;
- surface->owns_pixmap = 0;
+ surface->owns_pixmap = FALSE;
surface->visual = visual;
+ surface->format = format;
+ surface->use_pixmap = 0;
surface->width = width;
surface->height = height;
+ surface->depth = depth;
- if (! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) {
+ if (format) {
+ surface->depth = format->depth;
+ } else if (visual) {
+ int i, j, k;
+
+ /* This is ugly, but we have to walk over all visuals
+ * for the display to find the depth.
+ */
+ for (i = 0; i < ScreenCount (dpy); i++) {
+ Screen *screen = ScreenOfDisplay (dpy, i);
+ for (j = 0; j < screen->ndepths; j++) {
+ Depth *depth = &screen->depths[j];
+ for (k = 0; k < depth->nvisuals; k++) {
+ if (&depth->visuals[k] == visual) {
+ surface->depth = depth->depth;
+ goto found;
+ }
+ }
+ }
+ }
+ found:
+ ;
+ }
+
+ if (cairo_xlib_render_disabled ||
+ ! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) {
surface->render_major = -1;
surface->render_minor = -1;
}
- switch (format) {
- case CAIRO_FORMAT_A1:
- render_standard = PictStandardA1;
- break;
- case CAIRO_FORMAT_A8:
- render_standard = PictStandardA8;
- break;
- case CAIRO_FORMAT_RGB24:
- render_standard = PictStandardRGB24;
- break;
- case CAIRO_FORMAT_ARGB32:
- default:
- render_standard = PictStandardARGB32;
- break;
- }
+ surface->picture = None;
- /* XXX: I'm currently ignoring the colormap. Is that bad? */
- if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
- surface->picture = XRenderCreatePicture (dpy, drawable,
- visual ?
- XRenderFindVisualFormat (dpy, visual) :
- XRenderFindStandardFormat (dpy, render_standard),
- 0, NULL);
- else
- surface->picture = 0;
+ if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
+
+ if (!format) {
+ if (visual) {
+ format = XRenderFindVisualFormat (dpy, visual);
+ } else if (depth == 1)
+ format = XRenderFindStandardFormat (dpy, PictStandardA1);
+ }
+
+ if (format)
+ surface->picture = XRenderCreatePicture (dpy, drawable,
+ format, 0, NULL);
+ }
return (cairo_surface_t *) surface;
}
+/**
+ * cairo_xlib_surface_create:
+ * @dpy: an X Display
+ * @drawable: an X Drawable, (a Pixmap or a Window)
+ * @visual: the visual to use for drawing to @drawable. The depth
+ * of the visual must match the depth of the drawable.
+ * Currently, only TrueColor visuals are fully supported.
+ * @width: the current width of @drawable.
+ * @height: the current height of @drawable.
+ *
+ * Creates an Xlib surface that draws to the given drawable.
+ * The way that colors are represented in the drawable is specified
+ * by the provided visual.
+ *
+ * NOTE: If @drawable is a Window, then the function
+ * cairo_xlib_surface_set_size must be called whenever the size of the
+ * window changes.
+ *
+ * Return value: the newly created surface
+ **/
cairo_surface_t *
-cairo_xlib_surface_create (Display *dpy,
- Drawable drawable,
- Visual *visual,
- cairo_format_t format,
- Colormap colormap)
+cairo_xlib_surface_create (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ int width,
+ int height)
{
- Window window_ignore;
- unsigned int int_ignore;
- unsigned int width, height;
+ return _cairo_xlib_surface_create_internal (dpy, drawable,
+ visual, NULL, width, height, 0);
+}
- /* XXX: This call is a round-trip. We probably want to instead (or
- * also?) export a version that accepts width/height. Then, we'll
- * likely also need a resize function too.
- */
- XGetGeometry(dpy, drawable,
- &window_ignore, &int_ignore, &int_ignore,
- &width, &height,
- &int_ignore, &int_ignore);
+/**
+ * cairo_xlib_surface_create_for_bitmap:
+ * @dpy: an X Display
+ * @bitmap: an X Drawable, (a depth-1 Pixmap)
+ * @width: the current width of @bitmap.
+ * @height: the current height of @bitmap.
+ *
+ * Creates an Xlib surface that draws to the given bitmap.
+ * This will be drawn to as a CAIRO_FORMAT_A1 object.
+ *
+ * Return value: the newly created surface
+ **/
+cairo_surface_t *
+cairo_xlib_surface_create_for_bitmap (Display *dpy,
+ Pixmap bitmap,
+ int width,
+ int height)
+{
+ return _cairo_xlib_surface_create_internal (dpy, bitmap,
+ NULL, NULL, width, height, 1);
+}
+
+/**
+ * cairo_xlib_surface_create_with_xrender_format:
+ * @dpy: an X Display
+ * @drawable: an X Drawable, (a Pixmap or a Window)
+ * @format: the picture format to use for drawing to @drawable. The depth
+ * of @format must match the depth of the drawable.
+ * @width: the current width of @drawable.
+ * @height: the current height of @drawable.
+ *
+ * Creates an Xlib surface that draws to the given drawable.
+ * The way that colors are represented in the drawable is specified
+ * by the provided picture format.
+ *
+ * NOTE: If @drawable is a Window, then the function
+ * cairo_xlib_surface_set_size must be called whenever the size of the
+ * window changes.
+ *
+ * Return value: the newly created surface
+ **/
+cairo_surface_t *
+cairo_xlib_surface_create_with_xrender_format (Display *dpy,
+ Drawable drawable,
+ XRenderPictFormat *format,
+ int width,
+ int height)
+{
+ return _cairo_xlib_surface_create_internal (dpy, drawable,
+ NULL, format, width, height, 0);
+}
- return _cairo_xlib_surface_create_with_size (dpy, drawable, visual, format,
- colormap, width, height);
+/**
+ * cairo_xlib_surface_set_size:
+ * @surface: a #cairo_surface_t for the XLib backend
+ * @width: the new width of the surface
+ * @height: the new height of the surface
+ *
+ * Informs cairo of the new size of the X Drawable underlying the
+ * surface. For a surface created for a Window (rather than a Pixmap),
+ * this function must be called each time the size of the window
+ * changes. (For a subwindow, you are normally resizing the window
+ * yourself, but for a toplevel window, it is necessary to listen for
+ * ConfigureNotify events.)
+ *
+ * A Pixmap can never change size, so it is never necessary to call
+ * this function on a surface created for a Pixmap.
+ **/
+void
+cairo_xlib_surface_set_size (cairo_surface_t *surface,
+ int width,
+ int height)
+{
+ cairo_xlib_surface_t *xlib_surface = (cairo_xlib_surface_t *)surface;
+
+ /* XXX: How do we want to handle this error case? */
+ if (! _cairo_surface_is_xlib (surface))
+ return;
+
+ xlib_surface->width = width;
+ xlib_surface->height = height;
}
-DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create);
/* RENDER glyphset cache code */
@@ -1079,7 +1319,7 @@ _xlib_glyphset_cache_create_entry (void *cache,
XRenderAddGlyphs (g->display, g->glyphset,
&(v->glyph), &(v->info), 1,
- im->image ? im->image->data : NULL,
+ im->image ? (char *) im->image->data : NULL,
im->image ? v->info.height * v->info.width : 0);
v->key.base.memory = im->image ? im->image->width * im->image->stride : 0;
@@ -1186,7 +1426,7 @@ _get_glyphset_cache (Display *d)
#define N_STACK_BUF 1024
static cairo_status_t
-_cairo_xlib_surface_show_glyphs32 (cairo_font_t *font,
+_cairo_xlib_surface_show_glyphs32 (cairo_scaled_font_t *scaled_font,
cairo_operator_t operator,
glyphset_cache_t *g,
cairo_glyph_cache_key_t *key,
@@ -1263,7 +1503,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo_font_t *font,
static cairo_status_t
-_cairo_xlib_surface_show_glyphs16 (cairo_font_t *font,
+_cairo_xlib_surface_show_glyphs16 (cairo_scaled_font_t *scaled_font,
cairo_operator_t operator,
glyphset_cache_t *g,
cairo_glyph_cache_key_t *key,
@@ -1339,7 +1579,7 @@ _cairo_xlib_surface_show_glyphs16 (cairo_font_t *font,
}
static cairo_status_t
-_cairo_xlib_surface_show_glyphs8 (cairo_font_t *font,
+_cairo_xlib_surface_show_glyphs8 (cairo_scaled_font_t *scaled_font,
cairo_operator_t operator,
glyphset_cache_t *g,
cairo_glyph_cache_key_t *key,
@@ -1415,8 +1655,8 @@ _cairo_xlib_surface_show_glyphs8 (cairo_font_t *font,
}
-static cairo_status_t
-_cairo_xlib_surface_show_glyphs (cairo_font_t *font,
+static cairo_int_status_t
+_cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_operator_t operator,
cairo_pattern_t *pattern,
void *abstract_surface,
@@ -1471,7 +1711,7 @@ _cairo_xlib_surface_show_glyphs (cairo_font_t *font,
/* Work out the index size to use. */
elt_size = 8;
- _cairo_font_get_glyph_cache_key (font, &key);
+ _cairo_scaled_font_get_glyph_cache_key (scaled_font, &key);
for (i = 0; i < num_glyphs; ++i) {
key.index = glyphs[i].index;
@@ -1499,17 +1739,17 @@ _cairo_xlib_surface_show_glyphs (cairo_font_t *font,
/* Call the appropriate sub-function. */
if (elt_size == 8)
- status = _cairo_xlib_surface_show_glyphs8 (font, operator, g, &key, src, self,
+ status = _cairo_xlib_surface_show_glyphs8 (scaled_font, operator, g, &key, src, self,
source_x + attributes.x_offset,
source_y + attributes.y_offset,
glyphs, entries, num_glyphs);
else if (elt_size == 16)
- status = _cairo_xlib_surface_show_glyphs16 (font, operator, g, &key, src, self,
+ status = _cairo_xlib_surface_show_glyphs16 (scaled_font, operator, g, &key, src, self,
source_x + attributes.x_offset,
source_y + attributes.y_offset,
glyphs, entries, num_glyphs);
else
- status = _cairo_xlib_surface_show_glyphs32 (font, operator, g, &key, src, self,
+ status = _cairo_xlib_surface_show_glyphs32 (scaled_font, operator, g, &key, src, self,
source_x + attributes.x_offset,
source_y + attributes.y_offset,
glyphs, entries, num_glyphs);
diff --git a/src/cairo-png.h b/src/cairo-xlib-test.h
index 3e86210b0..44b986c7f 100644
--- a/src/cairo-png.h
+++ b/src/cairo-xlib-test.h
@@ -1,6 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -34,31 +34,22 @@
* Carl D. Worth <cworth@cworth.org>
*/
-#ifndef CAIRO_PNG_H
-#define CAIRO_PNG_H
+#ifndef CAIRO_XLIB_TEST_H
+#define CAIRO_XLIB_TEST_H
#include <cairo.h>
-#ifdef CAIRO_HAS_PNG_SURFACE
+#if CAIRO_HAS_XLIB_SURFACE
-#include <stdio.h>
+#include <cairo-xlib.h>
CAIRO_BEGIN_DECLS
void
-cairo_set_target_png (cairo_t *cr,
- FILE *file,
- cairo_format_t format,
- int width,
- int height);
-
-cairo_surface_t *
-cairo_png_surface_create (FILE *file,
- cairo_format_t format,
- int width,
- int height);
+cairo_test_xlib_disable_render (void);
CAIRO_END_DECLS
-#endif /* CAIRO_HAS_PNG_SURFACE */
-#endif /* CAIRO_PNG_H */
+#endif /* CAIRO_HAS_XLIB_SURFACE */
+#endif /* CAIRO_XLIB_H */
+
diff --git a/src/cairo_color.c b/src/cairo-xlib-xrender.h
index f203d96cc..08a8624e2 100644
--- a/src/cairo_color.c
+++ b/src/cairo-xlib-xrender.h
@@ -34,64 +34,29 @@
* Carl D. Worth <cworth@cworth.org>
*/
-#include "cairoint.h"
+#ifndef CAIRO_XLIB_XRENDER_H
+#define CAIRO_XLIB_XRENDER_H
-static cairo_color_t const CAIRO_COLOR_WHITE = {
- 1.0, 1.0, 1.0, 1.0,
- 0xffff, 0xffff, 0xffff, 0xffff
-};
+#include <cairo.h>
-static void
-_cairo_color_compute_shorts (cairo_color_t *color);
+#if CAIRO_HAS_XLIB_SURFACE
-void
-_cairo_color_init (cairo_color_t *color)
-{
- *color = CAIRO_COLOR_WHITE;
-}
+#include <X11/extensions/Xrender.h>
-void
-_cairo_color_fini (cairo_color_t *color)
-{
- /* Nothing to do here */
-}
+CAIRO_BEGIN_DECLS
-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_surface_t *
+cairo_xlib_surface_create_with_xrender_format (Display *dpy,
+ Drawable drawable,
+ XRenderPictFormat *format,
+ int width,
+ int height);
- _cairo_color_compute_shorts (color);
-}
-void
-_cairo_color_get_rgb (const cairo_color_t *color,
- double *red, double *green, double *blue)
-{
- if (red)
- *red = color->red;
- if (green)
- *green = color->green;
- if (blue)
- *blue = color->blue;
-}
+CAIRO_END_DECLS
-void
-_cairo_color_set_alpha (cairo_color_t *color, double alpha)
-{
- color->alpha = alpha;
-
- _cairo_color_compute_shorts (color);
-}
-
-static void
-_cairo_color_compute_shorts (cairo_color_t *color)
-{
- color->red_short = (color->red * color->alpha) * 0xffff;
- color->green_short = (color->green * color->alpha) * 0xffff;
- color->blue_short = (color->blue * color->alpha) * 0xffff;
- color->alpha_short = color->alpha * 0xffff;
-}
+#else /* CAIRO_HAS_XLIB_SURFACE */
+# error Cairo was not compiled with support for the xlib backend
+#endif /* CAIRO_HAS_XLIB_SURFACE */
+#endif /* CAIRO_XLIB_XRENDER_H */
diff --git a/src/cairo-xlib.h b/src/cairo-xlib.h
index 18db7b114..3fe285fdb 100644
--- a/src/cairo-xlib.h
+++ b/src/cairo-xlib.h
@@ -39,38 +39,35 @@
#include <cairo.h>
-#ifdef CAIRO_HAS_XLIB_SURFACE
+#if CAIRO_HAS_XLIB_SURFACE
-#include <X11/extensions/Xrender.h>
+#include <X11/Xlib.h>
CAIRO_BEGIN_DECLS
-/* XXX: This shold be renamed to cairo_set_target_xlib to match the
- * other backends */
-void
-cairo_set_target_drawable (cairo_t *cr,
- Display *dpy,
- Drawable drawable);
+cairo_surface_t *
+cairo_xlib_surface_create (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ int width,
+ int height);
-/* 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_xlib_surface_create (Display *dpy,
- Drawable drawable,
- Visual *visual,
- cairo_format_t format,
- Colormap colormap);
-
-/* XXX: This has been proposed
-cairo_status_t
-cairo_xlib_surface_set_size (cairo_surface_t *surface, int width, int height);
-*/
+cairo_xlib_surface_create_for_bitmap (Display *dpy,
+ Pixmap bitmap,
+ int width,
+ int height);
+
+void
+cairo_xlib_surface_set_size (cairo_surface_t *surface,
+ int width,
+ int height);
CAIRO_END_DECLS
+#else /* CAIRO_HAS_XLIB_SURFACE */
+# error Cairo was not compiled with support for the xlib backend
#endif /* CAIRO_HAS_XLIB_SURFACE */
+
#endif /* CAIRO_XLIB_H */
diff --git a/src/cairo.c b/src/cairo.c
index fd10b5cac..f825c733e 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -34,13 +35,18 @@
* Carl D. Worth <cworth@cworth.org>
*/
-
#include "cairoint.h"
+#include "cairo-private.h"
+
+#include "cairo-arc-private.h"
+#include "cairo-path-data-private.h"
#define CAIRO_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */
-#ifdef CAIRO_DO_SANITY_CHECKING
#include <assert.h>
+#ifdef NDEBUG
+#define CAIRO_CHECK_SANITY(cr)
+#else
static int
cairo_sane_state (cairo_t *cr)
{
@@ -56,6 +62,8 @@ cairo_sane_state (cairo_t *cr)
case CAIRO_STATUS_INVALID_MATRIX:
case CAIRO_STATUS_NO_TARGET_SURFACE:
case CAIRO_STATUS_NULL_POINTER:
+ case CAIRO_STATUS_INVALID_STRING:
+ case CAIRO_STATUS_INVALID_PATH_DATA:
break;
default:
return 0;
@@ -63,25 +71,38 @@ cairo_sane_state (cairo_t *cr)
return 1;
}
#define CAIRO_CHECK_SANITY(cr) assert(cairo_sane_state ((cr)))
-#else
-#define CAIRO_CHECK_SANITY(cr)
#endif
-
-/**
+/*
* cairo_create:
+ * @target: target surface for the context
*
- * Creates a new #cairo_t with default values. The target
- * surface must be set on the #cairo_t with cairo_set_target_surface(),
- * or a backend-specific function like cairo_set_target_image() before
- * drawing with the #cairo_t.
+ * Creates a new #cairo_t with all graphics state parameters set to
+ * default values and with @target as a target surface. The target
+ * surface should be constructed with a backend-specific function such
+ * as cairo_image_surface_create (or any other
+ * cairo_<backend>_surface_create variant).
+ *
+ * This function references @target, so you can immediately
+ * call cairo_surface_destroy() on it if you don't need to
+ * maintain a separate reference to it.
+ *
+ * Note that there are restrictions on using the same surface in
+ * multiple contexts at the same time. If, after creating @cr_a with
+ * @surface you also create @cr_b with the same surface, you must
+ * ensure that @cr_b has finished using @surface before resuming use
+ * of @cr_a. Currently, the only way time at which this is guaranteed
+ * is when the the last reference to @cr_b is released with
+ * cairo_destroy(). (XXX: We need to add a cairo_finish() call to
+ * provide a way to achieve this explicitly). See also the
+ * %CAIRO_STATUS_BAD_NESTING status.
*
* Return value: a newly allocated #cairo_t with a reference
* count of 1. The initial reference count should be released
* with cairo_destroy() when you are done using the #cairo_t.
- **/
+ */
cairo_t *
-cairo_create (void)
+cairo_create (cairo_surface_t *target)
{
cairo_t *cr;
@@ -92,7 +113,15 @@ cairo_create (void)
cr->status = CAIRO_STATUS_SUCCESS;
cr->ref_count = 1;
- cr->gstate = _cairo_gstate_create ();
+ _cairo_path_fixed_init (&cr->path);
+
+ if (target == NULL) {
+ cr->gstate = NULL;
+ cr->status = CAIRO_STATUS_NULL_POINTER;
+ return cr;
+ }
+
+ cr->gstate = _cairo_gstate_create (target);
if (cr->gstate == NULL)
cr->status = CAIRO_STATUS_NO_MEMORY;
@@ -125,7 +154,7 @@ cairo_reference (cairo_t *cr)
*
* Decreases the reference count on @cr by one. If the result
* is zero, then @cr and all associated resources are freed.
- * See cairo_destroy().
+ * See cairo_reference().
**/
void
cairo_destroy (cairo_t *cr)
@@ -142,6 +171,8 @@ cairo_destroy (cairo_t *cr)
_cairo_gstate_destroy (tmp);
}
+ _cairo_path_fixed_fini (&cr->path);
+
free (cr);
}
@@ -170,11 +201,7 @@ cairo_save (cairo_t *cr)
if (cr->status)
return;
- if (cr->gstate) {
- top = _cairo_gstate_clone (cr->gstate);
- } else {
- top = _cairo_gstate_create ();
- }
+ top = _cairo_gstate_clone (cr->gstate);
if (top == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
@@ -216,44 +243,10 @@ cairo_restore (cairo_t *cr)
if (cr->status)
return;
- cr->status = _cairo_gstate_restore_external_state (cr->gstate);
-
CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_restore);
-/**
- * cairo_copy:
- * @dest: a #cairo_t
- * @src: another #cairo_t
- *
- * This function copies all current state information from src to
- * dest. This includes the current point and path, the target surface,
- * the transformation matrix, and so forth.
- *
- * The stack of states saved with cairo_save() is <emphasis>not</emphasis>
- * not copied; nor are any saved states on @dest cleared. The
- * operation only copies the current state of @src to the current
- * state of @dest.
- **/
-void
-cairo_copy (cairo_t *dest, cairo_t *src)
-{
- CAIRO_CHECK_SANITY (src);
- CAIRO_CHECK_SANITY (dest);
- if (dest->status)
- return;
-
- if (src->status) {
- dest->status = src->status;
- return;
- }
-
- dest->status = _cairo_gstate_copy (dest->gstate, src->gstate);
- CAIRO_CHECK_SANITY (src);
- CAIRO_CHECK_SANITY (dest);
-}
-
/* XXX: I want to rethink this API
void
cairo_push_group (cairo_t *cr)
@@ -283,130 +276,176 @@ cairo_pop_group (cairo_t *cr)
*/
/**
- * cairo_set_target_surface:
+ * cairo_set_operator:
* @cr: a #cairo_t
- * @surface: a #cairo_surface_t
+ * @op: a compositing operator, specified as a #cairo_operator_t
*
- * Directs output for a #cairo_t to a given surface. The surface
- * will be referenced by the #cairo_t, so you can immediately
- * call cairo_surface_destroy() on it if you don't need to
- * keep a reference to it around.
+ * Sets the compositing operator to be used for all drawing
+ * operations. See #cairo_operator_t for details on the semantics of
+ * each available drawing operator.
+ *
+ * XXX: I'd also like to direct the reader's attention to some
+ * (not-yet-written) section on cairo's imaging model. How would I do
+ * that if such a section existed? (cworth).
**/
void
-cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface)
+cairo_set_operator (cairo_t *cr, cairo_operator_t op)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_set_target_surface (cr->gstate, surface);
+ cr->status = _cairo_gstate_set_operator (cr->gstate, op);
CAIRO_CHECK_SANITY (cr);
}
-slim_hidden_def(cairo_set_target_surface);
/**
- * cairo_set_target_image:
- * @cr: a #cairo_t
- * @data: a pointer to a buffer supplied by the application
- * in which to write contents.
- * @format: the format of pixels in the buffer
- * @width: the width of the image to be stored in the buffer
- * @height: the eight of the image to be stored in the buffer
- * @stride: the number of bytes between the start of rows
- * in the buffer. Having this be specified separate from @width
- * allows for padding at the end of rows, or for writing
- * to a subportion of a larger image.
- *
- * Directs output for a #cairo_t to an in-memory image. The output
- * buffer must be kept around until the #cairo_t is destroyed or set
- * to to have a different target. The initial contents of @buffer
- * will be used as the inital image contents; you must explicitely
- * clear the buffer, using, for example, cairo_rectangle() and
- * cairo_fill() if you want it cleared.
+ * cairo_set_source_rgb
+ * @cr: a cairo context
+ * @red: red component of color
+ * @green: green component of color
+ * @blue: blue component of color
+ *
+ * Sets the source pattern within @cr to an opaque color. This opaque
+ * color will then be used for any subsequent drawing operation until
+ * a new source pattern is set.
+ *
+ * The color components are floating point numbers in the range 0 to
+ * 1. If the values passed in are outside that range, they will be
+ * clamped.
**/
void
-cairo_set_target_image (cairo_t *cr,
- char *data,
- cairo_format_t format,
- int width,
- int height,
- int stride)
+cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue)
{
- cairo_surface_t *surface;
+ cairo_color_t color;
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- surface = cairo_surface_create_for_image (data,
- format,
- width, height, stride);
- if (surface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- CAIRO_CHECK_SANITY (cr);
- 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);
- cairo_set_target_surface (cr, surface);
+ _cairo_color_init_rgb (&color, red, green, blue);
- cairo_surface_destroy (surface);
+ cr->status = _cairo_gstate_set_source_solid (cr->gstate, &color);
+
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_source_rgba:
+ * @cr: a cairo context
+ * @red: red component of color
+ * @green: green component of color
+ * @blue: blue component of color
+ * @alpha: alpha component of color
+ *
+ * Sets the source pattern within @cr to a translucent color. This
+ * color will then be used for any subsequent drawing operation until
+ * a new source pattern is set.
+ *
+ * The color and alpha components are floating point numbers in the
+ * range 0 to 1. If the values passed in are outside that range, they
+ * will be clamped.
+ **/
void
-cairo_set_operator (cairo_t *cr, cairo_operator_t op)
+cairo_set_source_rgba (cairo_t *cr,
+ double red, double green, double blue,
+ double alpha)
{
+ cairo_color_t color;
+
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_set_operator (cr->gstate, op);
+ _cairo_restrict_value (&red, 0.0, 1.0);
+ _cairo_restrict_value (&green, 0.0, 1.0);
+ _cairo_restrict_value (&blue, 0.0, 1.0);
+ _cairo_restrict_value (&alpha, 0.0, 1.0);
+
+ _cairo_color_init_rgba (&color, red, green, blue, alpha);
+
+ cr->status = _cairo_gstate_set_source_solid (cr->gstate, &color);
+
CAIRO_CHECK_SANITY (cr);
}
-/**
- * cairo_set_rgb_color:
- * @cr: a #cairo_t
- * @red: red component of color
- * @green: green component of color
- * @blue: blue component of color
- *
- * Sets a constant color for filling and stroking. This replaces any
- * pattern set with cairo_set_pattern(). The color components are
- * floating point numbers in the range 0 to 1. If the values passed in
- * are outside that range, they will be clamped.
- **/
void
-cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue)
+cairo_set_source_surface (cairo_t *cr,
+ cairo_surface_t *surface,
+ double x,
+ double y)
{
+ cairo_pattern_t *pattern;
+ cairo_matrix_t matrix;
+
CAIRO_CHECK_SANITY (cr);
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);
+ pattern = cairo_pattern_create_for_surface (surface);
+ if (!pattern) {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cairo_matrix_init_translate (&matrix, -x, -y);
+ cairo_pattern_set_matrix (pattern, &matrix);
+
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
- cr->status = _cairo_gstate_set_rgb_color (cr->gstate, red, green, blue);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_source
+ * @cr: a cairo context
+ * @source: a #cairo_pattern_t to be used as the source for
+ * subsequent drawing operations.
+ *
+ * Sets the source pattern within @cr to @source. This pattern
+ * will then be used for any subsequent drawing operation until a new
+ * source pattern is set.
+ *
+ * XXX: I'd also like to direct the reader's attention to some
+ * (not-yet-written) section on cairo's imaging model. How would I do
+ * that if such a section existed? (cworth).
+ **/
void
-cairo_set_pattern (cairo_t *cr, cairo_pattern_t *pattern)
+cairo_set_source (cairo_t *cr, cairo_pattern_t *source)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_set_pattern (cr->gstate, pattern);
+ cr->status = _cairo_gstate_set_source (cr->gstate, source);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_get_source:
+ * @cr: a cairo context
+ *
+ * Gets the current source pattern for @cr.
+ *
+ * Return value: the current source pattern. This object is owned by
+ * cairo. To keep a reference to it, you must call
+ * cairo_pattern_reference().
+ **/
cairo_pattern_t *
-cairo_current_pattern (cairo_t *cr)
+cairo_get_source (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_pattern (cr->gstate);
+ /* XXX: We'll want to do something like this:
+ if (cr->status)
+ return cairo_pattern_nil;
+ */
+
+ return _cairo_gstate_get_source (cr->gstate);
}
/**
@@ -436,30 +475,17 @@ cairo_set_tolerance (cairo_t *cr, double tolerance)
}
/**
- * cairo_set_alpha:
+ * cairo_set_fill_rule:
* @cr: a #cairo_t
- * @alpha: the alpha value. 0 is transparent, 1 fully opaque.
- * if the value is outside the range 0 to 1, it will be
- * clamped to that range.
- *
- * Sets an overall alpha value used for stroking and filling. This
- * value is multiplied with any alpha value coming from a gradient or
- * image pattern.
+ * @fill_rule: a fill rule, specified as a #cairo_fill_rule_t
+ *
+ * Set the current fill rule within the cairo context. The fill rule
+ * is used to determine which regions are inside or outside a complex
+ * (potentially self-intersecting) path. The current fill rule affects
+ * both cairo_fill and cairo_clip. See #cairo_fill_rule_t for details
+ * on the semantics of each available fill rule.
**/
void
-cairo_set_alpha (cairo_t *cr, double alpha)
-{
- CAIRO_CHECK_SANITY (cr);
- if (cr->status)
- return;
-
- _cairo_restrict_value (&alpha, 0.0, 1.0);
-
- cr->status = _cairo_gstate_set_alpha (cr->gstate, alpha);
- CAIRO_CHECK_SANITY (cr);
-}
-
-void
cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule)
{
CAIRO_CHECK_SANITY (cr);
@@ -470,6 +496,20 @@ cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule)
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_line_width:
+ * @cr: a #cairo_t
+ * @width: a line width, as a user-space value
+ *
+ * Sets the current line width within the cairo context. The line
+ * width specifies the diameter of a pen that is circular in
+ * user-space.
+ *
+ * As with the other stroke parameters, the current line cap style is
+ * examined by cairo_stroke(), cairo_stroke_extents(), and
+ * cairo_stroke_to_path(), but does not have any effect during path
+ * construction.
+ **/
void
cairo_set_line_width (cairo_t *cr, double width)
{
@@ -483,6 +523,20 @@ cairo_set_line_width (cairo_t *cr, double width)
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_line_cap:
+ * @cr: a cairo context, as a #cairo_t
+ * @line_cap: a line cap style, as a #cairo_line_cap_t
+ *
+ * Sets the current line cap style within the cairo context. See
+ * #cairo_line_cap_t for details about how the available line cap
+ * styles are drawn.
+ *
+ * As with the other stroke parameters, the current line cap style is
+ * examined by cairo_stroke(), cairo_stroke_extents(), and
+ * cairo_stroke_to_path(), but does not have any effect during path
+ * construction.
+ **/
void
cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap)
{
@@ -494,6 +548,20 @@ cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap)
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_line_join:
+ * @cr: a cairo context, as a #cairo_t
+ * @line_join: a line joint style, as a #cairo_line_join_t
+ *
+ * Sets the current line join style within the cairo context. See
+ * #cairo_line_join_t for details about how the available line join
+ * styles are drawn.
+ *
+ * As with the other stroke parameters, the current line join style is
+ * examined by cairo_stroke(), cairo_stroke_extents(), and
+ * cairo_stroke_to_path(), but does not have any effect during path
+ * construction.
+ **/
void
cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join)
{
@@ -527,6 +595,19 @@ cairo_set_miter_limit (cairo_t *cr, double limit)
CAIRO_CHECK_SANITY (cr);
}
+
+/**
+ * cairo_translate:
+ * @cr: a cairo context
+ * @tx: amount to translate in the X direction
+ * @ty: amount to translate in the Y direction
+ *
+ * Modifies the current transformation matrix (CTM) by tanslating the
+ * user-space origin by (@tx, @ty). This offset is interpreted as a
+ * user-space coordinate according to the CTM in place before the new
+ * call to cairo_translate. In other words, the translation of the
+ * user-space origin takes place after any existing transformation.
+ **/
void
cairo_translate (cairo_t *cr, double tx, double ty)
{
@@ -538,6 +619,17 @@ cairo_translate (cairo_t *cr, double tx, double ty)
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_scale:
+ * @cr: a cairo context
+ * @sx: scale factor for the X dimension
+ * @sy: scale factor for the Y dimension
+ *
+ * Modifies the current transformation matrix (CTM) by scaling the X
+ * and Y user-space axes by @sx and @sy respectively. The scaling of
+ * the axes takes place after any existing transformation of user
+ * space.
+ **/
void
cairo_scale (cairo_t *cr, double sx, double sy)
{
@@ -549,6 +641,19 @@ cairo_scale (cairo_t *cr, double sx, double sy)
CAIRO_CHECK_SANITY (cr);
}
+
+/**
+ * cairo_rotate:
+ * @cr: a cairo context
+ * @angle: angle (in radians) by which the user-space axes will be
+ * rotated
+ *
+ * Modifies the current transformation matrix (CTM) by rotating the
+ * user-space axes by @angle radians. The rotation of the axes takes
+ * places after any existing transformation of user space. The
+ * rotation direction for positive angles is from the positive X axis
+ * toward the positive Y axis.
+ **/
void
cairo_rotate (cairo_t *cr, double angle)
{
@@ -560,21 +665,38 @@ cairo_rotate (cairo_t *cr, double angle)
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_transform:
+ * @cr: a cairo context
+ * @matrix: a transformation to be applied to the user-space axes
+ *
+ * Modifies the current transformation matrix (CTM) by applying
+ * @matrix as an additional transformation. The new transformation of
+ * user space takes place after any existing transformation.
+ **/
void
-cairo_concat_matrix (cairo_t *cr,
- cairo_matrix_t *matrix)
+cairo_transform (cairo_t *cr,
+ const cairo_matrix_t *matrix)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_concat_matrix (cr->gstate, matrix);
+ cr->status = _cairo_gstate_transform (cr->gstate, matrix);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_matrix:
+ * @cr: a cairo context
+ * @matrix: a transformation matrix from user space to device space
+ *
+ * Modifies the current transformation matrix (CTM) by setting it
+ * equal to @matrix.
+ **/
void
-cairo_set_matrix (cairo_t *cr,
- cairo_matrix_t *matrix)
+cairo_set_matrix (cairo_t *cr,
+ const cairo_matrix_t *matrix)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
@@ -584,17 +706,15 @@ cairo_set_matrix (cairo_t *cr,
CAIRO_CHECK_SANITY (cr);
}
-void
-cairo_default_matrix (cairo_t *cr)
-{
- CAIRO_CHECK_SANITY (cr);
- if (cr->status)
- return;
-
- cr->status = _cairo_gstate_default_matrix (cr->gstate);
- CAIRO_CHECK_SANITY (cr);
-}
-
+/**
+ * cairo_identity_matrix:
+ * @cr: a cairo context
+ *
+ * Resets the current transformation matrix (CTM) by setting it equal
+ * to the identity matrix. That is, the user-space and device-space
+ * axes will be aligned and one user-space unit will transform to one
+ * device-space unit.
+ **/
void
cairo_identity_matrix (cairo_t *cr)
{
@@ -606,47 +726,89 @@ cairo_identity_matrix (cairo_t *cr)
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_user_to_device:
+ * @cr: a cairo context
+ * @x: X value of coordinate (in/out parameter)
+ * @y: Y value of coordinate (in/out parameter)
+ *
+ * Transform a coordinate from user space to device space by
+ * multiplying the given point by the current transformation matrix
+ * (CTM).
+ **/
void
-cairo_transform_point (cairo_t *cr, double *x, double *y)
+cairo_user_to_device (cairo_t *cr, double *x, double *y)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_transform_point (cr->gstate, x, y);
+ cr->status = _cairo_gstate_user_to_device (cr->gstate, x, y);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_user_to_device_distance:
+ * @cr: a cairo context
+ * @dx: X component of a distance vector (in/out parameter)
+ * @dy: Y component of a distance vector (in/out parameter)
+ *
+ * Transform a distance vector from user space to device space. This
+ * function is similar to cairo_user_to_device() except that the
+ * translation components of the CTM will be ignored when transforming
+ * (@dx,@dy).
+ **/
void
-cairo_transform_distance (cairo_t *cr, double *dx, double *dy)
+cairo_user_to_device_distance (cairo_t *cr, double *dx, double *dy)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_transform_distance (cr->gstate, dx, dy);
+ cr->status = _cairo_gstate_user_to_device_distance (cr->gstate, dx, dy);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_device_to_user:
+ * @cr: a cairo
+ * @x: X value of coordinate (in/out parameter)
+ * @y: Y value of coordinate (in/out parameter)
+ *
+ * Transform a coordinate from device space to user space by
+ * multiplying the given point by the inverse of the current
+ * transformation matrix (CTM).
+ **/
void
-cairo_inverse_transform_point (cairo_t *cr, double *x, double *y)
+cairo_device_to_user (cairo_t *cr, double *x, double *y)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_inverse_transform_point (cr->gstate, x, y);
+ cr->status = _cairo_gstate_device_to_user (cr->gstate, x, y);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_device_to_user_distance:
+ * @cr: a cairo context
+ * @dx: X component of a distance vector (in/out parameter)
+ * @dy: Y component of a distance vector (in/out parameter)
+ *
+ * Transform a distance vector from device space to user space. This
+ * function is similar to cairo_device_to_user() except that the
+ * translation components of the inverse CTM will be ignored when
+ * transforming (@dx,@dy).
+ **/
void
-cairo_inverse_transform_distance (cairo_t *cr, double *dx, double *dy)
+cairo_device_to_user_distance (cairo_t *cr, double *dx, double *dy)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_inverse_transform_distance (cr->gstate, dx, dy);
+ cr->status = _cairo_gstate_device_to_user_distance (cr->gstate, dx, dy);
CAIRO_CHECK_SANITY (cr);
}
@@ -657,18 +819,27 @@ cairo_new_path (cairo_t *cr)
if (cr->status)
return;
- cr->status = _cairo_gstate_new_path (cr->gstate);
+ _cairo_path_fixed_fini (&cr->path);
+
CAIRO_CHECK_SANITY (cr);
}
+slim_hidden_def(cairo_new_path);
void
cairo_move_to (cairo_t *cr, double x, double y)
{
+ cairo_fixed_t x_fixed, y_fixed;
+
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_move_to (cr->gstate, x, y);
+ _cairo_gstate_user_to_backend (cr->gstate, &x, &y);
+ x_fixed = _cairo_fixed_from_double (x);
+ y_fixed = _cairo_fixed_from_double (y);
+
+ cr->status = _cairo_path_fixed_move_to (&cr->path, x_fixed, y_fixed);
+
CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_move_to);
@@ -676,11 +847,18 @@ slim_hidden_def(cairo_move_to);
void
cairo_line_to (cairo_t *cr, double x, double y)
{
+ cairo_fixed_t x_fixed, y_fixed;
+
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_line_to (cr->gstate, x, y);
+ _cairo_gstate_user_to_backend (cr->gstate, &x, &y);
+ x_fixed = _cairo_fixed_from_double (x);
+ y_fixed = _cairo_fixed_from_double (y);
+
+ cr->status = _cairo_path_fixed_line_to (&cr->path, x_fixed, y_fixed);
+
CAIRO_CHECK_SANITY (cr);
}
@@ -690,20 +868,38 @@ cairo_curve_to (cairo_t *cr,
double x2, double y2,
double x3, double y3)
{
+ cairo_fixed_t x1_fixed, y1_fixed;
+ cairo_fixed_t x2_fixed, y2_fixed;
+ cairo_fixed_t x3_fixed, y3_fixed;
+
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_curve_to (cr->gstate,
- x1, y1,
- x2, y2,
- x3, y3);
+ _cairo_gstate_user_to_backend (cr->gstate, &x1, &y1);
+ _cairo_gstate_user_to_backend (cr->gstate, &x2, &y2);
+ _cairo_gstate_user_to_backend (cr->gstate, &x3, &y3);
+
+ x1_fixed = _cairo_fixed_from_double (x1);
+ y1_fixed = _cairo_fixed_from_double (y1);
+
+ x2_fixed = _cairo_fixed_from_double (x2);
+ y2_fixed = _cairo_fixed_from_double (y2);
+
+ x3_fixed = _cairo_fixed_from_double (x3);
+ y3_fixed = _cairo_fixed_from_double (y3);
+
+ cr->status = _cairo_path_fixed_curve_to (&cr->path,
+ x1_fixed, y1_fixed,
+ x2_fixed, y2_fixed,
+ x3_fixed, y3_fixed);
+
CAIRO_CHECK_SANITY (cr);
}
/**
* cairo_arc:
- * @cr: a Cairo context
+ * @cr: a cairo context
* @xc: X position of the center of the arc
* @yc: Y position of the center of the arc
* @radius: the radius of the arc
@@ -744,16 +940,26 @@ cairo_arc (cairo_t *cr,
if (cr->status)
return;
- cr->status = _cairo_gstate_arc (cr->gstate,
- xc, yc,
- radius,
- angle1, angle2);
+ /* Do nothing, successfully, if radius is <= 0 */
+ if (radius <= 0.0)
+ return;
+
+ while (angle2 < angle1)
+ angle2 += 2 * M_PI;
+
+ cairo_line_to (cr,
+ xc + radius * cos (angle1),
+ yc + radius * sin (angle1));
+
+ _cairo_arc_path (cr, xc, yc, radius,
+ angle1, angle2);
+
CAIRO_CHECK_SANITY (cr);
}
/**
* cairo_arc_negative:
- * @cr: a Cairo context
+ * @cr: a cairo context
* @xc: X position of the center of the arc
* @yc: Y position of the center of the arc
* @radius: the radius of the arc
@@ -775,10 +981,20 @@ cairo_arc_negative (cairo_t *cr,
if (cr->status)
return;
- cr->status = _cairo_gstate_arc_negative (cr->gstate,
- xc, yc,
- radius,
- angle1, angle2);
+ /* Do nothing, successfully, if radius is <= 0 */
+ if (radius <= 0.0)
+ return;
+
+ while (angle2 > angle1)
+ angle2 -= 2 * M_PI;
+
+ cairo_line_to (cr,
+ xc + radius * cos (angle1),
+ yc + radius * sin (angle1));
+
+ _cairo_arc_path_negative (cr, xc, yc, radius,
+ angle1, angle2);
+
CAIRO_CHECK_SANITY (cr);
}
@@ -802,22 +1018,36 @@ cairo_arc_to (cairo_t *cr,
void
cairo_rel_move_to (cairo_t *cr, double dx, double dy)
{
+ cairo_fixed_t dx_fixed, dy_fixed;
+
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_rel_move_to (cr->gstate, dx, dy);
+ _cairo_gstate_user_to_device_distance (cr->gstate, &dx, &dy);
+ dx_fixed = _cairo_fixed_from_double (dx);
+ dy_fixed = _cairo_fixed_from_double (dy);
+
+ cr->status = _cairo_path_fixed_rel_move_to (&cr->path, dx_fixed, dy_fixed);
+
CAIRO_CHECK_SANITY (cr);
}
void
cairo_rel_line_to (cairo_t *cr, double dx, double dy)
{
+ cairo_fixed_t dx_fixed, dy_fixed;
+
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_rel_line_to (cr->gstate, dx, dy);
+ _cairo_gstate_user_to_device_distance (cr->gstate, &dx, &dy);
+ dx_fixed = _cairo_fixed_from_double (dx);
+ dy_fixed = _cairo_fixed_from_double (dy);
+
+ cr->status = _cairo_path_fixed_rel_line_to (&cr->path, dx_fixed, dy_fixed);
+
CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_rel_line_to);
@@ -828,14 +1058,32 @@ cairo_rel_curve_to (cairo_t *cr,
double dx2, double dy2,
double dx3, double dy3)
{
+ cairo_fixed_t dx1_fixed, dy1_fixed;
+ cairo_fixed_t dx2_fixed, dy2_fixed;
+ cairo_fixed_t dx3_fixed, dy3_fixed;
+
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_rel_curve_to (cr->gstate,
- dx1, dy1,
- dx2, dy2,
- dx3, dy3);
+ _cairo_gstate_user_to_device_distance (cr->gstate, &dx1, &dy1);
+ _cairo_gstate_user_to_device_distance (cr->gstate, &dx2, &dy2);
+ _cairo_gstate_user_to_device_distance (cr->gstate, &dx3, &dy3);
+
+ dx1_fixed = _cairo_fixed_from_double (dx1);
+ dy1_fixed = _cairo_fixed_from_double (dy1);
+
+ dx2_fixed = _cairo_fixed_from_double (dx2);
+ dy2_fixed = _cairo_fixed_from_double (dy2);
+
+ dx3_fixed = _cairo_fixed_from_double (dx3);
+ dy3_fixed = _cairo_fixed_from_double (dy3);
+
+ cr->status = _cairo_path_fixed_rel_curve_to (&cr->path,
+ dx1_fixed, dy1_fixed,
+ dx2_fixed, dy2_fixed,
+ dx3_fixed, dy3_fixed);
+
CAIRO_CHECK_SANITY (cr);
}
@@ -858,7 +1106,7 @@ cairo_rectangle (cairo_t *cr,
/* XXX: NYI
void
-cairo_stroke_path (cairo_t *cr)
+cairo_stroke_to_path (cairo_t *cr)
{
if (cr->status)
return;
@@ -874,32 +1122,208 @@ cairo_close_path (cairo_t *cr)
if (cr->status)
return;
- cr->status = _cairo_gstate_close_path (cr->gstate);
+ cr->status = _cairo_path_fixed_close_path (&cr->path);
+
CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_close_path);
+/**
+ * cairo_paint:
+ * @cr: a cairo context
+ *
+ * A drawing operator that paints the current source everywhere within
+ * the current clip region.
+ **/
+void
+cairo_paint (cairo_t *cr)
+{
+ CAIRO_CHECK_SANITY (cr);
+ if (cr->status)
+ return;
+
+ cr->status = _cairo_gstate_paint (cr->gstate);
+
+ CAIRO_CHECK_SANITY (cr);
+}
+
+/**
+ * cairo_paint_with_alpha:
+ * @cr: a cairo context
+ * @alpha: alpha value, between 0 (transparent) and 1 (opaque)
+ *
+ * A drawing operator that paints the current source everywhere within
+ * the current clip region using a mask of constant alpha value
+ * @alpha. The effect is similar to cairo_paint(), but the drawing
+ * is faded out using the alpha value.
+ **/
+void
+cairo_paint_with_alpha (cairo_t *cr,
+ double alpha)
+{
+ cairo_color_t color;
+ cairo_pattern_union_t pattern;
+
+ CAIRO_CHECK_SANITY (cr);
+ if (cr->status)
+ return;
+
+ _cairo_color_init_rgba (&color, 1., 1., 1., alpha);
+ _cairo_pattern_init_solid (&pattern.solid, &color);
+
+ cr->status = _cairo_gstate_mask (cr->gstate, &pattern.base);
+
+ _cairo_pattern_fini (&pattern.base);
+
+ CAIRO_CHECK_SANITY (cr);
+}
+
+/**
+ * cairo_mask:
+ * @cr: a cairo context
+ * @pattern: a #cairo_pattern_t
+ *
+ * A drawing operator that paints the current source
+ * using the alpha channel of @pattern as a mask. (Opaque
+ * areas of @mask are painted with the source, transparent
+ * areas are not painted.)
+ */
+void
+cairo_mask (cairo_t *cr,
+ cairo_pattern_t *pattern)
+{
+ CAIRO_CHECK_SANITY (cr);
+ if (cr->status)
+ return;
+
+ cr->status = _cairo_gstate_mask (cr->gstate, pattern);
+
+ CAIRO_CHECK_SANITY (cr);
+}
+
+/**
+ * cairo_mask_surface:
+ * @cr: a cairo context
+ * @surface: a #cairo_surface_t
+ * @surface_x: X coordinate at which to place the origin of @surface
+ * @surface_y: Y coordinate at which to place the origin of @surface
+ *
+ * A drawing operator that paints the current source
+ * using the alpha channel of @surface as a mask. (Opaque
+ * areas of @surface are painted with the source, transparent
+ * areas are not painted.)
+ */
+void
+cairo_mask_surface (cairo_t *cr,
+ cairo_surface_t *surface,
+ double surface_x,
+ double surface_y)
+{
+ cairo_pattern_t *pattern;
+ cairo_matrix_t matrix;
+
+ CAIRO_CHECK_SANITY (cr);
+ if (cr->status)
+ return;
+
+ pattern = cairo_pattern_create_for_surface (surface);
+ if (!pattern) {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cairo_matrix_init_translate (&matrix, - surface_x, - surface_y);
+ cairo_pattern_set_matrix (pattern, &matrix);
+
+ cairo_mask (cr, pattern);
+
+ cairo_pattern_destroy (pattern);
+}
+
+/**
+ * cairo_stroke:
+ * @cr: a cairo context
+ *
+ * A drawing operator that strokes the current path according to the
+ * current line width, line join, line cap, and dash settings. After
+ * cairo_stroke, the current path will be cleared from the cairo
+ * context. See cairo_set_line_width(), cairo_set_line_join(),
+ * cairo_set_line_cap(), cairo_set_dash(), and
+ * cairo_stroke_preserve().
+ **/
void
cairo_stroke (cairo_t *cr)
{
+ cairo_stroke_preserve (cr);
+
+ cairo_new_path (cr);
+}
+
+/**
+ * cairo_stroke_preserve:
+ * @cr: a cairo context
+ *
+ * A drawing operator that strokes the current path according to the
+ * current line width, line join, line cap, and dash settings. Unlike
+ * cairo_stroke(), cairo_stroke_preserve preserves the path within the
+ * cairo context.
+ *
+ * See cairo_set_line_width(), cairo_set_line_join(),
+ * cairo_set_line_cap(), cairo_set_dash(), and
+ * cairo_stroke_preserve().
+ **/
+void
+cairo_stroke_preserve (cairo_t *cr)
+{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_stroke (cr->gstate);
+ cr->status = _cairo_gstate_stroke (cr->gstate, &cr->path);
+
CAIRO_CHECK_SANITY (cr);
}
+slim_hidden_def(cairo_stroke_preserve);
+/**
+ * cairo_fill:
+ * @cr: a cairo context
+ *
+ * A drawing operator that fills the current path according to the
+ * current fill rule. After cairo_fill, the current path will be
+ * cleared from the cairo context. See cairo_set_fill_rule() and
+ * cairo_fill_preserve().
+ **/
void
cairo_fill (cairo_t *cr)
{
+ cairo_fill_preserve (cr);
+
+ cairo_new_path (cr);
+}
+
+/**
+ * cairo_fill_preserve:
+ * @cr: a cairo context
+ *
+ * A drawing operator that fills the current path according to the
+ * current fill rule. Unlike cairo_fill(), cairo_fill_preserve
+ * preserves the path within the cairo context.
+ *
+ * See cairo_set_fill_rule() and cairo_fill().
+ **/
+void
+cairo_fill_preserve (cairo_t *cr)
+{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_fill (cr->gstate);
+ cr->status = _cairo_gstate_fill (cr->gstate, &cr->path);
+
CAIRO_CHECK_SANITY (cr);
}
+slim_hidden_def(cairo_fill_preserve);
void
cairo_copy_page (cairo_t *cr)
@@ -932,7 +1356,9 @@ cairo_in_stroke (cairo_t *cr, double x, double y)
if (cr->status)
return 0;
- cr->status = _cairo_gstate_in_stroke (cr->gstate, x, y, &inside);
+ cr->status = _cairo_gstate_in_stroke (cr->gstate,
+ &cr->path,
+ x, y, &inside);
CAIRO_CHECK_SANITY (cr);
@@ -951,7 +1377,9 @@ cairo_in_fill (cairo_t *cr, double x, double y)
if (cr->status)
return 0;
- cr->status = _cairo_gstate_in_fill (cr->gstate, x, y, &inside);
+ cr->status = _cairo_gstate_in_fill (cr->gstate,
+ &cr->path,
+ x, y, &inside);
CAIRO_CHECK_SANITY (cr);
@@ -969,7 +1397,9 @@ cairo_stroke_extents (cairo_t *cr,
if (cr->status)
return;
- cr->status = _cairo_gstate_stroke_extents (cr->gstate, x1, y1, x2, y2);
+ cr->status = _cairo_gstate_stroke_extents (cr->gstate,
+ &cr->path,
+ x1, y1, x2, y2);
CAIRO_CHECK_SANITY (cr);
}
@@ -981,143 +1411,288 @@ cairo_fill_extents (cairo_t *cr,
if (cr->status)
return;
- cr->status = _cairo_gstate_fill_extents (cr->gstate, x1, y1, x2, y2);
+ cr->status = _cairo_gstate_fill_extents (cr->gstate,
+ &cr->path,
+ x1, y1, x2, y2);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_clip:
+ * @cr: a cairo context
+ *
+ * Establishes a new clip region by intersecting the current clip
+ * region with the current path as it would be filled by cairo_fill()
+ * and according to the current fill rule (see cairo_set_fill_rule()).
+ *
+ * After cairo_clip, the current path will be cleared from the cairo
+ * context.
+ *
+ * The current clip region affects all drawing operations by
+ * effectively masking out any changes to the surface that are outside
+ * the current clip region.
+ *
+ * Calling cairo_clip() can only make the clip region smaller, never
+ * larger. But the current clip is part of the graphics state, so a
+ * tempoarary restriction of the clip region can be achieved by
+ * calling cairo_clip() within a cairo_save()/cairo_restore()
+ * pair. The only other means of increasing the size of the clip
+ * region is cairo_reset_clip().
+ **/
+void
+cairo_clip (cairo_t *cr)
+{
+ cairo_clip_preserve (cr);
+
+ cairo_new_path (cr);
+}
+
+/**
+ * cairo_clip_preserve:
+ * @cr: a cairo context
+ *
+ * Establishes a new clip region by intersecting the current clip
+ * region with the current path as it would be filled by cairo_fill()
+ * and according to the current fill rule (see cairo_set_fill_rule()).
+ *
+ * Unlike cairo_clip(), cairo_clip_preserve preserves the path within
+ * the cairo context.
+ *
+ * The current clip region affects all drawing operations by
+ * effectively masking out any changes to the surface that are outside
+ * the current clip region.
+ *
+ * Calling cairo_clip() can only make the clip region smaller, never
+ * larger. But the current clip is part of the graphics state, so a
+ * tempoarary restriction of the clip region can be achieved by
+ * calling cairo_clip() within a cairo_save()/cairo_restore()
+ * pair. The only other means of increasing the size of the clip
+ * region is cairo_reset_clip().
+ **/
void
-cairo_init_clip (cairo_t *cr)
+cairo_clip_preserve (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_init_clip (cr->gstate);
+ cr->status = _cairo_gstate_clip (cr->gstate, &cr->path);
CAIRO_CHECK_SANITY (cr);
}
+slim_hidden_def(cairo_clip_preserve);
+/**
+ * cairo_reset_clip:
+ * @cr: a cairo context
+ *
+ * Reset the current clip region to its original, unrestricted
+ * state. That is, set the clip region to an infinitely large shape
+ * containing the target surface. Equivalently, if infinity is too
+ * hard to grasp, one can imagine the clip region being reset to the
+ * exact bounds of the target surface.
+ *
+ * Note that code meant to be reusable should not call
+ * cairo_reset_clip() as it will cause results unexpected by
+ * higher-level code which calls cairo_clip(). Consider using
+ * cairo_save() and cairo_restore() around cairo_clip() as a more
+ * robust means of temporarily restricting the clip region.
+ **/
void
-cairo_clip (cairo_t *cr)
+cairo_reset_clip (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_clip (cr->gstate);
+ cr->status = _cairo_gstate_reset_clip (cr->gstate);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_select_font_face:
+ * @cr: a #cairo_t
+ * @family: a font family name, encoded in UTF-8
+ * @slant: the slant for the font
+ * @weight: the weight for the font
+ *
+ * Selects a family and style of font from a simplified description as
+ * a family name, slant and weight. This function is meant to be used
+ * only for applications with simple font needs: Cairo doesn't provide
+ * for operations such as listing all available fonts on the system,
+ * and it is expected that most applications will need to use a more
+ * comprehensive font handling and text layout library in addition to
+ * Cairo.
+ **/
void
-cairo_select_font (cairo_t *cr,
- const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight)
+cairo_select_font_face (cairo_t *cr,
+ const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_select_font (cr->gstate, family, slant, weight);
+ cr->status = _cairo_gstate_select_font_face (cr->gstate, family, slant, weight);
CAIRO_CHECK_SANITY (cr);
}
/**
- * cairo_current_font:
+ * cairo_get_font_face:
* @cr: a #cairo_t
*
- * Gets the current font object for a #cairo_t. If there is no current
- * font object, because the font parameters, transform, or target
- * surface has been changed since a font was last used, a font object
- * will be created and stored in in the #cairo_t.
+ * Gets the current font face for a #cairo_t.
*
* Return value: the current font object. Can return %NULL
* on out-of-memory or if the context is already in
- * an error state. This object is owned by Cairo. To keep
+ * an error state. This object is owned by cairo. To keep
* a reference to it, you must call cairo_font_reference().
**/
-cairo_font_t *
-cairo_current_font (cairo_t *cr)
+cairo_font_face_t *
+cairo_get_font_face (cairo_t *cr)
{
- cairo_font_t *ret;
+ cairo_font_face_t *font_face;
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return NULL;
- cr->status = _cairo_gstate_current_font (cr->gstate, &ret);
+ cr->status = _cairo_gstate_get_font_face (cr->gstate, &font_face);
CAIRO_CHECK_SANITY (cr);
- return ret;
+ return font_face;
}
+/**
+ * cairo_font_extents:
+ * @cr: a #cairo_t
+ * @extents: a #cairo_font_extents_t object into which the results
+ * will be stored.
+ *
+ * Gets the font extents for the currently selected font.
+ **/
void
-cairo_current_font_extents (cairo_t *cr,
- cairo_font_extents_t *extents)
+cairo_font_extents (cairo_t *cr,
+ cairo_font_extents_t *extents)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_current_font_extents (cr->gstate, extents);
+ cr->status = _cairo_gstate_get_font_extents (cr->gstate, extents);
CAIRO_CHECK_SANITY (cr);
}
-
/**
- * cairo_set_font:
+ * cairo_set_font_face:
* @cr: a #cairo_t
- * @font: a #cairo_font_t, or %NULL to unset any previously set font.
- *
- * Replaces the current #cairo_font_t object in the #cairo_t with
- * @font. The replaced font in the #cairo_t will be destroyed if there
- * are no other references to it. Since a #cairo_font_t is specific to
- * a particular output device and size, changing the transformation,
- * font transformation, or target surfaces of a #cairo_t will clear
- * any previously set font. Setting the font using cairo_set_font() is
- * exclusive with the simple font selection API provided by
- * cairo_select_font(). The size and transformation set by
- * cairo_scale_font() and cairo_transform_font() are ignored unless
- * they were taken into account when creating @font.
+ * @font_face: a #cairo_font_face_t, or %NULL to restore to the default font
+ *
+ * Replaces the current #cairo_font_face_t object in the #cairo_t with
+ * @font_face. The replaced font face in the #cairo_t will be
+ * destroyed if there are no other references to it.
**/
void
-cairo_set_font (cairo_t *cr, cairo_font_t *font)
+cairo_set_font_face (cairo_t *cr,
+ cairo_font_face_t *font_face)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_set_font (cr->gstate, font);
+ cr->status = _cairo_gstate_set_font_face (cr->gstate, font_face);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_font_size:
+ * @cr: a #cairo_t
+ * @size: the new font size, in user space units
+ *
+ * Sets the current font matrix to a scale by a factor of @size, replacing
+ * any font matrix previously set with cairo_set_font_size() or
+ * cairo_set_font_matrix(). This results in a font size of @size user space
+ * units. (More precisely, this matrix will result in the font's
+ * em-square being a @size by @size square in user space.)
+ **/
void
-cairo_scale_font (cairo_t *cr, double scale)
+cairo_set_font_size (cairo_t *cr, double size)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_scale_font (cr->gstate, scale);
+ cr->status = _cairo_gstate_set_font_size (cr->gstate, size);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_font_matrix
+ * @cr: a #cairo_t
+ * @matrix: a #cairo_matrix_t describing a transform to be applied to
+ * the current font.
+ *
+ * Sets the current font matrix to @matrix. The font matrix gives a
+ * transformation from the design space of the font (in this space,
+ * the em-square is 1 unit by 1 unit) to user space. Normally, a
+ * simple scale is used (see cairo_set_font_size()), but a more
+ * complex font matrix can be used to shear the font
+ * or stretch it unequally along the two axes
+ **/
void
-cairo_transform_font (cairo_t *cr, cairo_matrix_t *matrix)
+cairo_set_font_matrix (cairo_t *cr,
+ const cairo_matrix_t *matrix)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_transform_font (cr->gstate, matrix);
+ cr->status = _cairo_gstate_set_font_matrix (cr->gstate, matrix);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_get_font_matrix
+ * @cr: a #cairo_t
+ * @matrix: return value for the matrix
+ *
+ * Stores the current font matrix into @matrix. See
+ * cairo_set_font_matrix().
+ **/
+void
+cairo_get_font_matrix (cairo_t *cr, cairo_matrix_t *matrix)
+{
+ CAIRO_CHECK_SANITY (cr);
+ _cairo_gstate_get_font_matrix (cr->gstate, matrix);
+}
+
+/**
+ * cairo_text_extents:
+ * @cr: a #cairo_t
+ * @utf8: a string of text, encoded in utf-8
+ * @extents: a #cairo_text_extents_t object into which the results
+ * will be stored.
+ *
+ * Gets the extents for a string of text. The extents describe a
+ * user-space rectangle that encloses the "inked" portion of the text,
+ * (as it would be drawn by cairo_show_text). Additionally, the
+ * x_advance and y_advance values indicate the amount by which the
+ * current point would be advanced by cairo_show_text.
+ *
+ * Note that whitespace characters do not directly contribute to the
+ * size of the rectangle (extents.width and extents.height). They do
+ * contribute indirectly by changing the position of non-whitespace
+ * characters. In particular, trailing whitespace characters are
+ * likely to not affect the size of the rectangle, though they will
+ * affect the x_advance and y_advance values.
+ **/
void
-cairo_text_extents (cairo_t *cr,
- const unsigned char *utf8,
- cairo_text_extents_t *extents)
+cairo_text_extents (cairo_t *cr,
+ const char *utf8,
+ cairo_text_extents_t *extents)
{
cairo_glyph_t *glyphs = NULL;
- int nglyphs;
+ int num_glyphs;
+ double x, y;
CAIRO_CHECK_SANITY (cr);
if (cr->status)
@@ -1133,7 +1708,11 @@ cairo_text_extents (cairo_t *cr,
return;
}
- cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, &glyphs, &nglyphs);
+ cairo_get_current_point (cr, &x, &y);
+
+ cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8,
+ x, y,
+ &glyphs, &num_glyphs);
CAIRO_CHECK_SANITY (cr);
if (cr->status) {
@@ -1142,13 +1721,31 @@ cairo_text_extents (cairo_t *cr,
return;
}
- cr->status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, nglyphs, extents);
+ cr->status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs, extents);
CAIRO_CHECK_SANITY (cr);
if (glyphs)
free (glyphs);
}
+/**
+ * cairo_glyph_extents:
+ * @cr: a #cairo_t
+ * @glyphs: an array of #cairo_glyph_t objects
+ * @num_glyphs: the number of elements in @glyphs
+ * @extents: a #cairo_text_extents_t object into which the results
+ * will be stored
+ *
+ * Gets the extents for an array of glyphs. The extents describe a
+ * user-space rectangle that encloses the "inked" portion of the
+ * glyphs, (as they would be drawn by cairo_show_glyphs).
+ * Additionally, the x_advance and y_advance values indicate the
+ * amount by which the current point would be advanced by
+ * cairo_show_glyphs.
+ *
+ * Note that whitespace glyphs do not contribute to the size of the
+ * rectangle (extents.width and extents.height).
+ **/
void
cairo_glyph_extents (cairo_t *cr,
cairo_glyph_t *glyphs,
@@ -1165,10 +1762,11 @@ cairo_glyph_extents (cairo_t *cr,
}
void
-cairo_show_text (cairo_t *cr, const unsigned char *utf8)
+cairo_show_text (cairo_t *cr, const char *utf8)
{
cairo_glyph_t *glyphs = NULL;
- int nglyphs;
+ int num_glyphs;
+ double x, y;
CAIRO_CHECK_SANITY (cr);
if (cr->status)
@@ -1177,7 +1775,11 @@ cairo_show_text (cairo_t *cr, const unsigned char *utf8)
if (utf8 == NULL)
return;
- cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, &glyphs, &nglyphs);
+ cairo_get_current_point (cr, &x, &y);
+
+ cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8,
+ x, y,
+ &glyphs, &num_glyphs);
CAIRO_CHECK_SANITY (cr);
if (cr->status) {
@@ -1186,7 +1788,7 @@ cairo_show_text (cairo_t *cr, const unsigned char *utf8)
return;
}
- cr->status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, nglyphs);
+ cr->status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, num_glyphs);
CAIRO_CHECK_SANITY (cr);
if (glyphs)
@@ -1205,16 +1807,21 @@ cairo_show_glyphs (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs)
}
void
-cairo_text_path (cairo_t *cr, const unsigned char *utf8)
+cairo_text_path (cairo_t *cr, const char *utf8)
{
cairo_glyph_t *glyphs = NULL;
- int nglyphs;
+ int num_glyphs;
+ double x, y;
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, &glyphs, &nglyphs);
+ cairo_get_current_point (cr, &x, &y);
+
+ cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8,
+ x, y,
+ &glyphs, &num_glyphs);
CAIRO_CHECK_SANITY (cr);
if (cr->status) {
@@ -1223,7 +1830,9 @@ cairo_text_path (cairo_t *cr, const unsigned char *utf8)
return;
}
- cr->status = _cairo_gstate_glyph_path (cr->gstate, glyphs, nglyphs);
+ cr->status = _cairo_gstate_glyph_path (cr->gstate,
+ glyphs, num_glyphs,
+ &cr->path);
CAIRO_CHECK_SANITY (cr);
if (glyphs)
@@ -1237,162 +1846,281 @@ cairo_glyph_path (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs)
if (cr->status)
return;
- cr->status = _cairo_gstate_glyph_path (cr->gstate, glyphs, num_glyphs);
+ cr->status = _cairo_gstate_glyph_path (cr->gstate,
+ glyphs, num_glyphs,
+ &cr->path);
+
CAIRO_CHECK_SANITY (cr);
}
-void
-cairo_show_surface (cairo_t *cr,
- cairo_surface_t *surface,
- int width,
- int height)
+/**
+ * cairo_get_operator:
+ * @cr: a cairo context
+ *
+ * Gets the current compositing operator for a cairo context.
+ *
+ * Return value: the current compositing operator.
+ **/
+cairo_operator_t
+cairo_get_operator (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- if (cr->status)
- return;
-
- cr->status = _cairo_gstate_show_surface (cr->gstate,
- surface, width, height);
- CAIRO_CHECK_SANITY (cr);
+ return _cairo_gstate_get_operator (cr->gstate);
}
-cairo_operator_t
-cairo_current_operator (cairo_t *cr)
+/**
+ * cairo_get_tolerance:
+ * @cr: a cairo context
+ *
+ * Gets the current tolerance value, as set by cairo_set_tolerance().
+ *
+ * Return value: the current tolerance value.
+ **/
+double
+cairo_get_tolerance (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_operator (cr->gstate);
+ return _cairo_gstate_get_tolerance (cr->gstate);
}
-DEPRECATE (cairo_get_operator, cairo_current_operator);
+/**
+ * cairo_get_current_point:
+ * @cr: a cairo context
+ * @x: return value for X coordinate of the current point
+ * @y: return value for Y coordinate of the current point
+ *
+ * Gets the current point of the current path, which is
+ * conceptually the final point reached by the path so far.
+ *
+ * The current point is returned in the user-space coordinate
+ * system. If there is no defined current point then @x and @y will
+ * both be set to 0.0.
+ *
+ * Most path construction functions alter the current point. See the
+ * following for details on how they affect the current point:
+ *
+ * cairo_new_path(), cairo_move_to(), cairo_line_to(),
+ * cairo_curve_to(), cairo_arc(), cairo_rel_move_to(),
+ * cairo_rel_line_to(), cairo_rel_curve_to(), cairo_arc(),
+ * cairo_text_path(), cairo_stroke_to_path()
+ **/
void
-cairo_current_rgb_color (cairo_t *cr, double *red, double *green, double *blue)
+cairo_get_current_point (cairo_t *cr, double *x_ret, double *y_ret)
{
- CAIRO_CHECK_SANITY (cr);
- _cairo_gstate_current_rgb_color (cr->gstate, red, green, blue);
- CAIRO_CHECK_SANITY (cr);
-}
-DEPRECATE (cairo_get_rgb_color, cairo_current_rgb_color);
+ cairo_status_t status;
+ cairo_fixed_t x_fixed, y_fixed;
+ double x, y;
-double
-cairo_current_alpha (cairo_t *cr)
-{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_alpha (cr->gstate);
-}
-DEPRECATE (cairo_get_alpha, cairo_current_alpha);
-double
-cairo_current_tolerance (cairo_t *cr)
-{
- CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_tolerance (cr->gstate);
-}
-DEPRECATE (cairo_get_tolerance, cairo_current_tolerance);
+ status = _cairo_path_fixed_get_current_point (&cr->path, &x_fixed, &y_fixed);
+ if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
+ x = 0.0;
+ y = 0.0;
+ } else {
+ x = _cairo_fixed_to_double (x_fixed);
+ y = _cairo_fixed_to_double (y_fixed);
+ _cairo_gstate_backend_to_user (cr->gstate, &x, &y);
+ }
+
+ if (x_ret)
+ *x_ret = x;
+ if (y_ret)
+ *y_ret = y;
-void
-cairo_current_point (cairo_t *cr, double *x, double *y)
-{
- CAIRO_CHECK_SANITY (cr);
- _cairo_gstate_current_point (cr->gstate, x, y);
CAIRO_CHECK_SANITY (cr);
}
-DEPRECATE (cairo_get_current_point, cairo_current_point);
+slim_hidden_def(cairo_get_current_point);
+/**
+ * cairo_get_fill_rule:
+ * @cr: a cairo context
+ *
+ * Gets the current fill rule, as set by cairo_set_fill_rule().
+ *
+ * Return value: the current fill rule.
+ **/
cairo_fill_rule_t
-cairo_current_fill_rule (cairo_t *cr)
+cairo_get_fill_rule (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_fill_rule (cr->gstate);
+ return _cairo_gstate_get_fill_rule (cr->gstate);
}
-DEPRECATE (cairo_get_fill_rule, cairo_current_fill_rule);
+/**
+ * cairo_get_line_width:
+ * @cr: a cairo context
+ *
+ * Gets the current line width, as set by cairo_set_line_width().
+ *
+ * Return value: the current line width, in user-space units.
+ **/
double
-cairo_current_line_width (cairo_t *cr)
+cairo_get_line_width (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_line_width (cr->gstate);
+ return _cairo_gstate_get_line_width (cr->gstate);
}
-DEPRECATE (cairo_get_line_width, cairo_current_line_width);
+/**
+ * cairo_get_line_cap:
+ * @cr: a cairo context
+ *
+ * Gets the current line cap style, as set by cairo_set_line_cap().
+ *
+ * Return value: the current line cap style.
+ **/
cairo_line_cap_t
-cairo_current_line_cap (cairo_t *cr)
+cairo_get_line_cap (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_line_cap (cr->gstate);
+ return _cairo_gstate_get_line_cap (cr->gstate);
}
-DEPRECATE (cairo_get_line_cap, cairo_current_line_cap);
+/**
+ * cairo_get_line_join:
+ * @cr: a cairo context
+ *
+ * Gets the current line join style, as set by cairo_set_line_join().
+ *
+ * Return value: the current line join style.
+ **/
cairo_line_join_t
-cairo_current_line_join (cairo_t *cr)
+cairo_get_line_join (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_line_join (cr->gstate);
+ return _cairo_gstate_get_line_join (cr->gstate);
}
-DEPRECATE (cairo_get_line_join, cairo_current_line_join);
+/**
+ * cairo_get_miter_limit:
+ * @cr: a cairo context
+ *
+ * Gets the current miter limit, as set by cairo_set_miter_limit().
+ *
+ * Return value: the current miter limit.
+ **/
double
-cairo_current_miter_limit (cairo_t *cr)
+cairo_get_miter_limit (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_miter_limit (cr->gstate);
+ return _cairo_gstate_get_miter_limit (cr->gstate);
}
-DEPRECATE (cairo_get_miter_limit, cairo_current_miter_limit);
+/**
+ * cairo_get_matrix:
+ * @cr: a cairo context
+ * @matrix: return value for the matrix
+ *
+ * Stores the current transformation matrix (CTM) into @matrix.
+ **/
void
-cairo_current_matrix (cairo_t *cr, cairo_matrix_t *matrix)
+cairo_get_matrix (cairo_t *cr, cairo_matrix_t *matrix)
{
CAIRO_CHECK_SANITY (cr);
- _cairo_gstate_current_matrix (cr->gstate, matrix);
- CAIRO_CHECK_SANITY (cr);
+ _cairo_gstate_get_matrix (cr->gstate, matrix);
}
-DEPRECATE (cairo_get_matrix, cairo_current_matrix);
+/**
+ * cairo_get_target:
+ * @cr: a cairo context
+ *
+ * Gets the target surface for the cairo context as passed to
+ * cairo_create().
+ *
+ * Return value: the target surface, (or NULL if @cr is in an error
+ * state). This object is owned by cairo. To keep a reference to it,
+ * you must call cairo_pattern_reference().
+ **/
cairo_surface_t *
-cairo_current_target_surface (cairo_t *cr)
+cairo_get_target (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_target_surface (cr->gstate);
+ if (cr->status)
+ return NULL;
+
+ return _cairo_gstate_get_target (cr->gstate);
}
-DEPRECATE (cairo_get_target_surface, cairo_current_target_surface);
-void
-cairo_current_path (cairo_t *cr,
- cairo_move_to_func_t *move_to,
- cairo_line_to_func_t *line_to,
- cairo_curve_to_func_t *curve_to,
- cairo_close_path_func_t *close_path,
- void *closure)
+/**
+ * cairo_copy_path:
+ * @cr: a cairo context
+ *
+ * Creates a copy of the current path and returns it to the user as a
+ * #cairo_path_t. See #cairo_path_data_t for hints on how to iterate
+ * over the returned data structure.
+ *
+ * Return value: the copy of the current path. The caller owns the
+ * returned object and should call cairo_path_destroy() when finished
+ * with it.
+ **/
+cairo_path_t *
+cairo_copy_path (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
- return;
-
- cr->status = _cairo_gstate_interpret_path (cr->gstate,
- move_to,
- line_to,
- curve_to,
- close_path,
- closure);
+ return &_cairo_path_nil;
+
+ return _cairo_path_data_create (&cr->path, cr->gstate);
+}
+
+/**
+ * cairo_copy_path_flat:
+ * @cr: a cairo context
+ *
+ * Gets a flattened copy of the current path and returns it to the
+ * user as a #cairo_path_t. See #cairo_path_data_t for hints on
+ * how to iterate over the returned data structure.
+ *
+ * This function is like cairo_copy_path() except that any curves
+ * in the path will be approximated with piecewise-linear
+ * approximations, (accurate to within the current tolerance
+ * value). That is, the result is guaranteed to not have any elements
+ * of type CAIRO_PATH_CURVE_TO which will instead be replaced by a
+ * series of CAIRO_PATH_LINE_TO elements.
+ *
+ * Return value: the copy of the current path. The caller owns the
+ * returned object and should call cairo_path_destroy() when finished
+ * with it.
+ **/
+cairo_path_t *
+cairo_copy_path_flat (cairo_t *cr)
+{
CAIRO_CHECK_SANITY (cr);
+ if (cr->status)
+ return &_cairo_path_nil;
+
+ return _cairo_path_data_create_flat (&cr->path, cr->gstate);
}
+/**
+ * cairo_append_path:
+ * @cr: a cairo context
+ * @path: path to be appended
+ *
+ * Append the @path onto the current path. See #cairo_path_t
+ * for details on how the path data structure must be initialized.
+ **/
void
-cairo_current_path_flat (cairo_t *cr,
- cairo_move_to_func_t *move_to,
- cairo_line_to_func_t *line_to,
- cairo_close_path_func_t *close_path,
- void *closure)
+cairo_append_path (cairo_t *cr,
+ cairo_path_t *path)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_interpret_path (cr->gstate,
- move_to,
- line_to,
- NULL,
- close_path,
- closure);
+ if (path == NULL || path->data == NULL) {
+ cr->status = CAIRO_STATUS_NULL_POINTER;
+ return;
+ }
+
+ if (path == &_cairo_path_nil) {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cr->status = _cairo_path_data_append_to_context (path, cr);
+
CAIRO_CHECK_SANITY (cr);
}
@@ -1402,7 +2130,6 @@ cairo_status (cairo_t *cr)
CAIRO_CHECK_SANITY (cr);
return cr->status;
}
-DEPRECATE (cairo_get_status, cairo_status);
const char *
cairo_status_string (cairo_t *cr)
@@ -1426,11 +2153,22 @@ cairo_status_string (cairo_t *cr)
return "NULL pointer";
case CAIRO_STATUS_INVALID_STRING:
return "input string not valid UTF-8";
+ case CAIRO_STATUS_INVALID_PATH_DATA:
+ return "input path data not valid";
+ case CAIRO_STATUS_READ_ERROR:
+ return "error while reading from input stream";
+ case CAIRO_STATUS_WRITE_ERROR:
+ return "error while writing to output stream";
+ case CAIRO_STATUS_SURFACE_FINISHED:
+ return "the target surface has been finished";
+ case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
+ return "the surface type is not appropriate for the operation";
+ case CAIRO_STATUS_BAD_NESTING:
+ return "drawing operations interleaved for two contexts for the same surface";
}
return "<unknown error status>";
}
-DEPRECATE (cairo_get_status_string, cairo_status_string);
void
_cairo_restrict_value (double *value, double min, double max)
diff --git a/src/cairo.h b/src/cairo.h
index 03e063242..4cb3a023e 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -46,7 +47,6 @@
#endif
#include <cairo-features.h>
-#include <pixman.h>
CAIRO_BEGIN_DECLS
@@ -55,7 +55,7 @@ CAIRO_BEGIN_DECLS
*
* #cairo_bool_t is used for boolean values. Returns of type
* #cairo_bool_t will always be either 0 or 1, but testing against
- * these values explicitely is not encouraged; just use the
+ * these values explicitly is not encouraged; just use the
* value as a boolean condition.
*
* <informalexample><programlisting>
@@ -94,9 +94,62 @@ typedef struct _cairo_surface cairo_surface_t;
* A #cairo_matrix_t holds an affine transformation, such as a scale,
* rotation, or shear, or a combination of those.
**/
-typedef struct _cairo_matrix cairo_matrix_t;
+typedef struct _cairo_matrix {
+ double xx; double yx;
+ double xy; double yy;
+ double x0; double y0;
+} cairo_matrix_t;
+
typedef struct _cairo_pattern cairo_pattern_t;
+/**
+ * cairo_destroy_func_t
+ *
+ * #cairo_destroy_func_t the type of function which is called when a
+ * data element is destroyed. It is passed the pointer to the data
+ * element and should free any memory and resources allocated for it.
+ */
+typedef void (*cairo_destroy_func_t) (void *data);
+
+/**
+ * cairo_user_data_key_t
+ *
+ * #cairo_user_data_key_t is used for attaching user data to cairo
+ * data structures. The actual contents of the struct is never used,
+ * and there is no need to initialize the object; only the unique
+ * address of a #cairo_data_key_t object is used. Typically, you
+ * would just use the address of a static #cairo_data_key_t object.
+ */
+typedef struct _cairo_user_data_key {
+ int unused;
+} cairo_user_data_key_t;
+
+/**
+ * cairo_status_t
+ * @CAIRO_STATUS_SUCCESS: no error has occurred
+ * @CAIRO_STATUS_NO_MEMORY:
+ * @CAIRO_STATUS_INVALID_RESTORE:
+ * @CAIRO_STATUS_INVALID_POP_GROUP:
+ * @CAIRO_STATUS_INVALID_MATRIX:
+ * @CAIRO_STATUS_NO_TARGET_SURFACE:
+ * @CAIRO_STATUS_NULL_POINTER:
+ * @CAIRO_STATUS_INVALID_STRING:
+ * @CAIRO_STATUS_INVALID_PATH_DATA:
+ * @CAIRO_STATUS_READ_ERROR:
+ * @CAIRO_STATUS_WRITE_ERROR:
+ * @CAIRO_STATUS_SURFACE_FINISHED:
+ * @CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
+ * @CAIRO_STATUS_BAD_NESTING: the same surface was used as the
+ * target surface for two different cairo contexts at once,
+ * and more drawing was done on the first context before the
+ * surface was unset as the target for the second context.
+ * See the documentation for cairo_create().
+ *
+ * #cairo_status_t is used to indicate errors that can occur when
+ * using Cairo. In some cases it is returned directly by functions.
+ * but when using #cairo_t, the last error, if any, is stored in
+ * the context and can be retrieved with cairo_status().
+ **/
typedef enum cairo_status {
CAIRO_STATUS_SUCCESS = 0,
CAIRO_STATUS_NO_MEMORY,
@@ -106,12 +159,48 @@ typedef enum cairo_status {
CAIRO_STATUS_INVALID_MATRIX,
CAIRO_STATUS_NO_TARGET_SURFACE,
CAIRO_STATUS_NULL_POINTER,
- CAIRO_STATUS_INVALID_STRING
+ CAIRO_STATUS_INVALID_STRING,
+ CAIRO_STATUS_INVALID_PATH_DATA,
+ CAIRO_STATUS_READ_ERROR,
+ CAIRO_STATUS_WRITE_ERROR,
+ CAIRO_STATUS_SURFACE_FINISHED,
+ CAIRO_STATUS_SURFACE_TYPE_MISMATCH,
+ CAIRO_STATUS_BAD_NESTING
} cairo_status_t;
+/**
+ * cairo_write_func_t
+ *
+ * #cairo_write_func_t is the type of function which is called when a
+ * backend needs to write data to an output stream. It is passed the
+ * closure which was specified by the user at the time the write
+ * function was registered, the data to write and the length of the
+ * data in bytes. The write function should return
+ * CAIRO_STATUS_SUCCESS if all the data was successfully written,
+ * CAIRO_STATUS_WRITE_ERROR otherwise.
+ */
+typedef cairo_status_t (*cairo_write_func_t) (void *closure,
+ const unsigned char *data,
+ unsigned int length);
+
+/**
+ * cairo_read_func_t
+ *
+ * #cairo_read_func_t is the type of function which is called when a
+ * backend needs to read data from an intput stream. It is passed the
+ * closure which was specified by the user at the time the read
+ * function was registered, the buffer to read the data into and the
+ * length of the data in bytes. The read function should return
+ * CAIRO_STATUS_SUCCESS if all the data was successfully written,
+ * CAIRO_STATUS_READ_ERROR otherwise.
+ */
+typedef cairo_status_t (*cairo_read_func_t) (void *closure,
+ unsigned char *data,
+ unsigned int length);
+
/* Functions for manipulating state objects */
cairo_t *
-cairo_create (void);
+cairo_create (cairo_surface_t *target);
void
cairo_reference (cairo_t *cr);
@@ -125,10 +214,6 @@ cairo_save (cairo_t *cr);
void
cairo_restore (cairo_t *cr);
-/* XXX: Replace with cairo_current_gstate/cairo_set_gstate */
-void
-cairo_copy (cairo_t *dest, cairo_t *src);
-
/* XXX: I want to rethink this API
void
cairo_push_group (cairo_t *cr);
@@ -138,59 +223,22 @@ cairo_pop_group (cairo_t *cr);
*/
/* Modify state */
-void
-cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface);
-
-/**
- * cairo_format_t
- * @CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with
- * alpha in the upper 8 bits, then red, then green, then blue.
- * The 32-bit quanties are stored native-endian. Pre-multiplied
- * alpha is used. (That is, 50% transparent red is 0x80800000,
- * not 0x80ff0000.)
- * @CAIRO_FORMAT_RGB24: each pixel is a 32-bit quantity, with
- * the upper 8 bits unused. Red, Green, and Blue are stored
- * in the remaining 24 bits in that order.
- * @CAIRO_FORMAT_A8: each pixel is a 8-bit quantity holding
- * an alpha value.
- * @CAIRO_FORMAT_A1: each pixel is a 1-bit quantity holding
- * an alpha value. Pixels are packed together into 32-bit
- * quantities. The ordering of the bits matches the
- * endianess of the platform. On a big-endian machine, the
- * first pixel is in the uppermost bit, on a little-endian
- * machine the first pixel is in the least-significant bit.
- *
- * #cairo_format_t is used to identify the memory format of
- * image data.
- */
-typedef enum cairo_format {
- CAIRO_FORMAT_ARGB32,
- CAIRO_FORMAT_RGB24,
- CAIRO_FORMAT_A8,
- CAIRO_FORMAT_A1
-} cairo_format_t;
-
-/* XXX: Need to add cairo_set_target_image_data */
-void
-cairo_set_target_image (cairo_t *cr,
- char *data,
- cairo_format_t format,
- int width,
- int height,
- int stride);
-typedef enum cairo_operator {
+typedef enum cairo_operator {
CAIRO_OPERATOR_CLEAR,
- CAIRO_OPERATOR_SRC,
- CAIRO_OPERATOR_DST,
+
+ CAIRO_OPERATOR_SOURCE,
CAIRO_OPERATOR_OVER,
- CAIRO_OPERATOR_OVER_REVERSE,
CAIRO_OPERATOR_IN,
- CAIRO_OPERATOR_IN_REVERSE,
CAIRO_OPERATOR_OUT,
- CAIRO_OPERATOR_OUT_REVERSE,
CAIRO_OPERATOR_ATOP,
- CAIRO_OPERATOR_ATOP_REVERSE,
+
+ CAIRO_OPERATOR_DEST,
+ CAIRO_OPERATOR_DEST_OVER,
+ CAIRO_OPERATOR_DEST_IN,
+ CAIRO_OPERATOR_DEST_OUT,
+ CAIRO_OPERATOR_DEST_ATOP,
+
CAIRO_OPERATOR_XOR,
CAIRO_OPERATOR_ADD,
CAIRO_OPERATOR_SATURATE
@@ -199,36 +247,23 @@ typedef enum cairo_operator {
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 */
-
-/* XXX: I've been trying to come up with a sane way to specify:
-
- cairo_set_color (cairo_t *cr, cairo_color_t *color);
-
- Keith wants to be able to support super-luminescent colors,
- (premultiplied colors with R/G/B greater than alpha). The current
- API does not allow that. Adding a premulitplied RGBA cairo_color_t
- would do the trick.
-
- One problem though is that alpha is currently orthogonal to
- color. For example, show_surface uses gstate->alpha but ignores the
- color. So, it doesn't seem be right to have cairo_set_color modify
- the behavior of cairo_show_surface.
-*/
+void
+cairo_set_source (cairo_t *cr, cairo_pattern_t *source);
void
-cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue);
+cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue);
void
-cairo_set_pattern (cairo_t *cr, cairo_pattern_t *pattern);
+cairo_set_source_rgba (cairo_t *cr,
+ double red, double green, double blue,
+ double alpha);
void
-cairo_set_alpha (cairo_t *cr, double alpha);
+cairo_set_source_surface (cairo_t *cr,
+ cairo_surface_t *surface,
+ double x,
+ double y);
-/* XXX: Currently, the tolerance value is specified by the user in
- terms of device-space units. If I'm not mistaken, this is the only
- value in this API that is not expressed in user-space units. I
- should think whether this value should be user-space instead. */
void
cairo_set_tolerance (cairo_t *cr, double tolerance);
@@ -307,32 +342,27 @@ 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);
+cairo_transform (cairo_t *cr,
+ const cairo_matrix_t *matrix);
void
-cairo_default_matrix (cairo_t *cr);
-
-/* XXX: There's been a proposal to add cairo_default_matrix_exact */
+cairo_set_matrix (cairo_t *cr,
+ const cairo_matrix_t *matrix);
void
cairo_identity_matrix (cairo_t *cr);
void
-cairo_transform_point (cairo_t *cr, double *x, double *y);
+cairo_user_to_device (cairo_t *cr, double *x, double *y);
void
-cairo_transform_distance (cairo_t *cr, double *dx, double *dy);
+cairo_user_to_device_distance (cairo_t *cr, double *dx, double *dy);
void
-cairo_inverse_transform_point (cairo_t *cr, double *x, double *y);
+cairo_device_to_user (cairo_t *cr, double *x, double *y);
void
-cairo_inverse_transform_distance (cairo_t *cr, double *dx, double *dy);
+cairo_device_to_user_distance (cairo_t *cr, double *dx, double *dy);
/* Path creation functions */
void
@@ -387,16 +417,9 @@ cairo_rectangle (cairo_t *cr,
double x, double y,
double width, double height);
-/* XXX: This is the same name that PostScript uses, but to me the name
- suggests an actual drawing operation ala cairo_stroke --- especially
- since I want to add a cairo_path_t and with that it would be
- natural to have "cairo_stroke_path (cairo_t *, cairo_path_t *)"
-
- Maybe we could use something like "cairo_outline_path (cairo_t *)"?
-*/
/* XXX: NYI
void
-cairo_stroke_path (cairo_t *cr);
+cairo_stroke_to_path (cairo_t *cr);
*/
void
@@ -404,12 +427,35 @@ cairo_close_path (cairo_t *cr);
/* Painting functions */
void
+cairo_paint (cairo_t *cr);
+
+void
+cairo_paint_with_alpha (cairo_t *cr,
+ double alpha);
+
+void
+cairo_mask (cairo_t *cr,
+ cairo_pattern_t *pattern);
+
+void
+cairo_mask_surface (cairo_t *cr,
+ cairo_surface_t *surface,
+ double surface_x,
+ double surface_y);
+
+void
cairo_stroke (cairo_t *cr);
void
+cairo_stroke_preserve (cairo_t *cr);
+
+void
cairo_fill (cairo_t *cr);
void
+cairo_fill_preserve (cairo_t *cr);
+
+void
cairo_copy_page (cairo_t *cr);
void
@@ -435,25 +481,37 @@ cairo_fill_extents (cairo_t *cr,
/* Clipping */
void
-cairo_init_clip (cairo_t *cr);
+cairo_reset_clip (cairo_t *cr);
-/* Note: cairo_clip does not consume the current path */
void
cairo_clip (cairo_t *cr);
+void
+cairo_clip_preserve (cairo_t *cr);
+
/* Font/Text functions */
/**
- * cairo_font_t:
- *
- * A #cairo_font_t is a font scaled to a particular size and device
- * resolution. A font can be set on a #cairo_t by using
- * cairo_set_font() assuming that the current transformation and
- * target surface of the #cairo_t match that for which the
- * #cairo_font_t was created. The effect of using a mismatched
- * #cairo_font_t will be incorrect font metrics.
+ * cairo_scaled_font_t:
+ *
+ * A #cairo_scaled_font_t is a font scaled to a particular size and device
+ * resolution. A cairo_scaled_font_t is most useful for low-level font
+ * usage where a library or application wants to cache a reference
+ * to a scaled font to speed up the computation of metrics.
*/
-typedef struct _cairo_font cairo_font_t;
+typedef struct _cairo_scaled_font cairo_scaled_font_t;
+
+/**
+ * cairo_font_face_t:
+ *
+ * A #cairo_font_face_t specifies all aspects of a font other
+ * than the size or font matrix (a font matrix is used to distort
+ * a font by sheering it or scaling it unequally in the two
+ * directions) . A font face can be set on a #cairo_t by using
+ * cairo_set_font_face(); the size and font matrix are set with
+ * cairo_set_font_size() and cairo_set_font_matrix().
+ */
+typedef struct _cairo_font_face cairo_font_face_t;
/**
* cairo_glyph_t:
@@ -502,10 +560,10 @@ typedef struct {
* after drawing these glyphs. Will typically be zero except
* for vertical text layout as found in East-Asian languages.
*
- * The #cairo_text_extents_t< structure stores the extents of a single
+ * The #cairo_text_extents_t structure stores the extents of a single
* glyph or a string of glyphs in user-space coordinates. Because text
- * extents are in user-space coordinates, they don't scale along with
- * the current transformation matrix. If you call
+ * extents are in user-space coordinates, they are mostly, but not
+ * entirely, independent of the current transformation matrix. If you call
* <literal>cairo_scale(cr, 2.0, 2.0)</literal>, text will
* be drawn twice as big, but the reported text extents will not be
* doubled. They will change slightly due to hinting (so you can't
@@ -521,6 +579,47 @@ typedef struct {
double y_advance;
} cairo_text_extents_t;
+/**
+ * cairo_font_extents_t:
+ * @ascent: the distance that the font extends above the baseline.
+ * Note that this is not always exactly equal to the maximum
+ * of the extents of all the glyphs in the font, but rather
+ * is picked to express the font designer's intent as to
+ * how the font should align with elements above it.
+ * @descent: the distance that the font extends below the baseline.
+ * This value is positive for typical fonts that include
+ * portions below the baseline. Note that this is not always
+ * exactly equal to the maximum of the extents of all the
+ * glyphs in the font, but rather is picked to express the
+ * font designer's intent as to how the the font should
+ * align with elements below it.
+ * @height: the recommended vertical distance between baselines when
+ * setting consecutive lines of text with the font. This
+ * is greater than @ascent+@descent by a
+ * quantity known as the <firstterm>line spacing</firstterm>
+ * or <firstterm>external leading</firstterm>. When space
+ * is at a premium, most fonts can be set with only
+ * a distance of @ascent+@descent between lines.
+ * @max_x_advance: the maximum distance in the X direction that
+ * the the origin is advanced for any glyph in the font.
+ * @max_y_advance: the maximum distance in the Y direction that
+ * the the origin is advanced for any glyph in the font.
+ * this will be zero for normal fonts used for horizontal
+ * writing. (The scripts of East Asia are sometimes written
+ * vertically.)
+ *
+ * The #cairo_text_extents_t structure stores metric information for
+ * a font. Values are given in the current user-space coordinate
+ * system.
+ *
+ * Because font metrics are in user-space coordinates, they are
+ * mostly, but not entirely, independent of the current transformation
+ * matrix. If you call <literal>cairo_scale(cr, 2.0, 2.0)</literal>,
+ * text will be drawn twice as big, but the reported text extents will
+ * not be doubled. They will change slightly due to hinting (so you
+ * can't assume that metrics are independent of the transformation
+ * matrix), but otherwise will remain unchanged.
+ */
typedef struct {
double ascent;
double descent;
@@ -544,37 +643,42 @@ typedef enum cairo_font_weight {
font object inside the the cairo_t. */
void
-cairo_select_font (cairo_t *cr,
- const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight);
+cairo_select_font_face (cairo_t *cr,
+ const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight);
+
+void
+cairo_set_font_size (cairo_t *cr, double size);
void
-cairo_scale_font (cairo_t *cr, double scale);
+cairo_set_font_matrix (cairo_t *cr,
+ const cairo_matrix_t *matrix);
void
-cairo_transform_font (cairo_t *cr, cairo_matrix_t *matrix);
+cairo_get_font_matrix (cairo_t *cr,
+ cairo_matrix_t *matrix);
void
-cairo_show_text (cairo_t *cr, const unsigned char *utf8);
+cairo_show_text (cairo_t *cr, const char *utf8);
void
cairo_show_glyphs (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs);
-cairo_font_t *
-cairo_current_font (cairo_t *cr);
+cairo_font_face_t *
+cairo_get_font_face (cairo_t *cr);
void
-cairo_current_font_extents (cairo_t *cr,
- cairo_font_extents_t *extents);
+cairo_font_extents (cairo_t *cr,
+ cairo_font_extents_t *extents);
void
-cairo_set_font (cairo_t *cr, cairo_font_t *font);
+cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face);
void
-cairo_text_extents (cairo_t *cr,
- const unsigned char *utf8,
- cairo_text_extents_t *extents);
+cairo_text_extents (cairo_t *cr,
+ const char *utf8,
+ cairo_text_extents_t *extents);
void
cairo_glyph_extents (cairo_t *cr,
@@ -583,119 +687,197 @@ cairo_glyph_extents (cairo_t *cr,
cairo_text_extents_t *extents);
void
-cairo_text_path (cairo_t *cr, const unsigned char *utf8);
+cairo_text_path (cairo_t *cr, const char *utf8);
void
cairo_glyph_path (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs);
-/* Portable interface to general font features. */
-
+/* Generic identifier for a font style */
+
void
-cairo_font_reference (cairo_font_t *font);
+cairo_font_face_reference (cairo_font_face_t *font_face);
void
-cairo_font_destroy (cairo_font_t *font);
+cairo_font_face_destroy (cairo_font_face_t *font_face);
+
+void *
+cairo_font_face_get_user_data (cairo_font_face_t *font_face,
+ const cairo_user_data_key_t *key);
cairo_status_t
-cairo_font_extents (cairo_font_t *font,
- cairo_matrix_t *font_matrix,
- cairo_font_extents_t *extents);
+cairo_font_face_set_user_data (cairo_font_face_t *font_face,
+ const cairo_user_data_key_t *key,
+ void *user_data,
+ cairo_destroy_func_t destroy);
+
+/* Portable interface to general font features. */
+
+cairo_scaled_font_t *
+cairo_scaled_font_create (cairo_font_face_t *font_face,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm);
void
-cairo_font_glyph_extents (cairo_font_t *font,
- cairo_matrix_t *font_matrix,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents);
+cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font);
-/* Image functions */
+void
+cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font);
+
+cairo_status_t
+cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font,
+ cairo_font_extents_t *extents);
-/* XXX: Eliminate width/height here */
void
-cairo_show_surface (cairo_t *cr,
- cairo_surface_t *surface,
- int width,
- int height);
+cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents);
/* Query functions */
-/* XXX: It would be nice if I could find a simpler way to make the
- definitions for the deprecated functions. Ideally, I would just
- have to put DEPRECATE (cairo_get_operator, cairo_current_operator)
- into one file and be done with it. For now, I've got a little more
- typing than that. */
-
cairo_operator_t
-cairo_current_operator (cairo_t *cr);
+cairo_get_operator (cairo_t *cr);
-void
-cairo_current_rgb_color (cairo_t *cr, double *red, double *green, double *blue);
cairo_pattern_t *
-cairo_current_pattern (cairo_t *cr);
-
-double
-cairo_current_alpha (cairo_t *cr);
-
-/* XXX: Do we want cairo_current_pattern as well? */
+cairo_get_source (cairo_t *cr);
double
-cairo_current_tolerance (cairo_t *cr);
+cairo_get_tolerance (cairo_t *cr);
void
-cairo_current_point (cairo_t *cr, double *x, double *y);
+cairo_get_current_point (cairo_t *cr, double *x, double *y);
cairo_fill_rule_t
-cairo_current_fill_rule (cairo_t *cr);
+cairo_get_fill_rule (cairo_t *cr);
double
-cairo_current_line_width (cairo_t *cr);
+cairo_get_line_width (cairo_t *cr);
cairo_line_cap_t
-cairo_current_line_cap (cairo_t *cr);
+cairo_get_line_cap (cairo_t *cr);
cairo_line_join_t
-cairo_current_line_join (cairo_t *cr);
+cairo_get_line_join (cairo_t *cr);
double
-cairo_current_miter_limit (cairo_t *cr);
+cairo_get_miter_limit (cairo_t *cr);
-/* XXX: How to do cairo_current_dash??? Do we want to switch to a cairo_dash object? */
+/* XXX: How to do cairo_get_dash??? Do we want to switch to a cairo_dash object? */
void
-cairo_current_matrix (cairo_t *cr, cairo_matrix_t *matrix);
+cairo_get_matrix (cairo_t *cr, cairo_matrix_t *matrix);
-/* XXX: Need to decide the memory mangement semantics of this
+/* XXX: Need to decide the memory management semantics of this
function. Should it reference the surface again? */
cairo_surface_t *
-cairo_current_target_surface (cairo_t *cr);
+cairo_get_target (cairo_t *cr);
-typedef void (cairo_move_to_func_t) (void *closure,
- double x, double y);
+/**
+ * cairo_path_data_t:
+ *
+ * A data structure for holding path data---appears within
+ * #cairo_path_t.
+ *
+ * The data structure is designed to try to balance the demands of
+ * efficiency and ease-of-use. A path is represented as an array of
+ * cairo_path_data_t which is a union of headers and points.
+ *
+ * Each portion of the path is represented by one or more elements in
+ * the array, (one header followed by 0 or more points). The length
+ * value of the header is the number of array elements for the current
+ * portion including the header, (ie. length == 1 + # of points), and
+ * where the number of points for each element type must be as
+ * follows:
+ *
+ * CAIRO_PATH_MOVE_TO: 1 point
+ * CAIRO_PATH_LINE_TO: 1 point
+ * CAIRO_PATH_CURVE_TO: 3 points
+ * CAIRO_PATH_CLOSE_PATH: 0 points
+ *
+ * The semantics and ordering of the coordinate values are consistent
+ * with cairo_move_to(), cairo_line_to(), cairo_curve_to(), and
+ * cairo_close_path().
+ *
+ * Here is sample code for iterating through a #cairo_path_t:
+ *
+ * <informalexample><programlisting>
+ * int i;
+ * cairo_path_t *path;
+ * cairo_path_data_t *data;
+ *
+ * path = cairo_copy_path (cr);
+ *
+ * for (i=0; i < path->num_data; i += path->data[i].header.length) {
+ * data = &path->data[i];
+ * switch (data->header.type) {
+ * case CAIRO_PATH_MOVE_TO:
+ * do_move_to_things (data[1].point.x, data[1].point.y);
+ * break;
+ * case CAIRO_PATH_LINE_TO:
+ * do_line_to_things (data[1].point.x, data[1].point.y);
+ * break;
+ * case CAIRO_PATH_CURVE_TO:
+ * do_curve_to_things (data[1].point.x, data[1].point.y,
+ * data[2].point.x, data[2].point.y,
+ * data[3].point.x, data[3].point.y);
+ * break;
+ * case CAIRO_PATH_CLOSE_PATH:
+ * do_close_path_things ();
+ * break;
+ * }
+ * }
+ *
+ * cairo_path_destroy (path);
+ * </programlisting></informalexample>
+ */
+typedef union {
+ struct {
+ enum {
+ CAIRO_PATH_MOVE_TO,
+ CAIRO_PATH_LINE_TO,
+ CAIRO_PATH_CURVE_TO,
+ CAIRO_PATH_CLOSE_PATH
+ } type;
+ int length;
+ } header;
+ struct {
+ double x, y;
+ } point;
+} cairo_path_data_t;
-typedef void (cairo_line_to_func_t) (void *closure,
- double x, double y);
+/**
+ * cairo_path_t:
+ *
+ * A data structure for holding a path. This data structure serves as
+ * the return value for cairo_copy_path_data() and
+ * cairo_copy_path_data_flat() as well the input value for
+ * cairo_append_path().
+ *
+ * See #cairo_path_data_t for hints on how to iterate over the
+ * actual data within the path.
+ *
+ * The num_data member gives the number of elements in the data
+ * array. This number is larger than the number of independent path
+ * portions (MOVE_TO, LINE_TO, CURVE_TO, CLOSE_PATH), since the data
+ * includes both headers and coordinates for each portion.
+ **/
+typedef struct cairo_path {
+ cairo_path_data_t *data;
+ int num_data;
+} cairo_path_t;
-typedef void (cairo_curve_to_func_t) (void *closure,
- double x1, double y1,
- double x2, double y2,
- double x3, double y3);
+cairo_path_t *
+cairo_copy_path (cairo_t *cr);
-typedef void (cairo_close_path_func_t) (void *closure);
+cairo_path_t *
+cairo_copy_path_flat (cairo_t *cr);
-extern void
-cairo_current_path (cairo_t *cr,
- cairo_move_to_func_t *move_to,
- cairo_line_to_func_t *line_to,
- cairo_curve_to_func_t *curve_to,
- cairo_close_path_func_t *close_path,
- void *closure);
+void
+cairo_append_path (cairo_t *cr,
+ cairo_path_t *path);
-extern void
-cairo_current_path_flat (cairo_t *cr,
- cairo_move_to_func_t *move_to,
- cairo_line_to_func_t *line_to,
- cairo_close_path_func_t *close_path,
- void *closure);
+void
+cairo_path_destroy (cairo_path_t *path);
/* Error status queries */
@@ -706,17 +888,38 @@ const char *
cairo_status_string (cairo_t *cr);
/* Surface manipulation */
-/* XXX: We may want to rename this function in light of the new
- virtualized surface backends... */
-cairo_surface_t *
-cairo_surface_create_for_image (char *data,
- cairo_format_t format,
- int width,
- int height,
- int stride);
+
+/**
+ * cairo_format_t
+ * @CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with
+ * alpha in the upper 8 bits, then red, then green, then blue.
+ * The 32-bit quantities are stored native-endian. Pre-multiplied
+ * alpha is used. (That is, 50% transparent red is 0x80800000,
+ * not 0x80ff0000.)
+ * @CAIRO_FORMAT_RGB24: each pixel is a 32-bit quantity, with
+ * the upper 8 bits unused. Red, Green, and Blue are stored
+ * in the remaining 24 bits in that order.
+ * @CAIRO_FORMAT_A8: each pixel is a 8-bit quantity holding
+ * an alpha value.
+ * @CAIRO_FORMAT_A1: each pixel is a 1-bit quantity holding
+ * an alpha value. Pixels are packed together into 32-bit
+ * quantities. The ordering of the bits matches the
+ * endianess of the platform. On a big-endian machine, the
+ * first pixel is in the uppermost bit, on a little-endian
+ * machine the first pixel is in the least-significant bit.
+ *
+ * #cairo_format_t is used to identify the memory format of
+ * image data.
+ */
+typedef enum cairo_format {
+ CAIRO_FORMAT_ARGB32,
+ CAIRO_FORMAT_RGB24,
+ CAIRO_FORMAT_A8,
+ CAIRO_FORMAT_A1
+} cairo_format_t;
/* XXX: I want to remove this function, (replace with
- cairo_set_target_scratch or similar). */
+ cairo_begin_group and friends). */
cairo_surface_t *
cairo_surface_create_similar (cairo_surface_t *other,
cairo_format_t format,
@@ -729,35 +932,36 @@ cairo_surface_reference (cairo_surface_t *surface);
void
cairo_surface_destroy (cairo_surface_t *surface);
-/* XXX: Note: The current Render/Ic implementations don't do the right
- thing with repeat when the surface has a non-identity matrix. */
-/* XXX: Rework this as a cairo function with an enum: cairo_set_pattern_extend */
cairo_status_t
-cairo_surface_set_repeat (cairo_surface_t *surface, int repeat);
+cairo_surface_finish (cairo_surface_t *surface);
+
+#if CAIRO_HAS_PNG_FUNCTIONS
-/* XXX: Rework this as a cairo function: cairo_set_pattern_transform */
cairo_status_t
-cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix);
+cairo_surface_write_to_png (cairo_surface_t *surface,
+ const char *filename);
-/* XXX: Rework this as a cairo function: cairo_current_pattern_transform */
cairo_status_t
-cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix);
+cairo_surface_write_to_png_stream (cairo_surface_t *surface,
+ cairo_write_func_t write_func,
+ void *closure);
+
+#endif
+
+void *
+cairo_surface_get_user_data (cairo_surface_t *surface,
+ const cairo_user_data_key_t *key);
-typedef enum {
- CAIRO_FILTER_FAST,
- CAIRO_FILTER_GOOD,
- CAIRO_FILTER_BEST,
- CAIRO_FILTER_NEAREST,
- CAIRO_FILTER_BILINEAR,
- CAIRO_FILTER_GAUSSIAN
-} cairo_filter_t;
-
-/* XXX: Rework this as a cairo function: cairo_set_pattern_filter */
cairo_status_t
-cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter);
+cairo_surface_set_user_data (cairo_surface_t *surface,
+ const cairo_user_data_key_t *key,
+ void *user_data,
+ cairo_destroy_func_t destroy);
-cairo_filter_t
-cairo_surface_get_filter (cairo_surface_t *surface);
+void
+cairo_surface_set_device_offset (cairo_surface_t *surface,
+ double x_offset,
+ double y_offset);
/* Image-surface functions */
@@ -767,12 +971,29 @@ cairo_image_surface_create (cairo_format_t format,
int height);
cairo_surface_t *
-cairo_image_surface_create_for_data (char *data,
+cairo_image_surface_create_for_data (unsigned char *data,
cairo_format_t format,
int width,
int height,
int stride);
+int
+cairo_image_surface_get_width (cairo_surface_t *surface);
+
+int
+cairo_image_surface_get_height (cairo_surface_t *surface);
+
+#if CAIRO_HAS_PNG_FUNCTIONS
+
+cairo_surface_t *
+cairo_image_surface_create_from_png (const char *filename);
+
+cairo_surface_t *
+cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
+ void *closure);
+
+#endif
+
/* Pattern creation functions */
cairo_pattern_t *
cairo_pattern_create_for_surface (cairo_surface_t *surface);
@@ -792,16 +1013,23 @@ void
cairo_pattern_destroy (cairo_pattern_t *pattern);
cairo_status_t
-cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
- double offset,
- double red, double green, double blue,
- double alpha);
-
+cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern,
+ double offset,
+ double red, double green, double blue);
+
cairo_status_t
-cairo_pattern_set_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix);
+cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern,
+ double offset,
+ double red, double green, double blue,
+ double alpha);
cairo_status_t
-cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix);
+cairo_pattern_set_matrix (cairo_pattern_t *pattern,
+ const cairo_matrix_t *matrix);
+
+cairo_status_t
+cairo_pattern_get_matrix (cairo_pattern_t *pattern,
+ cairo_matrix_t *matrix);
typedef enum {
CAIRO_EXTEND_NONE,
@@ -815,6 +1043,15 @@ cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend);
cairo_extend_t
cairo_pattern_get_extend (cairo_pattern_t *pattern);
+typedef enum {
+ CAIRO_FILTER_FAST,
+ CAIRO_FILTER_GOOD,
+ CAIRO_FILTER_BEST,
+ CAIRO_FILTER_NEAREST,
+ CAIRO_FILTER_BILINEAR,
+ CAIRO_FILTER_GAUSSIAN
+} cairo_filter_t;
+
cairo_status_t
cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter);
@@ -823,72 +1060,135 @@ cairo_pattern_get_filter (cairo_pattern_t *pattern);
/* Matrix functions */
-/* XXX: Rename all of these to cairo_transform_t */
-
-cairo_matrix_t *
-cairo_matrix_create (void);
-
void
-cairo_matrix_destroy (cairo_matrix_t *matrix);
+cairo_matrix_init (cairo_matrix_t *matrix,
+ double xx, double yx,
+ double xy, double yy,
+ double x0, double y0);
-cairo_status_t
-cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other);
+void
+cairo_matrix_init_identity (cairo_matrix_t *matrix);
-cairo_status_t
-cairo_matrix_set_identity (cairo_matrix_t *matrix);
+void
+cairo_matrix_init_translate (cairo_matrix_t *matrix,
+ double tx, double ty);
-cairo_status_t
-cairo_matrix_set_affine (cairo_matrix_t *matrix,
- double a, double b,
- double c, double d,
- double tx, double ty);
+void
+cairo_matrix_init_scale (cairo_matrix_t *matrix,
+ double sx, double sy);
-cairo_status_t
-cairo_matrix_get_affine (cairo_matrix_t *matrix,
- double *a, double *b,
- double *c, double *d,
- double *tx, double *ty);
+void
+cairo_matrix_init_rotate (cairo_matrix_t *matrix,
+ double radians);
-cairo_status_t
+void
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty);
-cairo_status_t
+void
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy);
-cairo_status_t
+void
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);
+void
+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);
+/* XXX: Need a new name here perhaps. */
+void
+cairo_matrix_transform_distance (const cairo_matrix_t *matrix,
+ double *dx, double *dy);
-cairo_status_t
-cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y);
+/* XXX: Need a new name here perhaps. */
+void
+cairo_matrix_transform_point (const cairo_matrix_t *matrix,
+ double *x, double *y);
-/* Deprecated functions. We've made some effort to allow the
- deprecated functions to continue to work for now, (with useful
- warnings). But the deprecated functions will not appear in the next
- release. */
#ifndef _CAIROINT_H_
-#define cairo_get_operator cairo_get_operator_DEPRECATED_BY_cairo_current_operator
-#define cairo_get_rgb_color cairo_get_rgb_color_DEPRECATED_BY_cairo_current_rgb_color
-#define cairo_get_alpha cairo_get_alpha_DEPRECATED_BY_cairo_current_alpha
-#define cairo_get_tolerance cairo_get_tolerance_DEPRECATED_BY_cairo_current_tolerance
-#define cairo_get_current_point cairo_get_current_point_DEPRECATED_BY_cairo_current_point
-#define cairo_get_fill_rule cairo_get_fill_rule_DEPRECATED_BY_cairo_current_fill_rule
-#define cairo_get_line_width cairo_get_line_width_DEPRECATED_BY_cairo_current_line_width
-#define cairo_get_line_cap cairo_get_line_cap_DEPRECATED_BY_cairo_current_line_cap
-#define cairo_get_line_join cairo_get_line_join_DEPRECATED_BY_cairo_current_line_join
-#define cairo_get_miter_limit cairo_get_miter_limit_DEPRECATED_BY_cairo_current_miter_limit
-#define cairo_get_matrix cairo_get_matrix_DEPRECATED_BY_cairo_current_matrix
-#define cairo_get_target_surface cairo_get_target_surface_DEPRECATED_BY_cairo_current_target_surface
-#define cairo_get_status cairo_get_status_DEPRECATED_BY_cairo_status
-#define cairo_get_status_string cairo_get_status_string_DEPRECATED_BY_cairo_status_string
+
+/* Obsolete functions. These definitions exist to coerce the compiler
+ * into providing a little bit of guidance with its error
+ * messages. The idea is to help users port their old code without
+ * having to dig through lots of documentation.
+ *
+ * The first set of REPLACED_BY functions is for functions whose names
+ * have just been changed. So fixing these up is mechanical, (and
+ * automated by means of the cairo/util/cairo-api-update script.
+ *
+ * The second set of DEPRECATED_BY functions is for functions where
+ * the replacement is used in a different way, (ie. different
+ * arguments, multiple functions instead of one, etc). Fixing these up
+ * will require a bit more work on the user's part, (and hopefully we
+ * can get cairo-api-update to find these and print some guiding
+ * information).
+ */
+#define cairo_current_font_extents cairo_current_font_extents_REPLACED_BY_cairo_font_extents
+#define cairo_get_font_extents cairo_get_font_extents_REPLACED_BY_cairo_font_extents
+#define cairo_current_operator cairo_current_operator_REPLACED_BY_cairo_get_operator
+#define cairo_current_tolerance cairo_current_tolerance_REPLACED_BY_cairo_get_tolerance
+#define cairo_current_point cairo_current_point_REPLACED_BY_cairo_get_current_point
+#define cairo_current_fill_rule cairo_current_fill_rule_REPLACED_BY_cairo_get_fill_rule
+#define cairo_current_line_width cairo_current_line_width_REPLACED_BY_cairo_get_line_width
+#define cairo_current_line_cap cairo_current_line_cap_REPLACED_BY_cairo_get_line_cap
+#define cairo_current_line_join cairo_current_line_join_REPLACED_BY_cairo_get_line_join
+#define cairo_current_miter_limit cairo_current_miter_limit_REPLACED_BY_cairo_get_miter_limit
+#define cairo_current_matrix cairo_current_matrix_REPLACED_BY_cairo_get_matrix
+#define cairo_current_target_surface cairo_current_target_surface_REPLACED_BY_cairo_get_target
+#define cairo_get_status cairo_get_status_REPLACED_BY_cairo_status
+#define cairo_get_status_string cairo_get_status_string_REPLACED_BY_cairo_status_string
+#define cairo_concat_matrix cairo_concat_matrix_REPLACED_BY_cairo_transform
+#define cairo_scale_font cairo_scale_font_REPLACED_BY_cairo_set_font_size
+#define cairo_select_font cairo_select_font_REPLACED_BY_cairo_select_font_face
+#define cairo_transform_font cairo_transform_font_REPLACED_BY_cairo_set_font_matrix
+#define cairo_transform_point cairo_transform_point_REPLACED_BY_cairo_user_to_device
+#define cairo_transform_distance cairo_transform_distance_REPLACED_BY_cairo_user_to_device_distance
+#define cairo_inverse_transform_point cairo_inverse_transform_point_REPLACED_BY_cairo_device_to_user
+#define cairo_inverse_transform_distance cairo_inverse_transform_distance_REPLACED_BY_cairo_device_to_user_distance
+#define cairo_init_clip cairo_init_clip_REPLACED_BY_cairo_reset_clip
+#define cairo_surface_create_for_image cairo_surface_create_for_image_REPLACED_BY_cairo_image_surface_create_for_data
+#define cairo_default_matrix cairo_default_matrix_REPLACED_BY_cairo_identity_matrix
+#define cairo_matrix_set_affine cairo_matrix_set_affine_REPLACED_BY_cairo_matrix_init
+#define cairo_matrix_set_identity cairo_matrix_set_identity_REPLACED_BY_cairo_matrix_init_identity
+#define cairo_pattern_add_color_stop cairo_pattern_add_color_stop_REPLACED_BY_cairo_pattern_add_color_stop_rgba
+#define cairo_set_rgb_color cairo_set_rgb_color_REPLACED_BY_cairo_set_source_rgb
+#define cairo_set_pattern cairo_set_pattern_REPLACED_BY_cairo_set_source
+#define cairo_xlib_surface_create_for_pixmap_with_visual cairo_xlib_surface_create_for_pixmap_with_visual_REPLACED_BY_cairo_xlib_surface_create
+#define cairo_xlib_surface_create_for_window_with_visual cairo_xlib_surface_create_for_window_with_visual_REPLACED_BY_cairo_xlib_surface_create
+#define cairo_xcb_surface_create_for_pixmap_with_visual cairo_xcb_surface_create_for_pixmap_with_visual_REPLACED_BY_cairo_xcb_surface_create
+#define cairo_xcb_surface_create_for_window_with_visual cairo_xcb_surface_create_for_window_with_visual_REPLACED_BY_cairo_xcb_surface_create
+
+
+#define cairo_current_path cairo_current_path_DEPRECATED_BY_cairo_copy_path
+#define cairo_current_path_flat cairo_current_path_flat_DEPRECATED_BY_cairo_copy_path_flat
+#define cairo_get_path cairo_get_path_DEPRECATED_BY_cairo_copy_path
+#define cairo_get_path_flat cairo_get_path_flat_DEPRECATED_BY_cairo_get_path_flat
+#define cairo_set_alpha cairo_set_alpha_DEPRECATED_BY_cairo_set_source_rgba_OR_cairo_paint_with_alpha
+#define cairo_show_surface cairo_show_surface_DEPRECATED_BY_cairo_set_source_surface_AND_cairo_paint
+#define cairo_copy cairo_copy_DEPRECATED_BY_cairo_create_AND_MANY_INDIVIDUAL_FUNCTIONS
+#define cairo_surface_set_repeat cairo_surface_set_repeat_DEPRECATED_BY_cairo_pattern_set_extend
+#define cairo_surface_set_matrix cairo_surface_set_matrix_DEPRECATED_BY_cairo_pattern_set_matrix
+#define cairo_surface_get_matrix cairo_surface_get_matrix_DEPRECATED_BY_cairo_pattern_get_matrix
+#define cairo_surface_set_filter cairo_surface_set_filter_DEPRECATED_BY_cairo_pattern_set_filter
+#define cairo_surface_get_filter cairo_surface_get_filter_DEPRECATED_BY_cairo_pattern_get_filter
+#define cairo_matrix_create cairo_matrix_create_DEPRECATED_BY_cairo_matrix_t
+#define cairo_matrix_destroy cairo_matrix_destroy_DEPRECATED_BY_cairo_matrix_t
+#define cairo_matrix_copy cairo_matrix_copy_DEPRECATED_BY_cairo_matrix_t
+#define cairo_matrix_get_affine cairo_matrix_get_affine_DEPRECATED_BY_cairo_matrix_t
+#define cairo_set_target_surface cairo_set_target_surface_DEPRECATED_BY_cairo_create
+#define cairo_set_target_glitz cairo_set_target_glitz_DEPRECATED_BY_cairo_glitz_surface_create
+#define cairo_set_target_image cairo_set_target_image_DEPRECATED_BY_cairo_image_surface_create_for_data
+#define cairo_set_target_pdf cairo_set_target_pdf_DEPRECATED_BY_cairo_pdf_surface_create
+#define cairo_set_target_png cairo_set_target_png_DEPRECATED_BY_cairo_surface_write_to_png
+#define cairo_set_target_ps cairo_set_target_ps_DEPRECATED_BY_cairo_ps_surface_create
+#define cairo_set_target_quartz cairo_set_target_quartz_DEPRECATED_BY_cairo_quartz_surface_create
+#define cairo_set_target_win32 cairo_set_target_win32_DEPRECATED_BY_cairo_win32_surface_create
+#define cairo_set_target_xcb cairo_set_target_xcb_DEPRECATED_BY_cairo_xcb_surface_create
+#define cairo_set_target_drawable cairo_set_target_drawable_DEPRECATED_BY_cairo_xlib_surface_create
+
#endif
CAIRO_END_DECLS
diff --git a/src/cairo_array.c b/src/cairo_array.c
deleted file mode 100644
index 2b1cf9d61..000000000
--- a/src/cairo_array.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2004 Red Hat, Inc
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Kristian Høgsberg <krh@redhat.com>
- */
-
-#include "cairoint.h"
-
-void
-_cairo_array_init (cairo_array_t *array, int element_size)
-{
- array->size = 0;
- array->num_elements = 0;
- array->element_size = element_size;
- array->elements = NULL;
-}
-
-void
-_cairo_array_fini (cairo_array_t *array)
-{
- free (array->elements);
-}
-
-cairo_status_t
-_cairo_array_grow_by (cairo_array_t *array, int additional)
-{
- char *new_elements;
- int old_size = array->size;
- int required_size = array->num_elements + additional;
- int new_size;
-
- if (required_size <= old_size)
- return CAIRO_STATUS_SUCCESS;
-
- if (old_size == 0)
- new_size = 1;
- else
- new_size = old_size * 2;
-
- while (new_size < required_size)
- new_size = new_size * 2;
-
- array->size = new_size;
- new_elements = realloc (array->elements,
- array->size * array->element_size);
-
- if (new_elements == NULL) {
- array->size = old_size;
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- array->elements = new_elements;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_array_truncate (cairo_array_t *array, int num_elements)
-{
- if (num_elements < array->num_elements)
- array->num_elements = num_elements;
-}
-
-void *
-_cairo_array_index (cairo_array_t *array, int index)
-{
- assert (0 <= index && index < array->num_elements);
-
- return (void *) &array->elements[index * array->element_size];
-}
-
-void
-_cairo_array_copy_element (cairo_array_t *array, int index, void *dst)
-{
- memcpy (dst, _cairo_array_index (array, index), array->element_size);
-}
-
-void *
-_cairo_array_append (cairo_array_t *array,
- const void *elements, int num_elements)
-{
- cairo_status_t status;
- void *dest;
-
- status = _cairo_array_grow_by (array, num_elements);
- if (status != CAIRO_STATUS_SUCCESS)
- return NULL;
-
- assert (array->num_elements + num_elements <= array->size);
-
- dest = &array->elements[array->num_elements * array->element_size];
- array->num_elements += num_elements;
-
- if (elements != NULL)
- memcpy (dest, elements, num_elements * array->element_size);
-
- return dest;
-}
-
-int
-_cairo_array_num_elements (cairo_array_t *array)
-{
- return array->num_elements;
-}
diff --git a/src/cairo_atsui_font.c b/src/cairo_atsui_font.c
deleted file mode 100644
index cb4b1c5d7..000000000
--- a/src/cairo_atsui_font.c
+++ /dev/null
@@ -1,807 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2004 Calum Robinson
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is Calum Robinson
- *
- * Contributor(s):
- * Calum Robinson <calumr@mac.com>
- */
-
-#include <stdlib.h>
-#include <math.h>
-
-#include "cairo-atsui.h"
-#include "cairoint.h"
-
-
-
-
-
-#pragma mark Types
-
-
-
-
-
-typedef struct {
- cairo_unscaled_font_t base;
-
- ATSUStyle style;
- ATSUFontID fontID;
-} cairo_atsui_font_t;
-
-
-typedef struct cairo_ATSUI_glyph_path_callback_info_t {
- cairo_path_t *path;
- cairo_matrix_t scale;
-} cairo_ATSUI_glyph_path_callback_info_t;
-
-
-
-
-
-#pragma mark Private Functions
-
-
-
-
-
-static CGAffineTransform CGAffineTransformMakeWithCairoFontScale(cairo_font_scale_t scale)
-{
- return CGAffineTransformMake( scale.matrix[0][0], scale.matrix[0][1],
- scale.matrix[1][0], scale.matrix[1][1],
- 0, 0);
-}
-
-
-static ATSUStyle CreateSizedCopyOfStyle(ATSUStyle inStyle, cairo_font_scale_t *scale)
-{
- ATSUStyle style;
- OSStatus err;
-
-
- // Set the style's size
- CGAffineTransform theTransform = CGAffineTransformMakeWithCairoFontScale(*scale);
- Fixed theSize = FloatToFixed(CGSizeApplyAffineTransform(CGSizeMake(1.0, 1.0), theTransform).height);
- const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag };
- const ByteCount theFontStyleSizes[] = { sizeof(Fixed) };
- ATSUAttributeValuePtr theFontStyleValues[] = { &theSize };
-
- err = ATSUCreateAndCopyStyle(inStyle, &style);
-
- err = ATSUSetAttributes( style,
- sizeof(theFontStyleTags) / sizeof(ATSUAttributeTag),
- theFontStyleTags, theFontStyleSizes, theFontStyleValues);
-
-
- return style;
-}
-
-
-
-
-
-#pragma mark Public Functions
-
-
-
-
-
-static cairo_unscaled_font_t *
-_cairo_atsui_font_create( const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight)
-{
- cairo_atsui_font_t *font = NULL;
- ATSUStyle style;
- ATSUFontID fontID;
- OSStatus err;
- Boolean isItalic, isBold;
-
-
- err = ATSUCreateStyle(&style);
-
-
- switch (weight)
- {
- case CAIRO_FONT_WEIGHT_BOLD:
- isBold = true;
- break;
- case CAIRO_FONT_WEIGHT_NORMAL:
- default:
- isBold = false;
- break;
- }
-
- switch (slant)
- {
- case CAIRO_FONT_SLANT_ITALIC:
- isItalic = true;
- break;
- case CAIRO_FONT_SLANT_OBLIQUE:
- isItalic = false;
- break;
- case CAIRO_FONT_SLANT_NORMAL:
- default:
- isItalic = false;
- break;
- }
-
- err = ATSUFindFontFromName( family, strlen(family),
- kFontFamilyName,
- kFontNoPlatformCode,
- kFontRomanScript,
- kFontNoLanguageCode,
- &fontID);
-
-
- ATSUAttributeTag styleTags[] = {kATSUQDItalicTag, kATSUQDBoldfaceTag, kATSUFontTag};
- ATSUAttributeValuePtr styleValues[] = {&isItalic, &isBold, &fontID};
- ByteCount styleSizes[] = {sizeof(Boolean), sizeof(Boolean), sizeof(ATSUFontID)};
-
-
- err = ATSUSetAttributes( style,
- sizeof(styleTags) / sizeof(styleTags[0]),
- styleTags,
- styleSizes,
- styleValues);
-
-
-
- font = malloc(sizeof(cairo_atsui_font_t));
-
- if (_cairo_unscaled_font_init(&font->base, &cairo_atsui_font_backend) == CAIRO_STATUS_SUCCESS)
- {
- font->style = style;
- font->fontID = fontID;
-
-
- return &font->base;
- }
-
-
- free(font);
-
- return NULL;
-}
-
-
-static void
-_cairo_atsui_font_destroy(void *abstract_font)
-{
- cairo_atsui_font_t *font = abstract_font;
-
-
- if (font == NULL)
- return;
-
- if (font->style)
- ATSUDisposeStyle(font->style);
-
- free(font);
-}
-
-
-static cairo_status_t
-_cairo_atsui_font_text_to_glyphs( void *abstract_font,
- cairo_font_scale_t *sc,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *nglyphs)
-{
- cairo_atsui_font_t *font = abstract_font;
- size_t i;
- OSStatus err;
- ATSUTextLayout textLayout;
- ATSLayoutRecord *layoutRecords;
- ItemCount glyphCount, charCount;
- UniChar *theText;
- ATSUStyle style;
-
-
- charCount = strlen(utf8);
-
-
- err = ATSUCreateTextLayout(&textLayout);
-
-
- // Set the text in the text layout object, so we can measure it
- theText = (UniChar *)malloc(charCount * sizeof(UniChar));
-
- for (i = 0; i < charCount; i++)
- {
- theText[i] = utf8[i];
- }
-
- err = ATSUSetTextPointerLocation( textLayout,
- theText,
- 0,
- charCount,
- charCount);
-
-
- style = CreateSizedCopyOfStyle(font->style, sc);
-
-
- // Set the style for all of the text
- err = ATSUSetRunStyle( textLayout,
- style,
- kATSUFromTextBeginning,
- kATSUToTextEnd);
-
-
-
- // Get the glyphs from the text layout object
- err = ATSUDirectGetLayoutDataArrayPtrFromTextLayout( textLayout,
- 0,
- kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
- (void *)&layoutRecords,
- &glyphCount);
-
- *nglyphs = glyphCount;
-
-
- *glyphs = (cairo_glyph_t *)malloc(glyphCount * (sizeof(cairo_glyph_t)));
- if (*glyphs == NULL)
- {
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- for (i = 0; i < glyphCount; i++)
- {
- (*glyphs)[i].index = layoutRecords[i].glyphID;
- (*glyphs)[i].x = FixedToFloat(layoutRecords[i].realPos);
- (*glyphs)[i].y = 0;
- }
-
-
- free(theText);
-
- ATSUDirectReleaseLayoutDataArrayPtr( NULL,
- kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
- (void *)&layoutRecords);
-
- ATSUDisposeTextLayout(textLayout);
-
- ATSUDisposeStyle(style);
-
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-static cairo_status_t
-_cairo_atsui_font_font_extents( void *abstract_font,
- cairo_font_scale_t *sc,
- cairo_font_extents_t *extents)
-{
- cairo_atsui_font_t *font = abstract_font;
- ATSFontRef atsFont;
- ATSFontMetrics metrics;
- OSStatus err;
-
-
- // TODO - test this
-
- atsFont = FMGetATSFontRefFromFont(font->fontID);
-
- if (atsFont)
- {
- err = ATSFontGetHorizontalMetrics(atsFont, kATSOptionFlagsDefault, &metrics);
-
- if (err == noErr)
- {
- extents->ascent = metrics.ascent;
- extents->descent = metrics.descent;
- extents->height = metrics.capHeight;
- extents->max_x_advance = metrics.maxAdvanceWidth;
-
- // The FT backend doesn't handle max_y_advance either, so we'll ignore it for now.
- extents->max_y_advance = 0.0;
-
-
- return CAIRO_STATUS_SUCCESS;
- }
- }
-
-
- return CAIRO_STATUS_NULL_POINTER;
-}
-
-
-static cairo_status_t
-_cairo_atsui_font_glyph_extents( void *abstract_font,
- cairo_font_scale_t *sc,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
-{
- cairo_atsui_font_t *font = abstract_font;
- cairo_point_double_t origin;
- cairo_point_double_t glyph_min, glyph_max;
- cairo_point_double_t total_min, total_max;
- OSStatus err;
- ATSUStyle style;
- int i;
-
-
- if (num_glyphs == 0)
- {
- extents->x_bearing = 0.0;
- extents->y_bearing = 0.0;
- extents->width = 0.0;
- extents->height = 0.0;
- extents->x_advance = 0.0;
- extents->y_advance = 0.0;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- origin.x = glyphs[0].x;
- origin.y = glyphs[0].y;
-
-
- style = CreateSizedCopyOfStyle(font->style, sc);
-
-
- for (i = 0; i < num_glyphs; i++)
- {
- GlyphID theGlyph = glyphs[i].index;
- double minX, maxX, ascent, descent;
- ATSGlyphIdealMetrics metricsH, metricsV;
-
-
- err = ATSUGlyphGetIdealMetrics( style,
- 1,
- &theGlyph,
- 0,
- &metricsH);
-
-
- ATSUVerticalCharacterType verticalType = kATSUStronglyVertical;
- ATSUAttributeTag theTag = kATSUVerticalCharacterTag;
- ByteCount theSize = sizeof(ATSUVerticalCharacterType);
-
- err = ATSUSetAttributes(style, 1, &theTag, &theSize, (ATSUAttributeValuePtr)&verticalType);
-
- err = ATSUGlyphGetIdealMetrics( style,
- 1,
- &theGlyph,
- 0,
- &metricsV);
-
- minX = metricsH.otherSideBearing.x;
- maxX = metricsH.advance.x;
-
- ascent = metricsV.advance.x;
- descent = metricsV.otherSideBearing.x;
-
- glyph_min.x = glyphs[i].x + minX;
- glyph_min.y = glyphs[i].y + descent;
- glyph_max.x = glyphs[i].x + maxX;
- glyph_max.y = glyphs[i].y + ascent;
-
- if (i==0)
- {
- total_min = glyph_min;
- total_max = glyph_max;
- }
- else
- {
- if (glyph_min.x < total_min.x)
- total_min.x = glyph_min.x;
- if (glyph_min.y < total_min.y)
- total_min.y = glyph_min.y;
-
- if (glyph_max.x > total_max.x)
- total_max.x = glyph_max.x;
- if (glyph_max.y > total_max.y)
- total_max.y = glyph_max.y;
- }
- }
-
-
- extents->x_bearing = total_min.x - origin.x;
- extents->y_bearing = total_min.y - origin.y;
- extents->width = total_max.x - total_min.x;
- extents->height = total_max.y - total_min.y;
- extents->x_advance = glyphs[i-1].x - origin.x;
- extents->y_advance = glyphs[i-1].y - origin.y;
-
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-static cairo_status_t
-_cairo_atsui_font_glyph_bbox( void *abstract_font,
- cairo_font_scale_t *sc,
- const cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox)
-{
- cairo_atsui_font_t *font = abstract_font;
- cairo_fixed_t x1, y1, x2, y2;
- int i;
- OSStatus err;
- ATSUStyle style;
-
-
- bbox->p1.x = bbox->p1.y = CAIRO_MAXSHORT << 16;
- bbox->p2.x = bbox->p2.y = CAIRO_MINSHORT << 16;
-
-
- style = CreateSizedCopyOfStyle(font->style, sc);
-
-
- for (i = 0; i < num_glyphs; i++)
- {
- GlyphID theGlyph = glyphs[i].index;
- ATSGlyphIdealMetrics metrics;
-
-
- err = ATSUGlyphGetIdealMetrics( style,
- 1,
- &theGlyph,
- 0,
- &metrics);
-
- x1 = _cairo_fixed_from_double(glyphs[i].x);
- y1 = _cairo_fixed_from_double(glyphs[i].y);
- x2 = x1 + _cairo_fixed_from_double(metrics.advance.x);
- y2 = y1 + _cairo_fixed_from_double(metrics.advance.y);
-
- if (x1 < bbox->p1.x)
- bbox->p1.x = x1;
-
- if (y1 < bbox->p1.y)
- bbox->p1.y = y1;
-
- if (x2 > bbox->p2.x)
- bbox->p2.x = x2;
-
- if (y2 > bbox->p2.y)
- bbox->p2.y = y2;
- }
-
-
- ATSUDisposeStyle(style);
-
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-static cairo_status_t
-_cairo_atsui_font_show_glyphs( void *abstract_font,
- cairo_font_scale_t *sc,
- cairo_operator_t operator,
- cairo_surface_t *source,
- cairo_surface_t *surface,
- int source_x,
- int source_y,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_atsui_font_t *font = abstract_font;
- CGContextRef myBitmapContext;
- CGColorSpaceRef colorSpace;
- cairo_image_surface_t *destImageSurface;
- int i;
-
-
- destImageSurface = _cairo_surface_get_image(surface);
-
-
- // Create a CGBitmapContext for the dest surface for drawing into
- colorSpace = CGColorSpaceCreateDeviceRGB();
-
- myBitmapContext = CGBitmapContextCreate( destImageSurface->data,
- destImageSurface->width,
- destImageSurface->height,
- destImageSurface->depth / 4,
- destImageSurface->stride,
- colorSpace,
- kCGImageAlphaPremultipliedFirst);
-
-
- ATSFontRef atsFont = FMGetATSFontRefFromFont(font->fontID);
- CGFontRef cgFont = CGFontCreateWithPlatformFont(&atsFont);
-
- CGContextSetFont(myBitmapContext, cgFont);
-
-
- CGAffineTransform textTransform = CGAffineTransformMakeWithCairoFontScale(*sc);
- CGSize textSize = CGSizeMake(1.0, 1.0);
-
- textSize = CGSizeApplyAffineTransform(textSize, textTransform);
-
- CGContextSetFontSize(myBitmapContext, textSize.width);
-
-
- // TODO - bold and italic text
- //
- // We could draw the text using ATSUI and get bold, italics
- // etc. for free, but ATSUI does a lot of text layout work
- // that we don't really need...
-
-
- for (i = 0; i < num_glyphs; i++)
- {
- CGGlyph theGlyph = glyphs[i].index;
-
- CGContextShowGlyphsAtPoint(myBitmapContext, source_x + glyphs[i].x, destImageSurface->height - (source_y + glyphs[i].y), &theGlyph, 1);
- }
-
-
- CGColorSpaceRelease(colorSpace);
- CGContextRelease(myBitmapContext);
-
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-#pragma mark -
-
-
-static OSStatus MyATSCubicMoveToCallback(const Float32Point *pt, void *callBackDataPtr)
-{
- cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
- double scaledPt[2];
- cairo_point_t point;
-
-
- scaledPt[0] = pt->x;
- scaledPt[1] = pt->y;
-
- cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
-
- point.x = _cairo_fixed_from_double(scaledPt[0]);
- point.y = _cairo_fixed_from_double(scaledPt[1]);
-
- _cairo_path_move_to(info->path, &point);
-
-
- return noErr;
-}
-
-
-static OSStatus MyATSCubicLineToCallback(const Float32Point *pt, void *callBackDataPtr)
-{
- cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
- cairo_point_t point;
- double scaledPt[2];
-
-
- scaledPt[0] = pt->x;
- scaledPt[1] = pt->y;
-
- cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
-
- point.x = _cairo_fixed_from_double(scaledPt[0]);
- point.y = _cairo_fixed_from_double(scaledPt[1]);
-
- _cairo_path_line_to(info->path, &point);
-
-
- return noErr;
-}
-
-
-static OSStatus MyATSCubicCurveToCallback( const Float32Point *pt1,
- const Float32Point *pt2,
- const Float32Point *pt3,
- void *callBackDataPtr)
-{
- cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
- cairo_point_t p0, p1, p2;
- double scaledPt[2];
-
-
- scaledPt[0] = pt1->x;
- scaledPt[1] = pt1->y;
-
- cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
-
- p0.x = _cairo_fixed_from_double(scaledPt[0]);
- p0.y = _cairo_fixed_from_double(scaledPt[1]);
-
-
- scaledPt[0] = pt2->x;
- scaledPt[1] = pt2->y;
-
- cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
-
- p1.x = _cairo_fixed_from_double(scaledPt[0]);
- p1.y = _cairo_fixed_from_double(scaledPt[1]);
-
-
- scaledPt[0] = pt3->x;
- scaledPt[1] = pt3->y;
-
- cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
-
- p2.x = _cairo_fixed_from_double(scaledPt[0]);
- p2.y = _cairo_fixed_from_double(scaledPt[1]);
-
-
- _cairo_path_curve_to(info->path, &p0, &p1, &p2);
-
-
- return noErr;
-}
-
-
-static OSStatus MyCubicClosePathProc(void * callBackDataPtr)
-{
- cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
-
-
- _cairo_path_close_path(info->path);
-
-
- return noErr;
-}
-
-
-static cairo_status_t
-_cairo_atsui_font_glyph_path( void *abstract_font,
- cairo_font_scale_t *sc,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path)
-{
- int i;
- cairo_atsui_font_t *font = abstract_font;
- OSStatus err;
- cairo_ATSUI_glyph_path_callback_info_t info;
- ATSUStyle style;
-
-
- static ATSCubicMoveToUPP moveProc = NULL;
- static ATSCubicLineToUPP lineProc = NULL;
- static ATSCubicCurveToUPP curveProc = NULL;
- static ATSCubicClosePathUPP closePathProc = NULL;
-
-
- if (moveProc == NULL)
- {
- moveProc = NewATSCubicMoveToUPP(MyATSCubicMoveToCallback);
- lineProc = NewATSCubicLineToUPP(MyATSCubicLineToCallback);
- curveProc = NewATSCubicCurveToUPP(MyATSCubicCurveToCallback);
- closePathProc = NewATSCubicClosePathUPP(MyCubicClosePathProc);
- }
-
-
- info.path = path;
-
-
- style = CreateSizedCopyOfStyle(font->style, sc);
-
-
- for (i = 0; i < num_glyphs; i++)
- {
- GlyphID theGlyph = glyphs[i].index;
-
-
- cairo_matrix_set_affine( &info.scale,
- 1.0, 0.0,
- 0.0, 1.0,
- glyphs[i].x, glyphs[i].y);
-
-
- err = ATSUGlyphGetCubicPaths( style,
- theGlyph,
- moveProc,
- lineProc,
- curveProc,
- closePathProc,
- (void *)&info,
- &err);
- }
-
-
- err = ATSUDisposeStyle(style);
-
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-#pragma mark -
-
-
-static cairo_status_t
-_cairo_atsui_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
-{
- // TODO
- printf("_cairo_atsui_font_create_glyph is unimplemented\n");
-
- // I'm not sure if we need this, given that the ATSUI backend does no caching(?)
-
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-cairo_font_t *
-cairo_atsui_font_create(ATSUStyle style)
-{
- cairo_font_scale_t scale;
- cairo_font_t *scaled;
- cairo_atsui_font_t *f = NULL;
-
-
- scaled = malloc(sizeof(cairo_font_t));
- if (scaled == NULL)
- return NULL;
-
-
- f = malloc(sizeof(cairo_atsui_font_t));
- if (f)
- {
- if (_cairo_unscaled_font_init(&f->base, &cairo_atsui_font_backend) == CAIRO_STATUS_SUCCESS)
- {
- f->style = style;
-
- _cairo_font_init(scaled, &scale, &f->base);
-
- return scaled;
- }
- }
-
-
- free(scaled);
-
-
- return NULL;
-}
-
-
-
-
-
-#pragma mark Backend
-
-
-
-
-
-const cairo_font_backend_t cairo_atsui_font_backend = {
- _cairo_atsui_font_create,
- _cairo_atsui_font_destroy,
- _cairo_atsui_font_font_extents,
- _cairo_atsui_font_text_to_glyphs,
- _cairo_atsui_font_glyph_extents,
- _cairo_atsui_font_glyph_bbox,
- _cairo_atsui_font_show_glyphs,
- _cairo_atsui_font_glyph_path,
- _cairo_atsui_font_create_glyph
-};
diff --git a/src/cairo_cache.c b/src/cairo_cache.c
deleted file mode 100644
index d1ad5a4e2..000000000
--- a/src/cairo_cache.c
+++ /dev/null
@@ -1,518 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * This file is Copyright © 2004 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is Red Hat, Inc.
- *
- * Contributor(s):
- * Keith Packard
- * Graydon Hoare <graydon@redhat.com>
- */
-
-#include "cairoint.h"
-
-/*
- * This structure, and accompanying table, is borrowed/modified from the
- * file xserver/render/glyph.c in the freedesktop.org x server, with
- * permission (and suggested modification of doubling sizes) by Keith
- * Packard.
- */
-
-static const cairo_cache_arrangement_t cache_arrangements [] = {
- { 16, 43, 41 },
- { 32, 73, 71 },
- { 64, 151, 149 },
- { 128, 283, 281 },
- { 256, 571, 569 },
- { 512, 1153, 1151 },
- { 1024, 2269, 2267 },
- { 2048, 4519, 4517 },
- { 4096, 9013, 9011 },
- { 8192, 18043, 18041 },
- { 16384, 36109, 36107 },
- { 32768, 72091, 72089 },
- { 65536, 144409, 144407 },
- { 131072, 288361, 288359 },
- { 262144, 576883, 576881 },
- { 524288, 1153459, 1153457 },
- { 1048576, 2307163, 2307161 },
- { 2097152, 4613893, 4613891 },
- { 4194304, 9227641, 9227639 },
- { 8388608, 18455029, 18455027 },
- { 16777216, 36911011, 36911009 },
- { 33554432, 73819861, 73819859 },
- { 67108864, 147639589, 147639587 },
- { 134217728, 295279081, 295279079 },
- { 268435456, 590559793, 590559791 }
-};
-
-#define N_CACHE_SIZES (sizeof(cache_arrangements)/sizeof(cache_arrangements[0]))
-
-/*
- * Entries 'e' are poiners, in one of 3 states:
- *
- * e == NULL: The entry has never had anything put in it
- * e != DEAD_ENTRY: The entry has an active value in it currently
- * e == DEAD_ENTRY: The entry *had* a value in it at some point, but the
- * entry has been killed. Lookups requesting free space can
- * reuse these entries; lookups requesting a precise match
- * should neither return these entries nor stop searching when
- * seeing these entries.
- *
- * We expect keys will not be destroyed frequently, so our table does not
- * contain any explicit shrinking code nor any chain-coalescing code for
- * entries randomly deleted by memory pressure (except during rehashing, of
- * course). These assumptions are potentially bad, but they make the
- * implementation straightforward.
- *
- * Revisit later if evidence appears that we're using excessive memory from
- * a mostly-dead table.
- *
- * Generally you do not need to worry about freeing cache entries; the
- * cache will expire entries randomly as it experiences memory pressure.
- * If max_memory is set, entries are not expired, and must be explicitely
- * removed.
- *
- * This table is open-addressed with double hashing. Each table size is a
- * prime chosen to be a little more than double the high water mark for a
- * given arrangement, so the tables should remain < 50% full. The table
- * size makes for the "first" hash modulus; a second prime (2 less than the
- * first prime) serves as the "second" hash modulus, which is co-prime and
- * thus guarantees a complete permutation of table indices.
- *
- */
-
-#define DEAD_ENTRY ((cairo_cache_entry_base_t *) 1)
-#define NULL_ENTRY_P(cache, i) ((cache)->entries[i] == NULL)
-#define DEAD_ENTRY_P(cache, i) ((cache)->entries[i] == DEAD_ENTRY)
-#define LIVE_ENTRY_P(cache, i) \
- (!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i)))))
-
-#ifdef CAIRO_DO_SANITY_CHECKING
-static void
-_cache_sane_state (cairo_cache_t *cache)
-{
- assert (cache != NULL);
- assert (cache->entries != NULL);
- assert (cache->backend != NULL);
- assert (cache->arrangement != NULL);
- /* Cannot check this, a single object may larger */
- /* assert (cache->used_memory <= cache->max_memory); */
- assert (cache->live_entries <= cache->arrangement->size);
-}
-#else
-#define _cache_sane_state(c)
-#endif
-
-static void
-_entry_destroy (cairo_cache_t *cache, unsigned long i)
-{
- _cache_sane_state (cache);
-
- if (LIVE_ENTRY_P(cache, i))
- {
- cairo_cache_entry_base_t *entry = cache->entries[i];
- assert(cache->live_entries > 0);
- assert(cache->used_memory >= entry->memory);
-
- cache->live_entries--;
- cache->used_memory -= entry->memory;
- cache->backend->destroy_entry (cache, entry);
- cache->entries[i] = DEAD_ENTRY;
- }
-}
-
-static cairo_cache_entry_base_t **
-_cache_lookup (cairo_cache_t *cache,
- void *key,
- int (*predicate)(void*,void*,void*))
-{
-
- cairo_cache_entry_base_t **probe;
- unsigned long hash;
- unsigned long table_size, i, idx, step;
-
- _cache_sane_state (cache);
- assert (key != NULL);
-
- table_size = cache->arrangement->size;
- hash = cache->backend->hash (cache, key);
- idx = hash % table_size;
- step = 0;
-
- for (i = 0; i < table_size; ++i)
- {
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
- cache->probes++;
-#endif
- assert(idx < table_size);
- probe = cache->entries + idx;
-
- /*
- * There are two lookup modes: searching for a free slot and searching
- * for an exact entry.
- */
-
- if (predicate != NULL)
- {
- /* We are looking up an exact entry. */
- if (*probe == NULL)
- /* Found an empty spot, there can't be a match */
- break;
- else if (*probe != DEAD_ENTRY
- && (*probe)->hashcode == hash
- && predicate (cache, key, *probe))
- return probe;
- }
- else
- {
- /* We are just looking for a free slot. */
- if (*probe == NULL
- || *probe == DEAD_ENTRY)
- return probe;
- }
-
- if (step == 0) {
- step = hash % cache->arrangement->rehash;
- if (step == 0)
- step = 1;
- }
-
- idx += step;
- if (idx >= table_size)
- idx -= table_size;
- }
-
- /*
- * The table should not have permitted you to get here if you were just
- * looking for a free slot: there should have been room.
- */
- assert(predicate != NULL);
- return NULL;
-}
-
-static cairo_cache_entry_base_t **
-_find_available_entry_for (cairo_cache_t *cache,
- void *key)
-{
- return _cache_lookup (cache, key, NULL);
-}
-
-static cairo_cache_entry_base_t **
-_find_exact_live_entry_for (cairo_cache_t *cache,
- void *key)
-{
- return _cache_lookup (cache, key, cache->backend->keys_equal);
-}
-
-static const cairo_cache_arrangement_t *
-_find_cache_arrangement (unsigned long proposed_size)
-{
- unsigned long idx;
-
- for (idx = 0; idx < N_CACHE_SIZES; ++idx)
- if (cache_arrangements[idx].high_water_mark >= proposed_size)
- return &cache_arrangements[idx];
- return NULL;
-}
-
-static cairo_status_t
-_resize_cache (cairo_cache_t *cache, unsigned long proposed_size)
-{
- cairo_cache_t tmp;
- cairo_cache_entry_base_t **e;
- unsigned long new_size, i;
-
- tmp = *cache;
- tmp.arrangement = _find_cache_arrangement (proposed_size);
- assert(tmp.arrangement != NULL);
- if (tmp.arrangement == cache->arrangement)
- return CAIRO_STATUS_SUCCESS;
-
- new_size = tmp.arrangement->size;
- tmp.entries = calloc (new_size, sizeof (cairo_cache_entry_base_t *));
- if (tmp.entries == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- for (i = 0; i < cache->arrangement->size; ++i) {
- if (LIVE_ENTRY_P(cache, i)) {
- e = _find_available_entry_for (&tmp, cache->entries[i]);
- assert (e != NULL);
- *e = cache->entries[i];
- }
- }
- free (cache->entries);
- cache->entries = tmp.entries;
- cache->arrangement = tmp.arrangement;
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
-static double
-_load_factor (cairo_cache_t *cache)
-{
- return ((double) cache->live_entries)
- / ((double) cache->arrangement->size);
-}
-#endif
-
-/* Find a random in the cache matching the given predicate. We use the
- * same algorithm as the probing algorithm to walk over the entries in
- * the hash table in a pseudo-random order. Walking linearly would
- * favor entries following gaps in the hash table. We could also
- * call rand() repeatedly, which works well for almost-full tables,
- * but degrades when the table is almost empty, or predicate
- * returns false for most entries.
- */
-static cairo_cache_entry_base_t **
-_random_entry (cairo_cache_t *cache,
- int (*predicate)(void*))
-{
- cairo_cache_entry_base_t **probe;
- unsigned long hash;
- unsigned long table_size, i, idx, step;
-
- _cache_sane_state (cache);
-
- table_size = cache->arrangement->size;
- hash = rand ();
- idx = hash % table_size;
- step = 0;
-
- for (i = 0; i < table_size; ++i)
- {
- assert(idx < table_size);
- probe = cache->entries + idx;
-
- if (LIVE_ENTRY_P(cache, idx)
- && (!predicate || predicate (*probe)))
- return probe;
-
- if (step == 0) {
- step = hash % cache->arrangement->rehash;
- if (step == 0)
- step = 1;
- }
-
- idx += step;
- if (idx >= table_size)
- idx -= table_size;
- }
-
- return NULL;
-}
-
-/* public API follows */
-
-cairo_status_t
-_cairo_cache_init (cairo_cache_t *cache,
- const cairo_cache_backend_t *backend,
- unsigned long max_memory)
-{
- assert (backend != NULL);
-
- if (cache != NULL){
- cache->arrangement = &cache_arrangements[0];
- cache->refcount = 1;
- cache->max_memory = max_memory;
- cache->used_memory = 0;
- cache->live_entries = 0;
-
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
- cache->hits = 0;
- cache->misses = 0;
- cache->probes = 0;
-#endif
-
- cache->backend = backend;
- cache->entries = calloc (sizeof(cairo_cache_entry_base_t *),
- cache->arrangement->size);
- if (cache->entries == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- }
- _cache_sane_state (cache);
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_cache_reference (cairo_cache_t *cache)
-{
- _cache_sane_state (cache);
- cache->refcount++;
-}
-
-void
-_cairo_cache_destroy (cairo_cache_t *cache)
-{
- unsigned long i;
- if (cache != NULL) {
-
- _cache_sane_state (cache);
-
- if (--cache->refcount > 0)
- return;
-
- for (i = 0; i < cache->arrangement->size; ++i) {
- _entry_destroy (cache, i);
- }
-
- free (cache->entries);
- cache->entries = NULL;
- cache->backend->destroy_cache (cache);
- }
-}
-
-cairo_status_t
-_cairo_cache_lookup (cairo_cache_t *cache,
- void *key,
- void **entry_return,
- int *created_entry)
-{
-
- unsigned long idx;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_cache_entry_base_t **slot = NULL, *new_entry;
-
- _cache_sane_state (cache);
-
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
- if ((cache->hits + cache->misses) % 0xffff == 0)
- printf("cache %p stats: size %ld, live %ld, load %.2f\n"
- " mem %ld/%ld, hit %ld, miss %ld\n"
- " probe %ld, %.2f probe/access\n",
- cache,
- cache->arrangement->size,
- cache->live_entries,
- _load_factor (cache),
- cache->used_memory,
- cache->max_memory,
- cache->hits,
- cache->misses,
- cache->probes,
- ((double) cache->probes)
- / ((double) (cache->hits +
- cache->misses + 1)));
-#endif
-
- /* See if we have an entry in the table already. */
- slot = _find_exact_live_entry_for (cache, key);
- if (slot != NULL) {
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
- cache->hits++;
-#endif
- *entry_return = *slot;
- if (created_entry)
- *created_entry = 0;
- return status;
- }
-
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
- cache->misses++;
-#endif
-
- /* Build the new entry. */
- status = cache->backend->create_entry (cache, key,
- (void **)&new_entry);
- if (status != CAIRO_STATUS_SUCCESS)
- return status;
-
- /* Store the hash value in case the backend forgot. */
- new_entry->hashcode = cache->backend->hash (cache, key);
-
- /* Make some entries die if we're under memory pressure. */
- while (cache->live_entries > 0 &&
- cache->max_memory > 0 &&
- ((cache->max_memory - cache->used_memory) < new_entry->memory)) {
- idx = _random_entry (cache, NULL) - cache->entries;
- assert (idx < cache->arrangement->size);
- _entry_destroy (cache, idx);
- }
-
- /* Can't assert this; new_entry->memory may be larger than max_memory */
- /* assert(cache->max_memory >= (cache->used_memory + new_entry->memory)); */
-
- /* Make room in the table for a new slot. */
- status = _resize_cache (cache, cache->live_entries + 1);
- if (status != CAIRO_STATUS_SUCCESS) {
- cache->backend->destroy_entry (cache, new_entry);
- return status;
- }
-
- slot = _find_available_entry_for (cache, key);
- assert(slot != NULL);
-
- /* Store entry in slot and increment statistics. */
- *slot = new_entry;
- cache->live_entries++;
- cache->used_memory += new_entry->memory;
-
- _cache_sane_state (cache);
-
- *entry_return = new_entry;
- if (created_entry)
- *created_entry = 1;
-
- return status;
-}
-
-cairo_status_t
-_cairo_cache_remove (cairo_cache_t *cache,
- void *key)
-{
- cairo_cache_entry_base_t **slot;
-
- _cache_sane_state (cache);
-
- /* See if we have an entry in the table already. */
- slot = _find_exact_live_entry_for (cache, key);
- if (slot != NULL)
- _entry_destroy (cache, slot - cache->entries);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void *
-_cairo_cache_random_entry (cairo_cache_t *cache,
- int (*predicate)(void*))
-{
- cairo_cache_entry_base_t **slot = _random_entry (cache, predicate);
-
- return slot ? *slot : NULL;
-}
-
-unsigned long
-_cairo_hash_string (const char *c)
-{
- /* This is the djb2 hash. */
- unsigned long hash = 5381;
- while (*c)
- hash = ((hash << 5) + hash) + *c++;
- return hash;
-}
-
diff --git a/src/cairo_font.c b/src/cairo_font.c
deleted file mode 100644
index 529c1c7c3..000000000
--- a/src/cairo_font.c
+++ /dev/null
@@ -1,476 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2002 University of Southern California
- * Copyright © 2005 Red Hat Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- * Graydon Hoare <graydon@redhat.com>
- * Owen Taylor <otaylor@redhat.com>
- */
-
-#include "cairoint.h"
-
-/* Now the internal "unscaled + scale" font API */
-
-cairo_private cairo_status_t
-_cairo_font_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight,
- cairo_font_scale_t *sc,
- cairo_font_t **font)
-{
- const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
-
- return backend->create (family, slant, weight, sc, font);
-}
-
-void
-_cairo_font_init (cairo_font_t *font,
- cairo_font_scale_t *scale,
- const cairo_font_backend_t *backend)
-{
- font->scale = *scale;
- font->refcount = 1;
- font->backend = backend;
-}
-
-void
-_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
- const cairo_font_backend_t *backend)
-{
- font->refcount = 1;
- font->backend = backend;
-}
-
-cairo_status_t
-_cairo_font_text_to_glyphs (cairo_font_t *font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs)
-{
- return font->backend->text_to_glyphs (font, utf8, glyphs, num_glyphs);
-}
-
-cairo_status_t
-_cairo_font_glyph_extents (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
-{
- return font->backend->glyph_extents(font, glyphs, num_glyphs, extents);
-}
-
-
-cairo_status_t
-_cairo_font_glyph_bbox (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox)
-{
- return font->backend->glyph_bbox (font, glyphs, num_glyphs, bbox);
-}
-
-cairo_status_t
-_cairo_font_show_glyphs (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_status_t status;
- if (surface->backend->show_glyphs != NULL) {
- status = surface->backend->show_glyphs (font, operator, pattern,
- surface,
- source_x, source_y,
- dest_x, dest_y,
- width, height,
- glyphs, num_glyphs);
- if (status == CAIRO_STATUS_SUCCESS)
- return status;
- }
-
- /* Surface display routine either does not exist or failed. */
- return font->backend->show_glyphs (font, operator, pattern,
- surface,
- source_x, source_y,
- dest_x, dest_y,
- width, height,
- glyphs, num_glyphs);
-}
-
-cairo_status_t
-_cairo_font_glyph_path (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path)
-{
- return font->backend->glyph_path (font, glyphs, num_glyphs, path);
-}
-
-void
-_cairo_font_get_glyph_cache_key (cairo_font_t *font,
- cairo_glyph_cache_key_t *key)
-{
- font->backend->get_glyph_cache_key (font, key);
-}
-
-cairo_status_t
-_cairo_font_font_extents (cairo_font_t *font,
- cairo_font_extents_t *extents)
-{
- return font->backend->font_extents (font, extents);
-}
-
-void
-_cairo_unscaled_font_reference (cairo_unscaled_font_t *font)
-{
- font->refcount++;
-}
-
-void
-_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font)
-{
- if (--(font->refcount) > 0)
- return;
-
- font->backend->destroy_unscaled_font (font);
-}
-
-
-
-/* Public font API follows. */
-
-void
-cairo_font_reference (cairo_font_t *font)
-{
- font->refcount++;
-}
-
-void
-cairo_font_destroy (cairo_font_t *font)
-{
- if (--(font->refcount) > 0)
- return;
-
- font->backend->destroy_font (font);
-}
-
-/**
- * cairo_font_extents:
- * @font: a #cairo_font_t
- * @font_matrix: the font transformation for which this font was
- * created. (See cairo_transform_font()). This is needed
- * properly convert the metrics from the font into user space.
- * @extents: a #cairo_font_extents_t which to store the retrieved extents.
- *
- * Gets the metrics for a #cairo_font_t.
- *
- * Return value: %CAIRO_STATUS_SUCCESS on success. Otherwise, an
- * error such as %CAIRO_STATUS_NO_MEMORY.
- **/
-cairo_status_t
-cairo_font_extents (cairo_font_t *font,
- cairo_matrix_t *font_matrix,
- cairo_font_extents_t *extents)
-{
- cairo_int_status_t status;
- double font_scale_x, font_scale_y;
-
- status = _cairo_font_font_extents (font, extents);
-
- if (!CAIRO_OK (status))
- return status;
-
- _cairo_matrix_compute_scale_factors (font_matrix,
- &font_scale_x, &font_scale_y,
- /* XXX */ 1);
-
- /*
- * The font responded in unscaled units, scale by the font
- * matrix scale factors to get to user space
- */
-
- extents->ascent *= font_scale_y;
- extents->descent *= font_scale_y;
- extents->height *= font_scale_y;
- extents->max_x_advance *= font_scale_x;
- extents->max_y_advance *= font_scale_y;
-
- return status;
-}
-
-/**
- * cairo_font_glyph_extents:
- * @font: a #cairo_font_t
- * @font_matrix: the font transformation for which this font was
- * created. (See cairo_transform_font()). This is needed
- * properly convert the metrics from the font into user space.
- * @glyphs: an array of glyph IDs with X and Y offsets.
- * @num_glyphs: the number of glyphs in the @glyphs array
- * @extents: a #cairo_text_extents_t which to store the retrieved extents.
- *
- * cairo_font_glyph_extents() gets the overall metrics for a string of
- * glyphs. The X and Y offsets in @glyphs are taken from an origin of 0,0.
- **/
-void
-cairo_font_glyph_extents (cairo_font_t *font,
- cairo_matrix_t *font_matrix,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_glyph_t origin_glyph;
- cairo_text_extents_t origin_extents;
- int i;
- double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
- double x_pos = 0.0, y_pos = 0.0;
- int set = 0;
-
- if (!num_glyphs)
- {
- extents->x_bearing = 0.0;
- extents->y_bearing = 0.0;
- extents->width = 0.0;
- extents->height = 0.0;
- extents->x_advance = 0.0;
- extents->y_advance = 0.0;
-
- return;
- }
-
- for (i = 0; i < num_glyphs; i++)
- {
- double x, y;
- double wm, hm;
-
- origin_glyph = glyphs[i];
- origin_glyph.x = 0.0;
- origin_glyph.y = 0.0;
- status = _cairo_font_glyph_extents (font,
- &origin_glyph, 1,
- &origin_extents);
-
- /*
- * Transform font space metrics into user space metrics
- * by running the corners through the font matrix and
- * expanding the bounding box as necessary
- */
- x = origin_extents.x_bearing;
- y = origin_extents.y_bearing;
- cairo_matrix_transform_point (font_matrix,
- &x, &y);
-
- for (hm = 0.0; hm <= 1.0; hm += 1.0)
- for (wm = 0.0; wm <= 1.0; wm += 1.0)
- {
- x = origin_extents.x_bearing + origin_extents.width * wm;
- y = origin_extents.y_bearing + origin_extents.height * hm;
- cairo_matrix_transform_point (font_matrix,
- &x, &y);
- x += glyphs[i].x;
- y += glyphs[i].y;
- if (!set)
- {
- min_x = max_x = x;
- min_y = max_y = y;
- set = 1;
- }
- else
- {
- if (x < min_x) min_x = x;
- if (x > max_x) max_x = x;
- if (y < min_y) min_y = y;
- if (y > max_y) max_y = y;
- }
- }
-
- x = origin_extents.x_advance;
- y = origin_extents.y_advance;
- cairo_matrix_transform_point (font_matrix,
- &x, &y);
- x_pos = glyphs[i].x + x;
- y_pos = glyphs[i].y + y;
- }
-
- extents->x_bearing = min_x - glyphs[0].x;
- extents->y_bearing = min_y - glyphs[0].y;
- extents->width = max_x - min_x;
- extents->height = max_y - min_y;
- extents->x_advance = x_pos - glyphs[0].x;
- extents->y_advance = y_pos - glyphs[0].y;
-}
-
-/* Now we implement functions to access a default global image & metrics
- * cache.
- */
-
-unsigned long
-_cairo_glyph_cache_hash (void *cache, void *key)
-{
- cairo_glyph_cache_key_t *in;
- in = (cairo_glyph_cache_key_t *) key;
- return
- ((unsigned long) in->unscaled)
- ^ ((unsigned long) in->scale.matrix[0][0])
- ^ ((unsigned long) in->scale.matrix[0][1])
- ^ ((unsigned long) in->scale.matrix[1][0])
- ^ ((unsigned long) in->scale.matrix[1][1])
- ^ (in->flags * 1451) /* 1451 is just an abitrary prime */
- ^ in->index;
-}
-
-int
-_cairo_glyph_cache_keys_equal (void *cache,
- void *k1,
- void *k2)
-{
- cairo_glyph_cache_key_t *a, *b;
- a = (cairo_glyph_cache_key_t *) k1;
- b = (cairo_glyph_cache_key_t *) k2;
- return (a->index == b->index)
- && (a->unscaled == b->unscaled)
- && (a->flags == b->flags)
- && (a->scale.matrix[0][0] == b->scale.matrix[0][0])
- && (a->scale.matrix[0][1] == b->scale.matrix[0][1])
- && (a->scale.matrix[1][0] == b->scale.matrix[1][0])
- && (a->scale.matrix[1][1] == b->scale.matrix[1][1]);
-}
-
-
-static cairo_status_t
-_image_glyph_cache_create_entry (void *cache,
- void *key,
- void **return_value)
-{
- cairo_glyph_cache_key_t *k = (cairo_glyph_cache_key_t *) key;
- cairo_image_glyph_cache_entry_t *im;
- cairo_status_t status;
-
- im = calloc (1, sizeof (cairo_image_glyph_cache_entry_t));
- if (im == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- im->key = *k;
- status = im->key.unscaled->backend->create_glyph (im);
-
- if (status != CAIRO_STATUS_SUCCESS) {
- free (im);
- return status;
- }
-
- _cairo_unscaled_font_reference (im->key.unscaled);
-
- im->key.base.memory =
- sizeof (cairo_image_glyph_cache_entry_t)
- + (im->image ?
- sizeof (cairo_image_surface_t)
- + 28 * sizeof (int) /* rough guess at size of pixman image structure */
- + (im->image->height * im->image->stride) : 0);
-
- *return_value = im;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-static void
-_image_glyph_cache_destroy_entry (void *cache,
- void *value)
-{
- cairo_image_glyph_cache_entry_t *im;
-
- im = (cairo_image_glyph_cache_entry_t *) value;
- _cairo_unscaled_font_destroy (im->key.unscaled);
- cairo_surface_destroy (&(im->image->base));
- free (im);
-}
-
-static void
-_image_glyph_cache_destroy_cache (void *cache)
-{
- free (cache);
-}
-
-static const cairo_cache_backend_t cairo_image_cache_backend = {
- _cairo_glyph_cache_hash,
- _cairo_glyph_cache_keys_equal,
- _image_glyph_cache_create_entry,
- _image_glyph_cache_destroy_entry,
- _image_glyph_cache_destroy_cache
-};
-
-void
-_cairo_lock_global_image_glyph_cache()
-{
- /* FIXME: implement locking. */
-}
-
-void
-_cairo_unlock_global_image_glyph_cache()
-{
- /* FIXME: implement locking. */
-}
-
-static cairo_cache_t *
-_global_image_glyph_cache = NULL;
-
-cairo_cache_t *
-_cairo_get_global_image_glyph_cache ()
-{
- if (_global_image_glyph_cache == NULL) {
- _global_image_glyph_cache = malloc (sizeof (cairo_cache_t));
-
- if (_global_image_glyph_cache == NULL)
- goto FAIL;
-
- if (_cairo_cache_init (_global_image_glyph_cache,
- &cairo_image_cache_backend,
- CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT))
- goto FAIL;
- }
-
- return _global_image_glyph_cache;
-
- FAIL:
- if (_global_image_glyph_cache)
- free (_global_image_glyph_cache);
- _global_image_glyph_cache = NULL;
- return NULL;
-}
diff --git a/src/cairo_ft_font.c b/src/cairo_ft_font.c
deleted file mode 100644
index 44e1b0e84..000000000
--- a/src/cairo_ft_font.c
+++ /dev/null
@@ -1,1538 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2005 Red Hat, Inc
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is Red Hat, Inc.
- *
- * Contributor(s):
- * Graydon Hoare <graydon@redhat.com>
- * Owen Taylor <otaylor@redhat.com>
- */
-
-#include "cairo-ft-private.h"
-
-#include <fontconfig/fontconfig.h>
-#include <fontconfig/fcfreetype.h>
-
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_OUTLINE_H
-#include FT_IMAGE_H
-
-#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0))
-#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0)
-#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0))
-#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0)
-
-/* This is the max number of FT_face objects we keep open at once
- */
-#define MAX_OPEN_FACES 10
-
-/*
- * The simple 2x2 matrix is converted into separate scale and shape
- * factors so that hinting works right
- */
-
-typedef struct {
- double x_scale, y_scale;
- double shape[2][2];
-} ft_font_transform_t;
-
-/*
- * We create an object that corresponds to a single font on the disk;
- * (identified by a filename/id pair) these are shared between all
- * fonts using that file. For cairo_ft_font_create_for_ft_face(), we
- * just create a one-off version with a permanent face value.
- */
-
-typedef struct {
- cairo_unscaled_font_t base;
-
- int from_face; /* from cairo_ft_font_create_for_ft_face()? */
- FT_Face face; /* provided or cached face */
-
- /* only set if from_face is false */
- FT_Library library;
- char *filename;
- int id;
-
- /* We temporarily scale the unscaled font as neede */
- int have_scale;
- cairo_font_scale_t current_scale;
- double x_scale; /* Extracted X scale factor */
- double y_scale; /* Extracted Y scale factor */
-
- int lock; /* count of how many times this font has been locked */
-} ft_unscaled_font_t;
-
-const cairo_font_backend_t cairo_ft_font_backend;
-
-static ft_unscaled_font_t *
-_ft_unscaled_font_create_from_face (FT_Face face)
-{
- ft_unscaled_font_t *unscaled = malloc (sizeof(ft_unscaled_font_t));
- if (!unscaled)
- return NULL;
-
- unscaled->from_face = 1;
- unscaled->face = face;
-
- unscaled->library = NULL;
- unscaled->filename = NULL;
- unscaled->id = 0;
-
- unscaled->have_scale = 0;
- unscaled->lock = 0;
-
- _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled,
- &cairo_ft_font_backend);
- return unscaled;
-}
-
-static ft_unscaled_font_t *
-_ft_unscaled_font_create_from_filename (FT_Library library,
- const char *filename,
- int id)
-{
- ft_unscaled_font_t *unscaled;
- char *new_filename;
-
- new_filename = strdup (filename);
- if (!new_filename)
- return NULL;
-
- unscaled = malloc (sizeof (ft_unscaled_font_t));
- if (!unscaled) {
- free (new_filename);
- return NULL;
- }
-
- unscaled->from_face = 0;
- unscaled->face = NULL;
-
- unscaled->library = library;
- unscaled->filename = new_filename;
- unscaled->id = id;
-
- unscaled->have_scale = 0;
- unscaled->lock = 0;
-
- _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled,
- &cairo_ft_font_backend);
- return unscaled;
-}
-
-/*
- * We keep a global cache from [file/id] => [ft_unscaled_font_t]. This
- * hash isn't limited in size. However, we limit the number of
- * FT_Face objects we keep around; when we've exceeeded that
- * limit and need to create a new FT_Face, we dump the FT_Face from
- * a random ft_unscaled_font_t.
- */
-
-typedef struct {
- cairo_cache_entry_base_t base;
- char *filename;
- int id;
-} cairo_ft_cache_key_t;
-
-typedef struct {
- cairo_ft_cache_key_t key;
- ft_unscaled_font_t *unscaled;
-} cairo_ft_cache_entry_t;
-
-typedef struct {
- cairo_cache_t base;
- FT_Library lib;
- int n_faces; /* Number of open FT_Face objects */
-} ft_cache_t;
-
-static unsigned long
-_ft_font_cache_hash (void *cache, void *key)
-{
- cairo_ft_cache_key_t *in = (cairo_ft_cache_key_t *) key;
- unsigned long hash;
-
- /* 1607 is just a random prime. */
- hash = _cairo_hash_string (in->filename);
- hash += ((unsigned long) in->id) * 1607;
-
- return hash;
-}
-
-static int
-_ft_font_cache_keys_equal (void *cache,
- void *k1,
- void *k2)
-{
- cairo_ft_cache_key_t *a;
- cairo_ft_cache_key_t *b;
- a = (cairo_ft_cache_key_t *) k1;
- b = (cairo_ft_cache_key_t *) k2;
-
- return strcmp (a->filename, b->filename) == 0 &&
- a->id == b->id;
-}
-
-static cairo_status_t
-_ft_font_cache_create_entry (void *cache,
- void *key,
- void **return_entry)
-{
- ft_cache_t *ftcache = (ft_cache_t *) cache;
- cairo_ft_cache_key_t *k = (cairo_ft_cache_key_t *) key;
- cairo_ft_cache_entry_t *entry;
-
- entry = malloc (sizeof (cairo_ft_cache_entry_t));
- if (entry == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- entry->unscaled = _ft_unscaled_font_create_from_filename (ftcache->lib,
- k->filename,
- k->id);
- if (!entry->unscaled) {
- free (entry);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- entry->key.base.memory = 0;
- entry->key.filename = entry->unscaled->filename;
- entry->key.id = entry->unscaled->id;
-
- *return_entry = entry;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* Entries are never spontaneously destroyed; but only when
- * we remove them from the cache specifically. We free entry->unscaled
- * in the code that removes the entry from the cache
- */
-static void
-_ft_font_cache_destroy_entry (void *cache,
- void *entry)
-{
- cairo_ft_cache_entry_t *e = (cairo_ft_cache_entry_t *) entry;
-
- free (e);
-}
-
-static void
-_ft_font_cache_destroy_cache (void *cache)
-{
- ft_cache_t *fc = (ft_cache_t *) cache;
- FT_Done_FreeType (fc->lib);
- free (fc);
-}
-
-static const cairo_cache_backend_t _ft_font_cache_backend = {
- _ft_font_cache_hash,
- _ft_font_cache_keys_equal,
- _ft_font_cache_create_entry,
- _ft_font_cache_destroy_entry,
- _ft_font_cache_destroy_cache
-};
-
-static ft_cache_t *_global_ft_cache = NULL;
-
-static void
-_lock_global_ft_cache (void)
-{
- /* FIXME: Perform locking here. */
-}
-
-static void
-_unlock_global_ft_cache (void)
-{
- /* FIXME: Perform locking here. */
-}
-
-static cairo_cache_t *
-_get_global_ft_cache (void)
-{
- if (_global_ft_cache == NULL)
- {
- _global_ft_cache = malloc (sizeof(ft_cache_t));
- if (!_global_ft_cache)
- goto FAIL;
-
- if (_cairo_cache_init (&_global_ft_cache->base,
- &_ft_font_cache_backend,
- 0)) /* No memory limit */
- goto FAIL;
-
- if (FT_Init_FreeType (&_global_ft_cache->lib))
- goto FAIL;
- _global_ft_cache->n_faces = 0;
- }
- return &_global_ft_cache->base;
-
- FAIL:
- if (_global_ft_cache)
- free (_global_ft_cache);
- _global_ft_cache = NULL;
- return NULL;
-}
-
-/* Finds or creates a ft_unscaled_font for the filename/id from pattern.
- * Returns a new reference to the unscaled font.
- */
-static ft_unscaled_font_t *
-_ft_unscaled_font_get_for_pattern (FcPattern *pattern)
-{
- cairo_ft_cache_entry_t *entry;
- cairo_ft_cache_key_t key;
- cairo_cache_t *cache;
- cairo_status_t status;
- FcChar8 *filename;
- int created_entry;
-
- if (FcPatternGetString (pattern, FC_FILE, 0, &filename) != FcResultMatch)
- return NULL;
- key.filename = (char *)filename;
-
- if (FcPatternGetInteger (pattern, FC_INDEX, 0, &key.id) != FcResultMatch)
- return NULL;
-
- _lock_global_ft_cache ();
- cache = _get_global_ft_cache ();
- if (cache == NULL) {
- _unlock_global_ft_cache ();
- return NULL;
- }
-
- status = _cairo_cache_lookup (cache, &key, (void **) &entry, &created_entry);
- _unlock_global_ft_cache ();
- if (status)
- return NULL;
-
- if (!created_entry)
- _cairo_unscaled_font_reference ((cairo_unscaled_font_t *)entry->unscaled);
-
- return entry->unscaled;
-}
-
-static int
-_has_unlocked_face (void *entry)
-{
- cairo_ft_cache_entry_t *e = entry;
-
- return (e->unscaled->lock == 0 && e->unscaled->face);
-}
-
-/* Ensures that an unscaled font has a face object. If we exceed
- * MAX_OPEN_FACES, try to close some.
- */
-static FT_Face
-_ft_unscaled_font_lock_face (ft_unscaled_font_t *unscaled)
-{
- ft_cache_t *ftcache;
- FT_Face face = NULL;
-
- if (unscaled->face) {
- unscaled->lock++;
- return unscaled->face;
- }
-
- assert (!unscaled->from_face);
-
- _lock_global_ft_cache ();
- ftcache = (ft_cache_t *) _get_global_ft_cache ();
- assert (ftcache != NULL);
-
- while (ftcache->n_faces >= MAX_OPEN_FACES) {
- cairo_ft_cache_entry_t *entry;
-
- entry = _cairo_cache_random_entry ((cairo_cache_t *)ftcache, _has_unlocked_face);
- if (entry) {
- FT_Done_Face (entry->unscaled->face);
- entry->unscaled->face = NULL;
- entry->unscaled->have_scale = 0;
- ftcache->n_faces--;
- } else {
- break;
- }
- }
-
- if (FT_New_Face (ftcache->lib,
- unscaled->filename,
- unscaled->id,
- &face) != FT_Err_Ok)
- goto FAIL;
-
- unscaled->face = face;
- unscaled->lock++;
- ftcache->n_faces++;
-
- FAIL:
- _unlock_global_ft_cache ();
- return face;
-}
-
-/* Unlock unscaled font locked with _ft_unscaled_font_lock_face
- */
-static void
-_ft_unscaled_font_unlock_face (ft_unscaled_font_t *unscaled)
-{
- assert (unscaled->lock > 0);
-
- unscaled->lock--;
-}
-
-static void
-_compute_transform (ft_font_transform_t *sf,
- cairo_font_scale_t *sc)
-{
- cairo_matrix_t normalized;
- double tx, ty;
-
- /* The font matrix has x and y "scale" components which we extract and
- * use as character scale values. These influence the way freetype
- * chooses hints, as well as selecting different bitmaps in
- * hand-rendered fonts. We also copy the normalized matrix to
- * freetype's transformation.
- */
-
- cairo_matrix_set_affine (&normalized,
- sc->matrix[0][0],
- sc->matrix[0][1],
- sc->matrix[1][0],
- sc->matrix[1][1],
- 0, 0);
-
- _cairo_matrix_compute_scale_factors (&normalized,
- &sf->x_scale, &sf->y_scale,
- /* XXX */ 1);
- cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale);
- cairo_matrix_get_affine (&normalized,
- &sf->shape[0][0], &sf->shape[0][1],
- &sf->shape[1][0], &sf->shape[1][1],
- &tx, &ty);
-}
-
-/* Temporarily scales an unscaled font to the give scale. We catch
- * scaling to the same size, since changing a FT_Face is expensive.
- */
-static void
-_ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled,
- cairo_font_scale_t *scale)
-{
- ft_font_transform_t sf;
- FT_Matrix mat;
-
- assert (unscaled->face != NULL);
-
- if (unscaled->have_scale &&
- scale->matrix[0][0] == unscaled->current_scale.matrix[0][0] &&
- scale->matrix[0][1] == unscaled->current_scale.matrix[0][1] &&
- scale->matrix[1][0] == unscaled->current_scale.matrix[1][0] &&
- scale->matrix[1][1] == unscaled->current_scale.matrix[1][1])
- return;
-
- unscaled->have_scale = 1;
- unscaled->current_scale = *scale;
-
- _compute_transform (&sf, scale);
-
- unscaled->x_scale = sf.x_scale;
- unscaled->y_scale = sf.y_scale;
-
- mat.xx = DOUBLE_TO_16_16(sf.shape[0][0]);
- mat.yx = - DOUBLE_TO_16_16(sf.shape[0][1]);
- mat.xy = - DOUBLE_TO_16_16(sf.shape[1][0]);
- mat.yy = DOUBLE_TO_16_16(sf.shape[1][1]);
-
- FT_Set_Transform(unscaled->face, &mat, NULL);
-
- FT_Set_Pixel_Sizes(unscaled->face,
- (FT_UInt) sf.x_scale,
- (FT_UInt) sf.y_scale);
-}
-
-/* implement the font backend interface */
-
-typedef struct {
- cairo_font_t base;
- FcPattern *pattern;
- int load_flags;
- ft_unscaled_font_t *unscaled;
-} cairo_ft_font_t;
-
-/* for compatibility with older freetype versions */
-#ifndef FT_LOAD_TARGET_MONO
-#define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME
-#endif
-
-/* The load flags passed to FT_Load_Glyph control aspects like hinting and
- * antialiasing. Here we compute them from the fields of a FcPattern.
- */
-static int
-_get_load_flags (FcPattern *pattern)
-{
- FcBool antialias, hinting, autohint;
-#ifdef FC_HINT_STYLE
- int hintstyle;
-#endif
- int load_flags = 0;
-
- /* disable antialiasing if requested */
- if (FcPatternGetBool (pattern,
- FC_ANTIALIAS, 0, &antialias) != FcResultMatch)
- antialias = FcTrue;
-
- if (antialias)
- load_flags |= FT_LOAD_NO_BITMAP;
- else
- load_flags |= FT_LOAD_TARGET_MONO;
-
- /* disable hinting if requested */
- if (FcPatternGetBool (pattern,
- FC_HINTING, 0, &hinting) != FcResultMatch)
- hinting = FcTrue;
-
-#ifdef FC_HINT_STYLE
- if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch)
- hintstyle = FC_HINT_FULL;
-
- if (!hinting || hintstyle == FC_HINT_NONE)
- load_flags |= FT_LOAD_NO_HINTING;
-
- switch (hintstyle) {
- case FC_HINT_SLIGHT:
- case FC_HINT_MEDIUM:
- load_flags |= FT_LOAD_TARGET_LIGHT;
- break;
- default:
- load_flags |= FT_LOAD_TARGET_NORMAL;
- break;
- }
-#else /* !FC_HINT_STYLE */
- if (!hinting)
- load_flags |= FT_LOAD_NO_HINTING;
-#endif /* FC_FHINT_STYLE */
-
- /* force autohinting if requested */
- if (FcPatternGetBool (pattern,
- FC_AUTOHINT, 0, &autohint) != FcResultMatch)
- autohint = FcFalse;
-
- if (autohint)
- load_flags |= FT_LOAD_FORCE_AUTOHINT;
-
- return load_flags;
-}
-
-/* Like the public cairo_ft_font_create, but takes a cairo_font_scale_t,
- * rather than a cairo_font_t
- */
-static cairo_font_t *
-_ft_font_create (FcPattern *pattern,
- cairo_font_scale_t *scale)
-{
- cairo_ft_font_t *f = NULL;
- ft_unscaled_font_t *unscaled = NULL;
-
- unscaled = _ft_unscaled_font_get_for_pattern (pattern);
- if (unscaled == NULL)
- return NULL;
-
- f = malloc (sizeof(cairo_ft_font_t));
- if (f == NULL)
- goto FREE_UNSCALED;
-
- f->unscaled = unscaled;
- f->pattern = pattern;
- FcPatternReference (pattern);
- f->load_flags = _get_load_flags (pattern);
-
- _cairo_font_init ((cairo_font_t *)f, scale, &cairo_ft_font_backend);
-
- return (cairo_font_t *)f;
-
- FREE_UNSCALED:
- _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled);
-
- return NULL;
-}
-
-static cairo_status_t
-_cairo_ft_font_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight,
- cairo_font_scale_t *scale,
- cairo_font_t **font)
-{
- FcPattern *pattern, *resolved;
- cairo_font_t *new_font;
- FcResult result;
- int fcslant;
- int fcweight;
- ft_font_transform_t sf;
-
- pattern = FcPatternCreate ();
- if (!pattern)
- return CAIRO_STATUS_NO_MEMORY;
-
- switch (weight)
- {
- case CAIRO_FONT_WEIGHT_BOLD:
- fcweight = FC_WEIGHT_BOLD;
- break;
- case CAIRO_FONT_WEIGHT_NORMAL:
- default:
- fcweight = FC_WEIGHT_MEDIUM;
- break;
- }
-
- switch (slant)
- {
- case CAIRO_FONT_SLANT_ITALIC:
- fcslant = FC_SLANT_ITALIC;
- break;
- case CAIRO_FONT_SLANT_OBLIQUE:
- fcslant = FC_SLANT_OBLIQUE;
- break;
- case CAIRO_FONT_SLANT_NORMAL:
- default:
- fcslant = FC_SLANT_ROMAN;
- break;
- }
-
- if (!FcPatternAddString (pattern, FC_FAMILY, family))
- goto FREE_PATTERN;
- if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant))
- goto FREE_PATTERN;
- if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight))
- goto FREE_PATTERN;
-
- _compute_transform (&sf, scale);
-
- FcPatternAddInteger (pattern, FC_PIXEL_SIZE, sf.y_scale);
-
- FcConfigSubstitute (NULL, pattern, FcMatchPattern);
- FcDefaultSubstitute (pattern);
-
- resolved = FcFontMatch (NULL, pattern, &result);
- if (!resolved)
- goto FREE_PATTERN;
-
- new_font = _ft_font_create (resolved, scale);
-
- FcPatternDestroy (resolved);
- FcPatternDestroy (pattern);
-
- if (new_font) {
- *font = new_font;
- return CAIRO_STATUS_SUCCESS;
- } else {
- return CAIRO_STATUS_NO_MEMORY; /* A guess */
- }
-
- FREE_PATTERN:
- FcPatternDestroy (pattern);
-
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-static void
-_cairo_ft_font_destroy_font (void *abstract_font)
-{
- cairo_ft_font_t * font = abstract_font;
-
- if (font == NULL)
- return;
-
- if (font->pattern != NULL)
- FcPatternDestroy (font->pattern);
-
- _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)font->unscaled);
-
- free (font);
-}
-
-static void
-_cairo_ft_font_destroy_unscaled_font (void *abstract_font)
-{
- ft_unscaled_font_t *unscaled = abstract_font;
-
- if (!unscaled->from_face) {
- cairo_cache_t *cache;
- cairo_ft_cache_key_t key;
-
- _lock_global_ft_cache ();
- cache = _get_global_ft_cache ();
- assert (cache);
-
- key.filename = unscaled->filename;
- key.id = unscaled->id;
-
- _cairo_cache_remove (cache, &key);
-
- _unlock_global_ft_cache ();
- }
-
- if (unscaled == NULL)
- return;
-
- if (!unscaled->from_face && unscaled->face)
- FT_Done_Face (unscaled->face);
-
- if (unscaled->filename)
- free (unscaled->filename);
-
- free (unscaled);
-}
-
-static void
-_cairo_ft_font_get_glyph_cache_key (void *abstract_font,
- cairo_glyph_cache_key_t *key)
-{
- cairo_ft_font_t *font = abstract_font;
-
- key->unscaled = (cairo_unscaled_font_t *)font->unscaled;
- key->scale = font->base.scale;
- key->flags = font->load_flags;
-}
-
-static cairo_status_t
-_cairo_ft_font_text_to_glyphs (void *abstract_font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *nglyphs)
-{
- double x = 0., y = 0.;
- size_t i;
- uint32_t *ucs4 = NULL;
- cairo_ft_font_t *font = abstract_font;
- FT_Face face;
- cairo_glyph_cache_key_t key;
- cairo_image_glyph_cache_entry_t *val;
- cairo_cache_t *cache = NULL;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
- _cairo_ft_font_get_glyph_cache_key (font, &key);
-
- status = _cairo_utf8_to_ucs4 (utf8, -1, &ucs4, nglyphs);
- if (!CAIRO_OK (status))
- return status;
-
- face = cairo_ft_font_lock_face ((cairo_font_t *)font);
- if (!face) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL1;
- }
-
- _cairo_lock_global_image_glyph_cache ();
- cache = _cairo_get_global_image_glyph_cache ();
- if (cache == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL2;
- }
-
- *glyphs = (cairo_glyph_t *) malloc ((*nglyphs) * (sizeof (cairo_glyph_t)));
- if (*glyphs == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL2;
- }
-
- for (i = 0; i < *nglyphs; i++)
- {
- (*glyphs)[i].index = FT_Get_Char_Index (face, ucs4[i]);
- (*glyphs)[i].x = x;
- (*glyphs)[i].y = y;
-
- val = NULL;
- key.index = (*glyphs)[i].index;
-
- if (_cairo_cache_lookup (cache, &key, (void **) &val, NULL)
- != CAIRO_STATUS_SUCCESS || val == NULL)
- continue;
-
- x += val->extents.x_advance;
- y += val->extents.y_advance;
- }
-
- FAIL2:
- if (cache)
- _cairo_unlock_global_image_glyph_cache ();
-
- cairo_ft_font_unlock_face ((cairo_font_t *)font);
-
- FAIL1:
- free (ucs4);
-
- return status;
-}
-
-
-static cairo_status_t
-_cairo_ft_font_font_extents (void *abstract_font,
- cairo_font_extents_t *extents)
-{
- cairo_ft_font_t *font = abstract_font;
- FT_Face face;
- FT_Size_Metrics *metrics;
-
- face = _ft_unscaled_font_lock_face (font->unscaled);
- if (!face)
- return CAIRO_STATUS_NO_MEMORY;
-
- metrics = &face->size->metrics;
-
- _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale);
-
- /*
- * Get to unscaled metrics so that the upper level can get back to
- * user space
- */
- extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / font->unscaled->y_scale;
- extents->descent = DOUBLE_FROM_26_6(metrics->descender) / font->unscaled->y_scale;
- extents->height = DOUBLE_FROM_26_6(metrics->height) / font->unscaled->y_scale;
- extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / font->unscaled->x_scale;
-
- /* FIXME: this doesn't do vertical layout atm. */
- extents->max_y_advance = 0.0;
-
- _ft_unscaled_font_unlock_face (font->unscaled);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ft_font_glyph_extents (void *abstract_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
-{
- int i;
- cairo_ft_font_t *font = abstract_font;
- cairo_point_double_t origin;
- cairo_point_double_t glyph_min, glyph_max;
- cairo_point_double_t total_min, total_max;
-
- cairo_image_glyph_cache_entry_t *img = NULL;
- cairo_cache_t *cache;
- cairo_glyph_cache_key_t key;
-
- if (num_glyphs == 0)
- {
- extents->x_bearing = 0.0;
- extents->y_bearing = 0.0;
- extents->width = 0.0;
- extents->height = 0.0;
- extents->x_advance = 0.0;
- extents->y_advance = 0.0;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- origin.x = glyphs[0].x;
- origin.y = glyphs[0].y;
-
- _cairo_lock_global_image_glyph_cache ();
- cache = _cairo_get_global_image_glyph_cache ();
- if (cache == NULL) {
- _cairo_unlock_global_image_glyph_cache ();
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- _cairo_ft_font_get_glyph_cache_key (font, &key);
-
- for (i = 0; i < num_glyphs; i++)
- {
- img = NULL;
- key.index = glyphs[i].index;
- if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL)
- != CAIRO_STATUS_SUCCESS || img == NULL)
- continue;
-
- /* XXX: Need to add code here to check the font's FcPattern
- for FC_VERTICAL_LAYOUT and if set get vertBearingX/Y
- instead. This will require that
- cairo_ft_font_create_for_ft_face accept an
- FcPattern. */
- glyph_min.x = glyphs[i].x + img->extents.x_bearing;
- glyph_min.y = glyphs[i].y + img->extents.y_bearing;
- glyph_max.x = glyph_min.x + img->extents.width;
- glyph_max.y = glyph_min.y + img->extents.height;
-
- if (i==0) {
- total_min = glyph_min;
- total_max = glyph_max;
- } else {
- if (glyph_min.x < total_min.x)
- total_min.x = glyph_min.x;
- if (glyph_min.y < total_min.y)
- total_min.y = glyph_min.y;
-
- if (glyph_max.x > total_max.x)
- total_max.x = glyph_max.x;
- if (glyph_max.y > total_max.y)
- total_max.y = glyph_max.y;
- }
- }
- _cairo_unlock_global_image_glyph_cache ();
-
- extents->x_bearing = (total_min.x - origin.x);
- extents->y_bearing = (total_min.y - origin.y);
- extents->width = (total_max.x - total_min.x);
- extents->height = (total_max.y - total_min.y);
- extents->x_advance = glyphs[i-1].x + (img == NULL ? 0 : img->extents.x_advance) - origin.x;
- extents->y_advance = glyphs[i-1].y + (img == NULL ? 0 : img->extents.y_advance) - origin.y;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-static cairo_status_t
-_cairo_ft_font_glyph_bbox (void *abstract_font,
- const cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox)
-{
- cairo_image_glyph_cache_entry_t *img;
- cairo_cache_t *cache;
- cairo_glyph_cache_key_t key;
- cairo_ft_font_t *font = abstract_font;
-
- cairo_fixed_t x1, y1, x2, y2;
- int i;
-
- bbox->p1.x = bbox->p1.y = CAIRO_MAXSHORT << 16;
- bbox->p2.x = bbox->p2.y = CAIRO_MINSHORT << 16;
-
- _cairo_lock_global_image_glyph_cache ();
- cache = _cairo_get_global_image_glyph_cache();
-
- if (cache == NULL
- || font == NULL
- || glyphs == NULL) {
- _cairo_unlock_global_image_glyph_cache ();
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- _cairo_ft_font_get_glyph_cache_key (font, &key);
-
- for (i = 0; i < num_glyphs; i++)
- {
-
- img = NULL;
- key.index = glyphs[i].index;
-
- if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL)
- != CAIRO_STATUS_SUCCESS || img == NULL)
- continue;
-
- x1 = _cairo_fixed_from_double (glyphs[i].x + img->size.x);
- y1 = _cairo_fixed_from_double (glyphs[i].y + img->size.y);
- x2 = x1 + _cairo_fixed_from_double (img->size.width);
- y2 = y1 + _cairo_fixed_from_double (img->size.height);
-
- if (x1 < bbox->p1.x)
- bbox->p1.x = x1;
-
- if (y1 < bbox->p1.y)
- bbox->p1.y = y1;
-
- if (x2 > bbox->p2.x)
- bbox->p2.x = x2;
-
- if (y2 > bbox->p2.y)
- bbox->p2.y = y2;
- }
- _cairo_unlock_global_image_glyph_cache ();
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-static cairo_status_t
-_cairo_ft_font_show_glyphs (void *abstract_font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_image_glyph_cache_entry_t *img;
- cairo_cache_t *cache;
- cairo_glyph_cache_key_t key;
- cairo_ft_font_t *font = abstract_font;
- cairo_surface_pattern_t glyph_pattern;
- cairo_status_t status;
- int x, y;
- int i;
-
- _cairo_lock_global_image_glyph_cache ();
- cache = _cairo_get_global_image_glyph_cache();
-
- if (cache == NULL
- || font == NULL
- || pattern == NULL
- || surface == NULL
- || glyphs == NULL) {
- _cairo_unlock_global_image_glyph_cache ();
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- key.unscaled = (cairo_unscaled_font_t *)font->unscaled;
- key.scale = font->base.scale;
- key.flags = font->load_flags;
-
- for (i = 0; i < num_glyphs; i++)
- {
- img = NULL;
- key.index = glyphs[i].index;
-
- if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL)
- != CAIRO_STATUS_SUCCESS
- || img == NULL
- || img->image == NULL)
- continue;
-
- x = (int) floor (glyphs[i].x + 0.5);
- y = (int) floor (glyphs[i].y + 0.5);
-
- _cairo_pattern_init_for_surface (&glyph_pattern, &(img->image->base));
-
- status = _cairo_surface_composite (operator, pattern,
- &glyph_pattern.base,
- surface,
- x + img->size.x,
- y + img->size.y,
- 0, 0,
- x + img->size.x,
- y + img->size.y,
- (double) img->size.width,
- (double) img->size.height);
-
- _cairo_pattern_fini (&glyph_pattern.base);
-
- if (status) {
- _cairo_unlock_global_image_glyph_cache ();
- return status;
- }
- }
-
- _cairo_unlock_global_image_glyph_cache ();
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-static int
-_move_to (FT_Vector *to, void *closure)
-{
- cairo_path_t *path = closure;
- cairo_point_t point;
-
- point.x = _cairo_fixed_from_26_6 (to->x);
- point.y = _cairo_fixed_from_26_6 (to->y);
-
- _cairo_path_close_path (path);
- _cairo_path_move_to (path, &point);
-
- return 0;
-}
-
-static int
-_line_to (FT_Vector *to, void *closure)
-{
- cairo_path_t *path = closure;
- cairo_point_t point;
-
- point.x = _cairo_fixed_from_26_6 (to->x);
- point.y = _cairo_fixed_from_26_6 (to->y);
-
- _cairo_path_line_to (path, &point);
-
- return 0;
-}
-
-static int
-_conic_to (FT_Vector *control, FT_Vector *to, void *closure)
-{
- cairo_path_t *path = closure;
-
- cairo_point_t p0, p1, p2, p3;
- cairo_point_t conic;
-
- _cairo_path_current_point (path, &p0);
-
- conic.x = _cairo_fixed_from_26_6 (control->x);
- conic.y = _cairo_fixed_from_26_6 (control->y);
-
- p3.x = _cairo_fixed_from_26_6 (to->x);
- p3.y = _cairo_fixed_from_26_6 (to->y);
-
- p1.x = p0.x + 2.0/3.0 * (conic.x - p0.x);
- p1.y = p0.y + 2.0/3.0 * (conic.y - p0.y);
-
- p2.x = p3.x + 2.0/3.0 * (conic.x - p3.x);
- p2.y = p3.y + 2.0/3.0 * (conic.y - p3.y);
-
- _cairo_path_curve_to (path,
- &p1, &p2, &p3);
-
- return 0;
-}
-
-static int
-_cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closure)
-{
- cairo_path_t *path = closure;
- cairo_point_t p0, p1, p2;
-
- p0.x = _cairo_fixed_from_26_6 (control1->x);
- p0.y = _cairo_fixed_from_26_6 (control1->y);
-
- p1.x = _cairo_fixed_from_26_6 (control2->x);
- p1.y = _cairo_fixed_from_26_6 (control2->y);
-
- p2.x = _cairo_fixed_from_26_6 (to->x);
- p2.y = _cairo_fixed_from_26_6 (to->y);
-
- _cairo_path_curve_to (path, &p0, &p1, &p2);
-
- return 0;
-}
-
-static cairo_status_t
-_cairo_ft_font_glyph_path (void *abstract_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path)
-{
- int i;
- cairo_ft_font_t *font = abstract_font;
- FT_GlyphSlot glyph;
- FT_Face face;
- FT_Error error;
- FT_Outline_Funcs outline_funcs = {
- _move_to,
- _line_to,
- _conic_to,
- _cubic_to,
- 0, /* shift */
- 0, /* delta */
- };
-
- face = cairo_ft_font_lock_face (abstract_font);
- if (!face)
- return CAIRO_STATUS_NO_MEMORY;
-
- glyph = face->glyph;
-
- for (i = 0; i < num_glyphs; i++)
- {
- FT_Matrix invert_y = {
- DOUBLE_TO_16_16 (1.0), 0,
- 0, DOUBLE_TO_16_16 (-1.0),
- };
-
- error = FT_Load_Glyph (font->unscaled->face, glyphs[i].index, font->load_flags | FT_LOAD_NO_BITMAP);
- /* XXX: What to do in this error case? */
- if (error)
- continue;
- /* XXX: Do we want to support bitmap fonts here? */
- if (glyph->format == ft_glyph_format_bitmap)
- continue;
-
- /* Font glyphs have an inverted Y axis compared to cairo. */
- FT_Outline_Transform (&glyph->outline, &invert_y);
- FT_Outline_Translate (&glyph->outline,
- DOUBLE_TO_26_6(glyphs[i].x),
- DOUBLE_TO_26_6(glyphs[i].y));
- FT_Outline_Decompose (&glyph->outline, &outline_funcs, path);
- }
- _cairo_path_close_path (path);
-
- cairo_ft_font_unlock_face (abstract_font);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ft_font_create_glyph (cairo_image_glyph_cache_entry_t *val)
-{
- ft_unscaled_font_t *unscaled = (ft_unscaled_font_t *)val->key.unscaled;
- FT_GlyphSlot glyphslot;
- unsigned int width, height, stride;
- FT_Face face;
- FT_Outline *outline;
- FT_BBox cbox;
- FT_Bitmap bitmap;
- FT_Glyph_Metrics *metrics;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
- glyphslot = unscaled->face->glyph;
- metrics = &glyphslot->metrics;
-
- face = _ft_unscaled_font_lock_face (unscaled);
- if (!face)
- return CAIRO_STATUS_NO_MEMORY;
-
- _ft_unscaled_font_set_scale (unscaled, &val->key.scale);
-
- if (FT_Load_Glyph (face, val->key.index, val->key.flags) != 0) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
-
- /*
- * Note: the font's coordinate system is upside down from ours, so the
- * Y coordinates of the bearing and advance need to be negated.
- *
- * Scale metrics back to glyph space from the scaled glyph space returned
- * by FreeType
- */
-
- val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / unscaled->x_scale;
- val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / unscaled->y_scale;
-
- val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / unscaled->x_scale;
- val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / unscaled->y_scale;
-
- /*
- * use untransformed advance values
- * XXX uses horizontal advance only at present;
- should provide FT_LOAD_VERTICAL_LAYOUT
- */
-
- val->extents.x_advance = DOUBLE_FROM_26_6 (face->glyph->metrics.horiAdvance) / unscaled->x_scale;
- val->extents.y_advance = 0 / unscaled->y_scale;
-
- outline = &glyphslot->outline;
-
- FT_Outline_Get_CBox (outline, &cbox);
-
- cbox.xMin &= -64;
- cbox.yMin &= -64;
- cbox.xMax = (cbox.xMax + 63) & -64;
- cbox.yMax = (cbox.yMax + 63) & -64;
-
- width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6);
- height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6);
- stride = (width + 3) & -4;
-
- if (width * height == 0)
- val->image = NULL;
- else
- {
-
- bitmap.pixel_mode = ft_pixel_mode_grays;
- bitmap.num_grays = 256;
- bitmap.width = width;
- bitmap.rows = height;
- bitmap.pitch = stride;
- bitmap.buffer = calloc (1, stride * height);
-
- if (bitmap.buffer == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
-
- FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin);
-
- if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) {
- free (bitmap.buffer);
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
-
- val->image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data ((char *) bitmap.buffer,
- CAIRO_FORMAT_A8,
- width, height, stride);
- if (val->image == NULL) {
- free (bitmap.buffer);
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
-
- _cairo_image_surface_assume_ownership_of_data (val->image);
- }
-
- /*
- * Note: the font's coordinate system is upside down from ours, so the
- * Y coordinate of the control box needs to be negated.
- */
-
- val->size.width = (unsigned short) width;
- val->size.height = (unsigned short) height;
- val->size.x = (short) (cbox.xMin >> 6);
- val->size.y = - (short) (cbox.yMax >> 6);
-
- FAIL:
- _ft_unscaled_font_unlock_face (unscaled);
-
- return status;
-}
-
-const cairo_font_backend_t cairo_ft_font_backend = {
- _cairo_ft_font_create,
- _cairo_ft_font_destroy_font,
- _cairo_ft_font_destroy_unscaled_font,
- _cairo_ft_font_font_extents,
- _cairo_ft_font_text_to_glyphs,
- _cairo_ft_font_glyph_extents,
- _cairo_ft_font_glyph_bbox,
- _cairo_ft_font_show_glyphs,
- _cairo_ft_font_glyph_path,
- _cairo_ft_font_get_glyph_cache_key,
- _cairo_ft_font_create_glyph
-};
-
-/* implement the platform-specific interface */
-
-/**
- * cairo_ft_font_create:
- * @pattern: A fully resolved fontconfig
- * pattern. A pattern can be resolved, by, among other things, calling
- * FcConfigSubstitute(), FcDefaultSubstitute(), then
- * FcFontMatch(). Cairo will call FcPatternReference() on this
- * pattern, so you should not further modify the pattern, but you can
- * release your reference to the pattern with FcPatternDestroy() if
- * you no longer need to access it.
- * @scale: The scale at which this font will be used. The
- * scale is given by multiplying the font matrix (see
- * cairo_transform_font()) by the current transformation matrix.
- * The translation elements of the resulting matrix are ignored.
- *
- * Creates a new font for the FreeType font backend based on a
- * fontconfig pattern. This font can then be used with
- * cairo_set_font(), cairo_font_glyph_extents(), or FreeType backend
- * specific functions like cairo_ft_font_lock_face().
- *
- * Return value: a newly created #cairo_font_t. Free with
- * cairo_font_destroy() when you are done using it.
- **/
-cairo_font_t *
-cairo_ft_font_create (FcPattern *pattern,
- cairo_matrix_t *scale)
-{
- cairo_font_scale_t sc;
- double tx, ty;
-
- cairo_matrix_get_affine (scale,
- &sc.matrix[0][0], &sc.matrix[0][1],
- &sc.matrix[1][0], &sc.matrix[1][1],
- &tx, &ty);
-
- return _ft_font_create (pattern, &sc);
-}
-
-/**
- * cairo_ft_font_create_for_ft_face:
- * @face: A FreeType face object, already opened. This must
- * be kept around until the font object's refcount drops to
- * zero and it is freed. The font object can be kept alive by
- * internal caching, so it's safest to keep the face object
- * around forever.
- * @load_flags: The flags to pass to FT_Load_Glyph when loading
- * glyphs from the font. These flags control aspects of
- * rendering such as hinting and antialiasing. See the FreeType
- * docs for full information.
- * @scale: The scale at which this font will be used. The
- * scale is given by multiplying the font matrix (see
- * cairo_transform_font()) by the current transformation matrix.
- * The translation elements of the resulting matrix are ignored.
- *
- * Creates a new font forthe FreeType font backend from a pre-opened
- * FreeType face. This font can then be used with cairo_set_font(),
- * cairo_font_glyph_extents(), or FreeType backend specific
- * functions like cairo_ft_font_lock_face() Cairo will determine the
- * pixel size and transformation from the @scale parameter and call
- * FT_Set_Transform() and FT_Set_Pixel_Sizes().
- *
- * Return value: a newly created #cairo_font_t. Free with
- * cairo_font_destroy() when you are done using it.
- **/
-cairo_font_t *
-cairo_ft_font_create_for_ft_face (FT_Face face,
- int load_flags,
- cairo_matrix_t *scale)
-{
- cairo_ft_font_t *f = NULL;
- ft_unscaled_font_t *unscaled = NULL;
- cairo_font_scale_t sc;
- double tx, ty;
-
- unscaled = _ft_unscaled_font_create_from_face (face);
- if (unscaled == NULL)
- return NULL;
-
- f = malloc (sizeof(cairo_ft_font_t));
- if (f == NULL)
- goto FREE_UNSCALED;
-
- f->unscaled = unscaled;
- f->pattern = NULL;
- f->load_flags = load_flags;
-
- cairo_matrix_get_affine (scale,
- &sc.matrix[0][0], &sc.matrix[0][1],
- &sc.matrix[1][0], &sc.matrix[1][1],
- &tx, &ty);
-
- _cairo_font_init ((cairo_font_t *)f, &sc, &cairo_ft_font_backend);
-
- return (cairo_font_t *)f;
-
- FREE_UNSCALED:
- _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled);
-
- return NULL;
-}
-
-
-/**
- * cairo_ft_font_lock_face:
- * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
- * object can be created with cairo_ft_font_create() or
- * cairo_ft_font_create_for_ft_face(). On some platforms the font from
- * cairo_current_font() will also be a FreeType font, but using this
- * functionality with fonts you don't create yourself is not
- * recommended.
- *
- * cairo_ft_font_lock_face() gets the #FT_Face object from a FreeType
- * backend font and scales it appropriately for the font. You must
- * release the face with cairo_ft_font_unlock_face()
- * when you are done using it. Since the #FT_Face object can be
- * shared between multiple #cairo_font_t objects, you must not
- * lock any other font objects until you unlock this one. A count is
- * kept of the number of times cairo_ft_font_lock_face() is
- * called. cairo_ft_font_unlock_face() must be called the same number
- * of times.
- *
- * You must be careful when using this function in a library or in a
- * threaded application, because other threads may lock faces that
- * share the same #FT_Face object. For this reason, you must call
- * cairo_ft_lock() before locking any face objects, and
- * cairo_ft_unlock() after you are done. (These functions are not yet
- * implemented, so this function cannot be currently safely used in a
- * threaded application.)
-
- * Return value: The #FT_Face object for @font, scaled appropriately.
- **/
-FT_Face
-cairo_ft_font_lock_face (cairo_font_t *abstract_font)
-{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
- FT_Face face;
-
- face = _ft_unscaled_font_lock_face (font->unscaled);
- if (!face)
- return NULL;
-
- _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale);
-
- return face;
-}
-
-/**
- * cairo_ft_font_unlock_face:
- * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
- * object can be created with cairo_ft_font_create() or
- * cairo_ft_font_create_for_ft_face(). On some platforms the font from
- * cairo_current_font() will also be a FreeType font, but using this
- * functionality with fonts you don't create yourself is not
- * recommended.
- *
- * Releases a face obtained with cairo_ft_font_lock_face(). See the
- * documentation for that function for full details.
- **/
-void
-cairo_ft_font_unlock_face (cairo_font_t *abstract_font)
-{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
-
- _ft_unscaled_font_unlock_face (font->unscaled);
-}
-
-/**
- * cairo_ft_font_get_pattern:
- * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
- * object can be created with cairo_ft_font_create() or
- * cairo_ft_font_create_for_ft_face(). On some platforms the font from
- * cairo_current_font() will also be a FreeType font, but using this
- * functionality with fonts you don't create yourself is not
- * recommended.
- *
- * cairo_ft_font_get_pattern() gets the #FcPattern for a FreeType
- * backend font.
-
- * Return value: The #FcPattenr for @font. The return value is owned
- * by the font, so you must not modify it, and must call
- * FcPatternReference() to keep a persistant reference to the
- * pattern. If the font was created with cairo_ft_font_create_for_ft_face()
- * returns %NULL.
- **/
-FcPattern *
-cairo_ft_font_get_pattern (cairo_font_t *abstract_font)
-{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
-
- if (font == NULL)
- return NULL;
-
- return font->pattern;
-}
-
-/* We expose our unscaled font implementation internally for the the
- * PDF backend, which needs to keep track of the the different
- * fonts-on-disk used by a document, so it can embed them.
- */
-cairo_unscaled_font_t *
-_cairo_ft_font_get_unscaled_font (cairo_font_t *abstract_font)
-{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
-
- return (cairo_unscaled_font_t *)font->unscaled;
-}
-
-/* This differs from _cairo_ft_scaled_font_lock_face in that it doesn't
- * set the scale on the face, but just returns it at the last scale.
- */
-FT_Face
-_cairo_ft_unscaled_font_lock_face (cairo_unscaled_font_t *unscaled_font)
-{
- return _ft_unscaled_font_lock_face ((ft_unscaled_font_t *)unscaled_font);
-}
-
-void
-_cairo_ft_unscaled_font_unlock_face (cairo_unscaled_font_t *unscaled_font)
-{
- _ft_unscaled_font_unlock_face ((ft_unscaled_font_t *)unscaled_font);
-}
diff --git a/src/cairo_glitz_surface.c b/src/cairo_glitz_surface.c
deleted file mode 100644
index ee664e1cc..000000000
--- a/src/cairo_glitz_surface.c
+++ /dev/null
@@ -1,1317 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2004 David Reveman
- *
- * 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 David
- * Reveman not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. David Reveman makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL DAVID REVEMAN 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: David Reveman <davidr@novell.com>
- */
-
-#include "cairoint.h"
-#include "cairo-glitz.h"
-
-void
-cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface)
-{
- cairo_surface_t *crsurface;
-
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
-
- crsurface = cairo_glitz_surface_create (surface);
- if (crsurface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface (cr, crsurface);
-
- cairo_surface_destroy (crsurface);
-}
-
-typedef struct _cairo_glitz_surface {
- cairo_surface_t base;
-
- glitz_surface_t *surface;
- glitz_format_t *format;
- pixman_region16_t *clip;
-} cairo_glitz_surface_t;
-
-static void
-_cairo_glitz_surface_destroy (void *abstract_surface)
-{
- cairo_glitz_surface_t *surface = abstract_surface;
-
- if (surface->clip)
- {
- glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
- pixman_region_destroy (surface->clip);
- }
-
- glitz_surface_destroy (surface->surface);
- free (surface);
-}
-
-static glitz_format_name_t
-_glitz_format (cairo_format_t format)
-{
- switch (format) {
- default:
- case CAIRO_FORMAT_ARGB32:
- return GLITZ_STANDARD_ARGB32;
- case CAIRO_FORMAT_RGB24:
- return GLITZ_STANDARD_RGB24;
- case CAIRO_FORMAT_A8:
- return GLITZ_STANDARD_A8;
- case CAIRO_FORMAT_A1:
- return GLITZ_STANDARD_A1;
- }
-}
-
-static cairo_surface_t *
-_cairo_glitz_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int draw,
- int width,
- int height)
-{
- cairo_glitz_surface_t *src = abstract_src;
- cairo_surface_t *crsurface;
- glitz_drawable_t *drawable;
- glitz_surface_t *surface;
- glitz_format_t *gformat;
-
- drawable = glitz_surface_get_drawable (src->surface);
-
- gformat = glitz_find_standard_format (drawable, _glitz_format (format));
- if (!gformat)
- return NULL;
-
- surface = glitz_surface_create (drawable, gformat, width, height, 0, NULL);
- if (!surface)
- return NULL;
-
- crsurface = cairo_glitz_surface_create (surface);
-
- glitz_surface_destroy (surface);
-
- return crsurface;
-}
-
-static double
-_cairo_glitz_surface_pixels_per_inch (void *abstract_surface)
-{
- return 96.0;
-}
-
-static cairo_status_t
-_cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
- cairo_rectangle_t *interest,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *rect_out)
-{
- cairo_image_surface_t *image;
- int x1, y1, x2, y2;
- int width, height;
- char *pixels;
- cairo_format_masks_t format;
- glitz_buffer_t *buffer;
- glitz_pixel_format_t pf;
-
- x1 = 0;
- y1 = 0;
- x2 = glitz_surface_get_width (surface->surface);
- y2 = glitz_surface_get_height (surface->surface);
-
- if (interest)
- {
- if (interest->x > x1)
- x1 = interest->x;
- if (interest->y > y1)
- y1 = interest->y;
- if (interest->x + interest->width < x2)
- x2 = interest->x + interest->width;
- if (interest->y + interest->height < y2)
- y2 = interest->y + interest->height;
-
- if (x1 >= x2 || y1 >= y2)
- {
- *image_out = NULL;
- return CAIRO_STATUS_SUCCESS;
- }
- }
-
- width = x2 - x1;
- height = y2 - y1;
-
- if (rect_out)
- {
- rect_out->x = x1;
- rect_out->y = y1;
- rect_out->width = width;
- rect_out->height = height;
- }
-
- if (surface->format->type == GLITZ_FORMAT_TYPE_COLOR) {
- if (surface->format->color.red_size > 0) {
- format.bpp = 32;
-
- if (surface->format->color.alpha_size > 0)
- format.alpha_mask = 0xff000000;
- else
- format.alpha_mask = 0x0;
-
- format.red_mask = 0xff0000;
- format.green_mask = 0xff00;
- format.blue_mask = 0xff;
- } else {
- format.bpp = 8;
- format.blue_mask = format.green_mask = format.red_mask = 0x0;
- format.alpha_mask = 0xff;
- }
- } else {
- format.bpp = 32;
- format.alpha_mask = 0xff000000;
- format.red_mask = 0xff0000;
- format.green_mask = 0xff00;
- format.blue_mask = 0xff;
- }
-
- pf.masks.bpp = format.bpp;
- pf.masks.alpha_mask = format.alpha_mask;
- pf.masks.red_mask = format.red_mask;
- pf.masks.green_mask = format.green_mask;
- pf.masks.blue_mask = format.blue_mask;
- pf.xoffset = 0;
- pf.skip_lines = 0;
-
- /* XXX: we should eventually return images with negative stride,
- need to verify that libpixman have no problem with this first. */
- pf.bytes_per_line = (((width * format.bpp) / 8) + 3) & -4;
- pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
-
- pixels = malloc (height * pf.bytes_per_line);
- if (!pixels)
- return CAIRO_STATUS_NO_MEMORY;
-
- buffer = glitz_buffer_create_for_data (pixels);
- if (!buffer) {
- free (pixels);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- glitz_get_pixels (surface->surface,
- x1, y1,
- width, height,
- &pf,
- buffer);
-
- glitz_buffer_destroy (buffer);
-
- image = (cairo_image_surface_t *)
- _cairo_image_surface_create_with_masks (pixels,
- &format,
- width, height,
- pf.bytes_per_line);
-
- if (!image)
- {
- free (pixels);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- _cairo_image_surface_assume_ownership_of_data (image);
-
- _cairo_image_surface_set_repeat (image, surface->base.repeat);
- _cairo_image_surface_set_matrix (image, &(surface->base.matrix));
-
- *image_out = image;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_glitz_surface_set_image (void *abstract_surface,
- cairo_image_surface_t *image,
- int x_dst,
- int y_dst)
-{
- cairo_glitz_surface_t *surface = abstract_surface;
- glitz_buffer_t *buffer;
- glitz_pixel_format_t pf;
- pixman_format_t *format;
- int am, rm, gm, bm;
- char *data;
-
- format = pixman_image_get_format (image->pixman_image);
- if (!format)
- return CAIRO_STATUS_NO_MEMORY;
-
- pixman_format_get_masks (format, &pf.masks.bpp, &am, &rm, &gm, &bm);
-
- pf.masks.alpha_mask = am;
- pf.masks.red_mask = rm;
- pf.masks.green_mask = gm;
- pf.masks.blue_mask = bm;
- pf.xoffset = 0;
- pf.skip_lines = 0;
-
- /* check for negative stride */
- if (image->stride < 0)
- {
- pf.bytes_per_line = -image->stride;
- pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP;
- data = (char *) image->data + image->stride * (image->height - 1);
- }
- else
- {
- pf.bytes_per_line = image->stride;
- pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
- data = (char *) image->data;
- }
-
- buffer = glitz_buffer_create_for_data (data);
- if (!buffer)
- return CAIRO_STATUS_NO_MEMORY;
-
- glitz_set_pixels (surface->surface,
- x_dst, y_dst,
- image->width, image->height,
- &pf,
- buffer);
-
- glitz_buffer_destroy (buffer);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_glitz_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_glitz_surface_t *surface = abstract_surface;
-
- *image_extra = NULL;
-
- return _cairo_glitz_surface_get_image (surface, NULL, image_out, NULL);
-}
-
-static void
-_cairo_glitz_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
- cairo_surface_destroy (&image->base);
-}
-
-static cairo_status_t
-_cairo_glitz_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect_out,
- void **image_extra)
-{
- cairo_glitz_surface_t *surface = abstract_surface;
- cairo_image_surface_t *image;
- cairo_status_t status;
-
- status = _cairo_glitz_surface_get_image (surface, interest_rect, &image,
- image_rect_out);
- if (status)
- return status;
-
- *image_out = image;
- *image_extra = NULL;
-
- return status;
-}
-
-static void
-_cairo_glitz_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
- cairo_glitz_surface_t *surface = abstract_surface;
-
- _cairo_glitz_surface_set_image (surface, image,
- image_rect->x, image_rect->y);
-
- cairo_surface_destroy (&image->base);
-}
-
-
-static cairo_status_t
-_cairo_glitz_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- cairo_glitz_surface_t *surface = abstract_surface;
- cairo_glitz_surface_t *clone;
-
- if (src->backend == surface->base.backend)
- {
- *clone_out = src;
- cairo_surface_reference (src);
-
- return CAIRO_STATUS_SUCCESS;
- }
- else if (_cairo_surface_is_image (src))
- {
- cairo_image_surface_t *image_src = (cairo_image_surface_t *) src;
-
- clone = (cairo_glitz_surface_t *)
- _cairo_glitz_surface_create_similar (surface, image_src->format, 0,
- image_src->width,
- image_src->height);
- if (!clone)
- return CAIRO_STATUS_NO_MEMORY;
-
- _cairo_glitz_surface_set_image (clone, image_src, 0, 0);
-
- *clone_out = &clone->base;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static void
-_cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *surface,
- cairo_matrix_t *matrix)
-{
- glitz_transform_t transform;
-
- transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
- transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
- transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
-
- transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
- transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
- transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
-
- transform.matrix[2][0] = 0;
- transform.matrix[2][1] = 0;
- transform.matrix[2][2] = 1 << 16;
-
- glitz_surface_set_transform (surface->surface, &transform);
-}
-
-static glitz_operator_t
-_glitz_operator (cairo_operator_t op)
-{
- switch (op) {
- case CAIRO_OPERATOR_CLEAR:
- return GLITZ_OPERATOR_CLEAR;
- case CAIRO_OPERATOR_SRC:
- return GLITZ_OPERATOR_SRC;
- case CAIRO_OPERATOR_DST:
- return GLITZ_OPERATOR_DST;
- case CAIRO_OPERATOR_OVER_REVERSE:
- return GLITZ_OPERATOR_OVER_REVERSE;
- case CAIRO_OPERATOR_IN:
- return GLITZ_OPERATOR_IN;
- case CAIRO_OPERATOR_IN_REVERSE:
- return GLITZ_OPERATOR_IN_REVERSE;
- case CAIRO_OPERATOR_OUT:
- return GLITZ_OPERATOR_OUT;
- case CAIRO_OPERATOR_OUT_REVERSE:
- return GLITZ_OPERATOR_OUT_REVERSE;
- case CAIRO_OPERATOR_ATOP:
- return GLITZ_OPERATOR_ATOP;
- case CAIRO_OPERATOR_ATOP_REVERSE:
- return GLITZ_OPERATOR_ATOP_REVERSE;
- case CAIRO_OPERATOR_XOR:
- return GLITZ_OPERATOR_XOR;
- case CAIRO_OPERATOR_ADD:
- return GLITZ_OPERATOR_ADD;
- case CAIRO_OPERATOR_OVER:
- default:
- return GLITZ_OPERATOR_OVER;
- }
-}
-
-static glitz_status_t
-_glitz_ensure_target (glitz_surface_t *surface)
-{
- glitz_drawable_t *drawable;
-
- drawable = glitz_surface_get_attached_drawable (surface);
- if (!drawable) {
- glitz_drawable_format_t *dformat;
- glitz_drawable_format_t templ;
- glitz_format_t *format;
- glitz_drawable_t *pbuffer;
- unsigned long mask;
- int i;
-
- format = glitz_surface_get_format (surface);
- if (format->type != GLITZ_FORMAT_TYPE_COLOR)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- drawable = glitz_surface_get_drawable (surface);
- dformat = glitz_drawable_get_format (drawable);
-
- templ.types.pbuffer = 1;
- mask = GLITZ_FORMAT_PBUFFER_MASK;
-
- templ.samples = dformat->samples;
- mask |= GLITZ_FORMAT_SAMPLES_MASK;
-
- i = 0;
- do {
- dformat = glitz_find_similar_drawable_format (drawable,
- mask, &templ, i++);
-
- if (dformat) {
- int sufficient = 1;
-
- if (format->color.red_size) {
- if (dformat->color.red_size < format->color.red_size)
- sufficient = 0;
- }
- if (format->color.alpha_size) {
- if (dformat->color.alpha_size < format->color.alpha_size)
- sufficient = 0;
- }
-
- if (sufficient)
- break;
- }
- } while (dformat);
-
- if (!dformat)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- pbuffer =
- glitz_create_pbuffer_drawable (drawable, dformat,
- glitz_surface_get_width (surface),
- glitz_surface_get_height (surface));
- if (!pbuffer)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- glitz_surface_attach (surface, pbuffer,
- GLITZ_DRAWABLE_BUFFER_FRONT_COLOR,
- 0, 0);
-
- glitz_drawable_destroy (pbuffer);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-typedef struct _cairo_glitz_surface_attributes {
- cairo_surface_attributes_t base;
-
- glitz_fill_t fill;
- glitz_filter_t filter;
- glitz_fixed16_16_t *params;
- int n_params;
- cairo_bool_t acquired;
-} cairo_glitz_surface_attributes_t;
-
-static cairo_int_status_t
-_cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern,
- cairo_glitz_surface_t *dst,
- int x,
- int y,
- unsigned int width,
- unsigned int height,
- cairo_glitz_surface_t **surface_out,
- cairo_glitz_surface_attributes_t *attr)
-{
- cairo_glitz_surface_t *src = NULL;
-
- attr->acquired = FALSE;
-
- switch (pattern->type) {
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL: {
- cairo_gradient_pattern_t *gradient =
- (cairo_gradient_pattern_t *) pattern;
- glitz_drawable_t *drawable;
- glitz_fixed16_16_t *params;
- int n_params;
- int i;
- unsigned short alpha;
-
- /* XXX: the current color gradient acceleration provided by glitz is
- * experimental, it's been proven inappropriate in a number of ways,
- * most importantly, it's currently implemented as filters and
- * gradients are not filters. eventually, it will be replaced with
- * something more appropriate.
- */
-
- if (gradient->n_stops < 2)
- break;
-
- /* glitz doesn't support inner and outer circle with different
- center points. */
- if (pattern->type == CAIRO_PATTERN_RADIAL)
- {
- cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
-
- if (grad->center0.x != grad->center1.x ||
- grad->center0.y != grad->center1.y)
- break;
- }
-
- drawable = glitz_surface_get_drawable (dst->surface);
- if (!(glitz_drawable_get_features (drawable) &
- GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK))
- break;
-
- if (pattern->filter != CAIRO_FILTER_BILINEAR &&
- pattern->filter != CAIRO_FILTER_GOOD &&
- pattern->filter != CAIRO_FILTER_BEST)
- break;
-
- alpha = (gradient->stops[0].color.alpha * pattern->alpha) * 0xffff;
- for (i = 1; i < gradient->n_stops; i++)
- {
- unsigned short a;
-
- a = (gradient->stops[i].color.alpha * pattern->alpha) * 0xffff;
- if (a != alpha)
- break;
- }
-
- /* we can't have color stops with different alpha as gradient color
- interpolation should be done to unpremultiplied colors. */
- if (i < gradient->n_stops)
- break;
-
- n_params = gradient->n_stops * 3 + 4;
-
- params = malloc (sizeof (glitz_fixed16_16_t) * n_params);
- if (!params)
- return CAIRO_STATUS_NO_MEMORY;
-
- src = (cairo_glitz_surface_t *)
- _cairo_surface_create_similar_scratch (&dst->base,
- CAIRO_FORMAT_ARGB32, 0,
- gradient->n_stops, 1);
- if (!src)
- {
- free (params);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- for (i = 0; i < gradient->n_stops; i++) {
- glitz_color_t color;
-
- color.red = gradient->stops[i].color.red * alpha;
- color.green = gradient->stops[i].color.green * alpha;
- color.blue = gradient->stops[i].color.blue * alpha;
- color.alpha = alpha;
-
- glitz_set_rectangle (src->surface, &color, i, 0, 1, 1);
-
- params[4 + 3 * i] = gradient->stops[i].offset;
- params[5 + 3 * i] = i << 16;
- params[6 + 3 * i] = 0;
- }
-
- if (pattern->type == CAIRO_PATTERN_LINEAR)
- {
- cairo_linear_pattern_t *grad = (cairo_linear_pattern_t *) pattern;
-
- params[0] = _cairo_fixed_from_double (grad->point0.x);
- params[1] = _cairo_fixed_from_double (grad->point0.y);
- params[2] = _cairo_fixed_from_double (grad->point1.x);
- params[3] = _cairo_fixed_from_double (grad->point1.y);
- attr->filter = GLITZ_FILTER_LINEAR_GRADIENT;
- }
- else
- {
- cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
-
- params[0] = _cairo_fixed_from_double (grad->center0.x);
- params[1] = _cairo_fixed_from_double (grad->center0.y);
- params[2] = _cairo_fixed_from_double (grad->radius0);
- params[3] = _cairo_fixed_from_double (grad->radius1);
- attr->filter = GLITZ_FILTER_RADIAL_GRADIENT;
- }
-
- switch (pattern->extend) {
- case CAIRO_EXTEND_NONE:
- attr->fill = GLITZ_FILL_NEAREST;
- break;
- case CAIRO_EXTEND_REPEAT:
- attr->fill = GLITZ_FILL_REPEAT;
- break;
- case CAIRO_EXTEND_REFLECT:
- attr->fill = GLITZ_FILL_REFLECT;
- break;
- }
-
- attr->params = params;
- attr->n_params = n_params;
- attr->base.matrix = pattern->matrix;
- attr->base.x_offset = 0;
- attr->base.y_offset = 0;
- } break;
- default:
- break;
- }
-
- if (!src)
- {
- cairo_int_status_t status;
-
- status = _cairo_pattern_acquire_surface (pattern, &dst->base,
- x, y, width, height,
- (cairo_surface_t **) &src,
- &attr->base);
- if (status)
- return status;
-
- if (src)
- {
- switch (attr->base.extend) {
- case CAIRO_EXTEND_NONE:
- attr->fill = GLITZ_FILL_TRANSPARENT;
- break;
- case CAIRO_EXTEND_REPEAT:
- attr->fill = GLITZ_FILL_REPEAT;
- break;
- case CAIRO_EXTEND_REFLECT:
- attr->fill = GLITZ_FILL_REFLECT;
- break;
- }
-
- switch (attr->base.filter) {
- case CAIRO_FILTER_FAST:
- case CAIRO_FILTER_NEAREST:
- attr->filter = GLITZ_FILTER_NEAREST;
- break;
- case CAIRO_FILTER_GOOD:
- case CAIRO_FILTER_BEST:
- case CAIRO_FILTER_BILINEAR:
- default:
- attr->filter = GLITZ_FILTER_BILINEAR;
- break;
- }
-
- attr->params = NULL;
- attr->n_params = 0;
- attr->acquired = TRUE;
- }
- }
-
- *surface_out = src;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_glitz_pattern_release_surface (cairo_glitz_surface_t *dst,
- cairo_glitz_surface_t *surface,
- cairo_glitz_surface_attributes_t *attr)
-{
- if (attr->acquired)
- _cairo_pattern_release_surface (&dst->base, &surface->base,
- &attr->base);
- else
- _cairo_glitz_surface_destroy (surface);
-}
-
-static cairo_int_status_t
-_cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src,
- cairo_pattern_t *mask,
- cairo_glitz_surface_t *dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- unsigned int width,
- unsigned int height,
- cairo_glitz_surface_t **src_out,
- cairo_glitz_surface_t **mask_out,
- cairo_glitz_surface_attributes_t *sattr,
- cairo_glitz_surface_attributes_t *mattr)
-{
- cairo_int_status_t status;
- cairo_pattern_union_t tmp;
- cairo_bool_t src_opaque, mask_opaque;
- double src_alpha, mask_alpha;
-
- src_opaque = _cairo_pattern_is_opaque (src);
- mask_opaque = !mask || _cairo_pattern_is_opaque (mask);
-
- /* For surface patterns, we move any translucency from src->alpha
- * to mask->alpha so we can use the source unchanged. Otherwise we
- * move the translucency from mask->alpha to src->alpha so that
- * we can drop the mask if possible.
- */
- if (src->type == CAIRO_PATTERN_SURFACE)
- {
- if (mask) {
- mask_opaque = mask_opaque && src_opaque;
- mask_alpha = mask->alpha * src->alpha;
- } else {
- mask_opaque = src_opaque;
- mask_alpha = src->alpha;
- }
-
- src_alpha = 1.0;
- src_opaque = TRUE;
- }
- else
- {
- if (mask)
- {
- src_opaque = mask_opaque && src_opaque;
- src_alpha = mask->alpha * src->alpha;
- /* FIXME: This needs changing when we support RENDER
- * style 4-channel masks.
- */
- if (mask->type == CAIRO_PATTERN_SOLID)
- mask = NULL;
- } else
- src_alpha = src->alpha;
-
- mask_alpha = 1.0;
- mask_opaque = TRUE;
- }
-
- _cairo_pattern_init_copy (&tmp.base, src);
- _cairo_pattern_set_alpha (&tmp.base, src_alpha);
-
- status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
- src_x, src_y,
- width, height,
- src_out, sattr);
-
- _cairo_pattern_fini (&tmp.base);
-
- if (status)
- return status;
-
- if (mask || !mask_opaque)
- {
- if (mask)
- _cairo_pattern_init_copy (&tmp.base, mask);
- else
- _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0);
-
- _cairo_pattern_set_alpha (&tmp.base, mask_alpha);
-
- status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
- mask_x, mask_y,
- width, height,
- mask_out, mattr);
-
- _cairo_pattern_fini (&tmp.base);
-
- if (status)
- {
- _cairo_glitz_pattern_release_surface (dst, *src_out, sattr);
- return status;
- }
- }
- else
- {
- *mask_out = NULL;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_glitz_surface_set_attributes (cairo_glitz_surface_t *surface,
- cairo_glitz_surface_attributes_t *a)
-{
- _cairo_glitz_surface_set_matrix (surface, &a->base.matrix);
- glitz_surface_set_fill (surface->surface, a->fill);
- glitz_surface_set_filter (surface->surface, a->filter,
- a->params, a->n_params);
-}
-
-static cairo_int_status_t
-_cairo_glitz_surface_composite (cairo_operator_t op,
- cairo_pattern_t *src_pattern,
- cairo_pattern_t *mask_pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- cairo_glitz_surface_attributes_t src_attr, mask_attr;
- cairo_glitz_surface_t *dst = abstract_dst;
- cairo_glitz_surface_t *src;
- cairo_glitz_surface_t *mask;
- cairo_int_status_t status;
-
- if (op == CAIRO_OPERATOR_SATURATE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (_glitz_ensure_target (dst->surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_glitz_pattern_acquire_surfaces (src_pattern, mask_pattern,
- dst,
- src_x, src_y,
- mask_x, mask_y,
- width, height,
- &src, &mask,
- &src_attr, &mask_attr);
- if (status)
- return status;
-
- _cairo_glitz_surface_set_attributes (src, &src_attr);
- if (mask)
- {
- _cairo_glitz_surface_set_attributes (mask, &mask_attr);
- glitz_composite (_glitz_operator (op),
- src->surface,
- mask->surface,
- dst->surface,
- src_x + src_attr.base.x_offset,
- src_y + src_attr.base.y_offset,
- mask_x + mask_attr.base.x_offset,
- mask_y + mask_attr.base.y_offset,
- dst_x, dst_y,
- width, height);
-
- if (mask_attr.n_params)
- free (mask_attr.params);
-
- _cairo_glitz_pattern_release_surface (dst, mask, &mask_attr);
- }
- else
- {
- glitz_composite (_glitz_operator (op),
- src->surface,
- NULL,
- dst->surface,
- src_x + src_attr.base.x_offset,
- src_y + src_attr.base.y_offset,
- 0, 0,
- dst_x, dst_y,
- width, height);
- }
-
- if (src_attr.n_params)
- free (src_attr.params);
-
- _cairo_glitz_pattern_release_surface (dst, src, &src_attr);
-
- if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_glitz_surface_fill_rectangles (void *abstract_dst,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int n_rects)
-{
- cairo_glitz_surface_t *dst = abstract_dst;
-
- if (op == CAIRO_OPERATOR_SRC)
- {
- glitz_color_t glitz_color;
-
- glitz_color.red = color->red_short;
- glitz_color.green = color->green_short;
- glitz_color.blue = color->blue_short;
- glitz_color.alpha = color->alpha_short;
-
- if (glitz_surface_get_width (dst->surface) != 1 ||
- glitz_surface_get_height (dst->surface) != 1)
- _glitz_ensure_target (dst->surface);
-
- glitz_set_rectangles (dst->surface, &glitz_color,
- (glitz_rectangle_t *) rects, n_rects);
- }
- else
- {
- cairo_glitz_surface_t *src;
-
- if (op == CAIRO_OPERATOR_SATURATE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (_glitz_ensure_target (dst->surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- src = (cairo_glitz_surface_t *)
- _cairo_surface_create_similar_solid (&dst->base,
- CAIRO_FORMAT_ARGB32, 1, 1,
- (cairo_color_t *) color);
- if (!src)
- return CAIRO_STATUS_NO_MEMORY;
-
- while (n_rects--)
- {
- glitz_composite (_glitz_operator (op),
- src->surface,
- NULL,
- dst->surface,
- 0, 0,
- 0, 0,
- rects->x, rects->y,
- rects->width, rects->height);
- rects++;
- }
-
- cairo_surface_destroy (&src->base);
- }
-
- if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
- cairo_pattern_t *pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int n_traps)
-{
- cairo_glitz_surface_attributes_t attributes;
- cairo_glitz_surface_t *dst = abstract_dst;
- cairo_glitz_surface_t *src;
- cairo_glitz_surface_t *mask = NULL;
- glitz_buffer_t *buffer = NULL;
- void *data = NULL;
- cairo_int_status_t status;
- unsigned short alpha;
-
- if (op == CAIRO_OPERATOR_SATURATE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (_glitz_ensure_target (dst->surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (pattern->type == CAIRO_PATTERN_SURFACE)
- {
- cairo_pattern_union_t tmp;
-
- _cairo_pattern_init_copy (&tmp.base, pattern);
- _cairo_pattern_set_alpha (&tmp.base, 1.0);
-
- status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
- src_x, src_y,
- width, height,
- &src, &attributes);
-
- _cairo_pattern_fini (&tmp.base);
-
- alpha = pattern->alpha * 0xffff;
- }
- else
- {
- status = _cairo_glitz_pattern_acquire_surface (pattern, dst,
- src_x, src_y,
- width, height,
- &src, &attributes);
- alpha = 0xffff;
- }
-
- if (status)
- return status;
-
- if (op == CAIRO_OPERATOR_ADD || n_traps <= 1)
- {
- static glitz_color_t clear_black = { 0, 0, 0, 0 };
- glitz_color_t color;
- glitz_geometry_format_t format;
- int n_trap_added;
- int offset = 0;
- int data_size = 0;
- int size = 30 * n_traps; /* just a guess */
-
- format.vertex.primitive = GLITZ_PRIMITIVE_QUADS;
- format.vertex.type = GLITZ_DATA_TYPE_FLOAT;
- format.vertex.bytes_per_vertex = 3 * sizeof (glitz_float_t);
- format.vertex.attributes = GLITZ_VERTEX_ATTRIBUTE_MASK_COORD_MASK;
- format.vertex.mask.type = GLITZ_DATA_TYPE_FLOAT;
- format.vertex.mask.size = GLITZ_COORDINATE_SIZE_X;
- format.vertex.mask.offset = 2 * sizeof (glitz_float_t);
-
- mask = (cairo_glitz_surface_t *)
- _cairo_glitz_surface_create_similar (&dst->base,
- CAIRO_FORMAT_A8, 0,
- 2, 1);
- if (!mask)
- {
- _cairo_glitz_pattern_release_surface (dst, src, &attributes);
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- color.red = color.green = color.blue = color.alpha = alpha;
-
- glitz_set_rectangle (mask->surface, &clear_black, 0, 0, 1, 1);
- glitz_set_rectangle (mask->surface, &color, 1, 0, 1, 1);
-
- glitz_surface_set_fill (mask->surface, GLITZ_FILL_NEAREST);
- glitz_surface_set_filter (mask->surface,
- GLITZ_FILTER_BILINEAR,
- NULL, 0);
-
- size *= format.vertex.bytes_per_vertex;
-
- while (n_traps)
- {
- if (data_size < size)
- {
- data_size = size;
- data = realloc (data, data_size);
- if (!data)
- {
- _cairo_glitz_pattern_release_surface (dst, src,
- &attributes);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- if (buffer)
- glitz_buffer_destroy (buffer);
-
- buffer = glitz_buffer_create_for_data (data);
- if (!buffer) {
- free (data);
- _cairo_glitz_pattern_release_surface (dst, src,
- &attributes);
- return CAIRO_STATUS_NO_MEMORY;
- }
- }
-
- offset +=
- glitz_add_trapezoids (buffer,
- offset, size - offset,
- format.vertex.type, mask->surface,
- (glitz_trapezoid_t *) traps, n_traps,
- &n_trap_added);
-
- n_traps -= n_trap_added;
- traps += n_trap_added;
- size *= 2;
- }
-
- glitz_set_geometry (dst->surface,
- GLITZ_GEOMETRY_TYPE_VERTEX,
- &format, buffer);
- glitz_set_array (dst->surface, 0, 3,
- offset / format.vertex.bytes_per_vertex,
- 0, 0);
- }
- else
- {
- cairo_image_surface_t *image;
- char *ptr;
- int stride;
-
- stride = (width + 3) & -4;
- data = malloc (stride * height);
- if (!data)
- {
- _cairo_glitz_pattern_release_surface (dst, src, &attributes);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- memset (data, 0, stride * height);
-
- /* using negative stride */
- ptr = (char *) data + stride * (height - 1);
-
- image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data (ptr,
- CAIRO_FORMAT_A8,
- width, height,
- -stride);
- if (!image)
- {
- cairo_surface_destroy (&src->base);
- free (data);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y,
- (pixman_trapezoid_t *) traps, n_traps);
-
- if (alpha != 0xffff)
- {
- pixman_color_t color;
-
- color.red = color.green = color.blue = color.alpha = alpha;
-
- pixman_fill_rectangle (PIXMAN_OPERATOR_IN,
- image->pixman_image,
- &color,
- 0, 0, width, height);
- }
-
- mask = (cairo_glitz_surface_t *)
- _cairo_surface_create_similar_scratch (&dst->base,
- CAIRO_FORMAT_A8, 0,
- width, height);
- if (!mask)
- {
- _cairo_glitz_pattern_release_surface (dst, src, &attributes);
- free (data);
- cairo_surface_destroy (&image->base);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- _cairo_glitz_surface_set_image (mask, image, 0, 0);
- }
-
- _cairo_glitz_surface_set_attributes (src, &attributes);
-
- glitz_composite (_glitz_operator (op),
- src->surface,
- mask->surface,
- dst->surface,
- src_x + attributes.base.x_offset,
- src_y + attributes.base.y_offset,
- 0, 0,
- dst_x, dst_y,
- width, height);
-
- if (attributes.n_params)
- free (attributes.params);
-
- glitz_set_geometry (dst->surface,
- GLITZ_GEOMETRY_TYPE_NONE,
- NULL, NULL);
-
- if (buffer)
- glitz_buffer_destroy (buffer);
-
- free (data);
-
- _cairo_glitz_pattern_release_surface (dst, src, &attributes);
- if (mask)
- cairo_surface_destroy (&mask->base);
-
- if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_glitz_surface_copy_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_glitz_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_glitz_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- cairo_glitz_surface_t *surface = abstract_surface;
-
- if (region)
- {
- glitz_box_t *box;
- int n;
-
- if (!surface->clip)
- {
- surface->clip = pixman_region_create ();
- if (!surface->clip)
- return CAIRO_STATUS_NO_MEMORY;
- }
- pixman_region_copy (surface->clip, region);
-
- box = (glitz_box_t *) pixman_region_rects (surface->clip);
- n = pixman_region_num_rects (surface->clip);
- glitz_surface_set_clip_region (surface->surface, 0, 0, box, n);
- }
- else
- {
- glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
-
- if (surface->clip)
- pixman_region_destroy (surface->clip);
-
- surface->clip = NULL;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static const cairo_surface_backend_t cairo_glitz_surface_backend = {
- _cairo_glitz_surface_create_similar,
- _cairo_glitz_surface_destroy,
- _cairo_glitz_surface_pixels_per_inch,
- _cairo_glitz_surface_acquire_source_image,
- _cairo_glitz_surface_release_source_image,
- _cairo_glitz_surface_acquire_dest_image,
- _cairo_glitz_surface_release_dest_image,
- _cairo_glitz_surface_clone_similar,
- _cairo_glitz_surface_composite,
- _cairo_glitz_surface_fill_rectangles,
- _cairo_glitz_surface_composite_trapezoids,
- _cairo_glitz_surface_copy_page,
- _cairo_glitz_surface_show_page,
- _cairo_glitz_surface_set_clip_region,
- NULL /* show_glyphs */
-};
-
-cairo_surface_t *
-cairo_glitz_surface_create (glitz_surface_t *surface)
-{
- cairo_glitz_surface_t *crsurface;
-
- if (!surface)
- return NULL;
-
- crsurface = malloc (sizeof (cairo_glitz_surface_t));
- if (crsurface == NULL)
- return NULL;
-
- _cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend);
-
- glitz_surface_reference (surface);
-
- crsurface->surface = surface;
- crsurface->format = glitz_surface_get_format (surface);
- crsurface->clip = NULL;
-
- return (cairo_surface_t *) crsurface;
-}
diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c
deleted file mode 100644
index d6db560a3..000000000
--- a/src/cairo_gstate.c
+++ /dev/null
@@ -1,2566 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2002 University of Southern California
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#include <stdlib.h>
-#include <math.h>
-
-#include "cairoint.h"
-
-static cairo_status_t
-_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
- cairo_pattern_t *src,
- cairo_operator_t operator,
- cairo_surface_t *dst,
- cairo_traps_t *traps);
-
-static cairo_status_t
-_cairo_gstate_ensure_font (cairo_gstate_t *gstate);
-
-static void
-_cairo_gstate_unset_font (cairo_gstate_t *gstate);
-
-cairo_gstate_t *
-_cairo_gstate_create ()
-{
- cairo_status_t status;
- cairo_gstate_t *gstate;
-
- gstate = malloc (sizeof (cairo_gstate_t));
-
- if (gstate)
- {
- status = _cairo_gstate_init (gstate);
- if (status) {
- free (gstate);
- return NULL;
- }
- }
-
- return gstate;
-}
-
-cairo_status_t
-_cairo_gstate_init (cairo_gstate_t *gstate)
-{
- gstate->operator = CAIRO_GSTATE_OPERATOR_DEFAULT;
-
- gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT;
-
- gstate->line_width = CAIRO_GSTATE_LINE_WIDTH_DEFAULT;
- gstate->line_cap = CAIRO_GSTATE_LINE_CAP_DEFAULT;
- gstate->line_join = CAIRO_GSTATE_LINE_JOIN_DEFAULT;
- gstate->miter_limit = CAIRO_GSTATE_MITER_LIMIT_DEFAULT;
-
- gstate->fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT;
-
- gstate->dash = NULL;
- gstate->num_dashes = 0;
- gstate->dash_offset = 0.0;
-
- gstate->font_family = NULL;
- gstate->font_slant = CAIRO_FONT_SLANT_DEFAULT;
- gstate->font_weight = CAIRO_FONT_WEIGHT_DEFAULT;
-
- gstate->font = NULL;
-
- gstate->surface = NULL;
-
- gstate->clip.region = NULL;
- gstate->clip.surface = NULL;
-
- gstate->pattern = _cairo_pattern_create_solid (0.0, 0.0, 0.0);
- if (!gstate->pattern)
- return CAIRO_STATUS_NO_MEMORY;
-
- gstate->alpha = 1.0;
-
- gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT;
- _cairo_gstate_default_matrix (gstate);
-
- _cairo_path_init (&gstate->path);
-
- _cairo_pen_init_empty (&gstate->pen_regular);
-
- gstate->next = NULL;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
-{
- cairo_status_t status;
- cairo_gstate_t *next;
-
- /* Copy all members, but don't smash the next pointer */
- next = gstate->next;
- *gstate = *other;
- gstate->next = next;
-
- /* Now fix up pointer data that needs to be cloned/referenced */
- if (other->dash) {
- gstate->dash = malloc (other->num_dashes * sizeof (double));
- if (gstate->dash == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double));
- }
-
- if (other->font_family) {
- gstate->font_family = strdup (other->font_family);
- if (!gstate->font_family)
- goto CLEANUP_DASH;
- }
-
- if (other->font) {
- gstate->font = other->font;
- cairo_font_reference (gstate->font);
- }
-
- if (other->clip.region)
- {
- gstate->clip.region = pixman_region_create ();
- pixman_region_copy (gstate->clip.region, other->clip.region);
- }
-
- cairo_surface_reference (gstate->surface);
- cairo_surface_reference (gstate->clip.surface);
-
- cairo_pattern_reference (gstate->pattern);
-
- status = _cairo_path_init_copy (&gstate->path, &other->path);
- if (status)
- goto CLEANUP_FONT;
-
- status = _cairo_pen_init_copy (&gstate->pen_regular, &other->pen_regular);
- if (status)
- goto CLEANUP_PATH;
-
- return status;
-
- CLEANUP_PATH:
- _cairo_path_fini (&gstate->path);
-
- CLEANUP_FONT:
- cairo_font_destroy (gstate->font);
- gstate->font = NULL;
-
- if (gstate->font_family) {
- free (gstate->font_family);
- gstate->font_family = NULL;
- }
-
- CLEANUP_DASH:
- free (gstate->dash);
- gstate->dash = NULL;
-
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-void
-_cairo_gstate_fini (cairo_gstate_t *gstate)
-{
- if (gstate->font_family)
- free (gstate->font_family);
-
- if (gstate->font)
- cairo_font_destroy (gstate->font);
-
- if (gstate->surface)
- cairo_surface_destroy (gstate->surface);
- gstate->surface = NULL;
-
- if (gstate->clip.surface)
- cairo_surface_destroy (gstate->clip.surface);
- gstate->clip.surface = NULL;
-
- if (gstate->clip.region)
- pixman_region_destroy (gstate->clip.region);
- gstate->clip.region = NULL;
-
- cairo_pattern_destroy (gstate->pattern);
-
- _cairo_matrix_fini (&gstate->font_matrix);
-
- _cairo_matrix_fini (&gstate->ctm);
- _cairo_matrix_fini (&gstate->ctm_inverse);
-
- _cairo_path_fini (&gstate->path);
-
- _cairo_pen_fini (&gstate->pen_regular);
-
- if (gstate->dash) {
- free (gstate->dash);
- gstate->dash = NULL;
- }
-}
-
-void
-_cairo_gstate_destroy (cairo_gstate_t *gstate)
-{
- _cairo_gstate_fini (gstate);
- free (gstate);
-}
-
-cairo_gstate_t*
-_cairo_gstate_clone (cairo_gstate_t *gstate)
-{
- cairo_status_t status;
- cairo_gstate_t *clone;
-
- clone = malloc (sizeof (cairo_gstate_t));
- if (clone) {
- status = _cairo_gstate_init_copy (clone, gstate);
- if (status) {
- free (clone);
- return NULL;
- }
- }
- clone->next = NULL;
-
- return clone;
-}
-
-cairo_status_t
-_cairo_gstate_copy (cairo_gstate_t *dest, cairo_gstate_t *src)
-{
- cairo_status_t status;
- cairo_gstate_t *next;
-
- /* Preserve next pointer over fini/init */
- next = dest->next;
- _cairo_gstate_fini (dest);
- status = _cairo_gstate_init_copy (dest, src);
- dest->next = next;
-
- return status;
-}
-
-/* Push rendering off to an off-screen group. */
-/* XXX: Rethinking this API
-cairo_status_t
-_cairo_gstate_begin_group (cairo_gstate_t *gstate)
-{
- Pixmap pix;
- cairo_color_t clear;
- unsigned int width, height;
-
- gstate->parent_surface = gstate->surface;
-
- width = _cairo_surface_get_width (gstate->surface);
- height = _cairo_surface_get_height (gstate->surface);
-
- pix = XCreatePixmap (gstate->dpy,
- _cairo_surface_get_drawable (gstate->surface),
- width, height,
- _cairo_surface_get_depth (gstate->surface));
- if (pix == 0)
- return CAIRO_STATUS_NO_MEMORY;
-
- gstate->surface = cairo_surface_create (gstate->dpy);
- if (gstate->surface == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- _cairo_surface_set_drawableWH (gstate->surface, pix, width, height);
-
- _cairo_color_init (&clear);
- _cairo_color_set_alpha (&clear, 0);
-
- status = _cairo_surface_fill_rectangle (gstate->surface,
- CAIRO_OPERATOR_SRC,
- &clear,
- 0, 0,
- _cairo_surface_get_width (gstate->surface),
- _cairo_surface_get_height (gstate->surface));
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-*/
-
-/* Complete the current offscreen group, composing its contents onto the parent surface. */
-/* XXX: Rethinking this API
-cairo_status_t
-_cairo_gstate_end_group (cairo_gstate_t *gstate)
-{
- Pixmap pix;
- cairo_color_t mask_color;
- cairo_surface_t mask;
-
- if (gstate->parent_surface == NULL)
- return CAIRO_STATUS_INVALID_POP_GROUP;
-
- _cairo_surface_init (&mask, gstate->dpy);
- _cairo_color_init (&mask_color);
- _cairo_color_set_alpha (&mask_color, gstate->alpha);
-
- _cairo_surface_set_solid_color (&mask, &mask_color);
-
- * XXX: This could be made much more efficient by using
- _cairo_surface_get_damaged_width/Height if cairo_surface_t actually kept
- track of such informaton. *
- _cairo_surface_composite (gstate->operator,
- gstate->surface,
- mask,
- gstate->parent_surface,
- 0, 0,
- 0, 0,
- 0, 0,
- _cairo_surface_get_width (gstate->surface),
- _cairo_surface_get_height (gstate->surface));
-
- _cairo_surface_fini (&mask);
-
- pix = _cairo_surface_get_drawable (gstate->surface);
- XFreePixmap (gstate->dpy, pix);
-
- cairo_surface_destroy (gstate->surface);
- gstate->surface = gstate->parent_surface;
- gstate->parent_surface = NULL;
-
- return CAIRO_STATUS_SUCCESS;
-}
-*/
-
-cairo_status_t
-_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface)
-{
- double scale;
-
- _cairo_gstate_unset_font (gstate);
-
- if (gstate->surface)
- cairo_surface_destroy (gstate->surface);
-
- gstate->surface = surface;
-
- /* Sometimes the user wants to return to having no target surface,
- * (just like after cairo_create). This can be useful for forcing
- * the old surface to be destroyed. */
- if (surface == NULL)
- return CAIRO_STATUS_SUCCESS;
-
- cairo_surface_reference (gstate->surface);
-
- scale = _cairo_surface_pixels_per_inch (surface) / gstate->pixels_per_inch;
- _cairo_gstate_scale (gstate, scale, scale);
- gstate->pixels_per_inch = _cairo_surface_pixels_per_inch (surface);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* XXX: Need to decide the memory mangement semantics of this
- function. Should it reference the surface again? */
-cairo_surface_t *
-_cairo_gstate_current_target_surface (cairo_gstate_t *gstate)
-{
- if (gstate == NULL)
- return NULL;
-
-/* XXX: Do we want this?
- if (gstate->surface)
- _cairo_surface_reference (gstate->surface);
-*/
-
- return gstate->surface;
-}
-
-cairo_status_t
-_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern)
-{
- if (pattern == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- cairo_pattern_reference (pattern);
- cairo_pattern_destroy (gstate->pattern);
- gstate->pattern = pattern;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_pattern_t *
-_cairo_gstate_current_pattern (cairo_gstate_t *gstate)
-{
- if (gstate == NULL)
- return NULL;
-
-/* XXX: Do we want this?
- cairo_pattern_reference (gstate->pattern);
-*/
-
- return gstate->pattern;
-}
-
-cairo_status_t
-_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator)
-{
- gstate->operator = operator;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_operator_t
-_cairo_gstate_current_operator (cairo_gstate_t *gstate)
-{
- return gstate->operator;
-}
-
-cairo_status_t
-_cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, double blue)
-{
- cairo_pattern_destroy (gstate->pattern);
-
- gstate->pattern = _cairo_pattern_create_solid (red, green, blue);
- if (!gstate->pattern)
- return CAIRO_STATUS_NO_MEMORY;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_current_rgb_color (cairo_gstate_t *gstate, double *red, double *green, double *blue)
-{
- return _cairo_pattern_get_rgb (gstate->pattern, red, green, blue);
-}
-
-cairo_status_t
-_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance)
-{
- gstate->tolerance = tolerance;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-double
-_cairo_gstate_current_tolerance (cairo_gstate_t *gstate)
-{
- return gstate->tolerance;
-}
-
-cairo_status_t
-_cairo_gstate_set_alpha (cairo_gstate_t *gstate, double alpha)
-{
- gstate->alpha = alpha;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-double
-_cairo_gstate_current_alpha (cairo_gstate_t *gstate)
-{
- return gstate->alpha;
-}
-
-cairo_status_t
-_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule)
-{
- gstate->fill_rule = fill_rule;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_fill_rule_t
-_cairo_gstate_current_fill_rule (cairo_gstate_t *gstate)
-{
- return gstate->fill_rule;
-}
-
-cairo_status_t
-_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width)
-{
- gstate->line_width = width;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-double
-_cairo_gstate_current_line_width (cairo_gstate_t *gstate)
-{
- return gstate->line_width;
-}
-
-cairo_status_t
-_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap)
-{
- gstate->line_cap = line_cap;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_line_cap_t
-_cairo_gstate_current_line_cap (cairo_gstate_t *gstate)
-{
- return gstate->line_cap;
-}
-
-cairo_status_t
-_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join)
-{
- gstate->line_join = line_join;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_line_join_t
-_cairo_gstate_current_line_join (cairo_gstate_t *gstate)
-{
- return gstate->line_join;
-}
-
-cairo_status_t
-_cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, double offset)
-{
- if (gstate->dash) {
- free (gstate->dash);
- gstate->dash = NULL;
- }
-
- gstate->num_dashes = num_dashes;
- if (gstate->num_dashes) {
- gstate->dash = malloc (gstate->num_dashes * sizeof (double));
- if (gstate->dash == NULL) {
- gstate->num_dashes = 0;
- return CAIRO_STATUS_NO_MEMORY;
- }
- }
-
- memcpy (gstate->dash, dash, gstate->num_dashes * sizeof (double));
- gstate->dash_offset = offset;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit)
-{
- gstate->miter_limit = limit;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-double
-_cairo_gstate_current_miter_limit (cairo_gstate_t *gstate)
-{
- return gstate->miter_limit;
-}
-
-void
-_cairo_gstate_current_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix)
-{
- cairo_matrix_copy (matrix, &gstate->ctm);
-}
-
-cairo_status_t
-_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
-{
- cairo_matrix_t tmp;
-
- _cairo_gstate_unset_font (gstate);
-
- _cairo_matrix_set_translate (&tmp, tx, ty);
- cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
-
- _cairo_matrix_set_translate (&tmp, -tx, -ty);
- cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
-{
- cairo_matrix_t tmp;
-
- if (sx == 0 || sy == 0)
- return CAIRO_STATUS_INVALID_MATRIX;
-
- _cairo_gstate_unset_font (gstate);
-
- _cairo_matrix_set_scale (&tmp, sx, sy);
- cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
-
- _cairo_matrix_set_scale (&tmp, 1/sx, 1/sy);
- cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
-{
- cairo_matrix_t tmp;
-
- _cairo_gstate_unset_font (gstate);
-
- _cairo_matrix_set_rotate (&tmp, angle);
- cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
-
- _cairo_matrix_set_rotate (&tmp, -angle);
- cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_concat_matrix (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
-{
- cairo_matrix_t tmp;
-
- _cairo_gstate_unset_font (gstate);
-
- cairo_matrix_copy (&tmp, matrix);
- cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
-
- cairo_matrix_invert (&tmp);
- cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
-{
- cairo_status_t status;
-
- _cairo_gstate_unset_font (gstate);
-
- cairo_matrix_copy (&gstate->ctm, matrix);
-
- cairo_matrix_copy (&gstate->ctm_inverse, matrix);
- status = cairo_matrix_invert (&gstate->ctm_inverse);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_default_matrix (cairo_gstate_t *gstate)
-{
- int scale = gstate->pixels_per_inch / CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT + 0.5;
- if (scale == 0)
- scale = 1;
-
- _cairo_gstate_unset_font (gstate);
-
- cairo_matrix_set_identity (&gstate->font_matrix);
-
- cairo_matrix_set_identity (&gstate->ctm);
- cairo_matrix_scale (&gstate->ctm, scale, scale);
- cairo_matrix_copy (&gstate->ctm_inverse, &gstate->ctm);
- cairo_matrix_invert (&gstate->ctm_inverse);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
-{
- _cairo_gstate_unset_font (gstate);
-
- cairo_matrix_set_identity (&gstate->ctm);
- cairo_matrix_set_identity (&gstate->ctm_inverse);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_transform_point (cairo_gstate_t *gstate, double *x, double *y)
-{
- cairo_matrix_transform_point (&gstate->ctm, x, y);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy)
-{
- cairo_matrix_transform_distance (&gstate->ctm, dx, dy);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_inverse_transform_point (cairo_gstate_t *gstate, double *x, double *y)
-{
- cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy)
-{
- cairo_matrix_transform_distance (&gstate->ctm_inverse, dx, dy);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_new_path (cairo_gstate_t *gstate)
-{
- _cairo_path_fini (&gstate->path);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y)
-{
- cairo_point_t point;
-
- cairo_matrix_transform_point (&gstate->ctm, &x, &y);
-
- point.x = _cairo_fixed_from_double (x);
- point.y = _cairo_fixed_from_double (y);
-
- return _cairo_path_move_to (&gstate->path, &point);
-}
-
-cairo_status_t
-_cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y)
-{
- cairo_point_t point;
-
- cairo_matrix_transform_point (&gstate->ctm, &x, &y);
-
- point.x = _cairo_fixed_from_double (x);
- point.y = _cairo_fixed_from_double (y);
-
- return _cairo_path_line_to (&gstate->path, &point);
-}
-
-cairo_status_t
-_cairo_gstate_curve_to (cairo_gstate_t *gstate,
- double x0, double y0,
- double x1, double y1,
- double x2, double y2)
-{
- cairo_point_t p0, p1, p2;
-
- cairo_matrix_transform_point (&gstate->ctm, &x0, &y0);
- cairo_matrix_transform_point (&gstate->ctm, &x1, &y1);
- cairo_matrix_transform_point (&gstate->ctm, &x2, &y2);
-
- p0.x = _cairo_fixed_from_double (x0);
- p0.y = _cairo_fixed_from_double (y0);
-
- p1.x = _cairo_fixed_from_double (x1);
- p1.y = _cairo_fixed_from_double (y1);
-
- p2.x = _cairo_fixed_from_double (x2);
- p2.y = _cairo_fixed_from_double (y2);
-
- return _cairo_path_curve_to (&gstate->path, &p0, &p1, &p2);
-}
-
-/* Spline deviation from the circle in radius would be given by:
-
- error = sqrt (x**2 + y**2) - 1
-
- A simpler error function to work with is:
-
- e = x**2 + y**2 - 1
-
- From "Good approximation of circles by curvature-continuous Bezier
- curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric
- Design 8 (1990) 22-41, we learn:
-
- abs (max(e)) = 4/27 * sin**6(angle/4) / cos**2(angle/4)
-
- and
- abs (error) =~ 1/2 * e
-
- Of course, this error value applies only for the particular spline
- approximation that is used in _cairo_gstate_arc_segment.
-*/
-static double
-_arc_error_normalized (double angle)
-{
- return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
-}
-
-static double
-_arc_max_angle_for_tolerance_normalized (double tolerance)
-{
- double angle, error;
- int i;
-
- /* Use table lookup to reduce search time in most cases. */
- struct {
- double angle;
- double error;
- } table[] = {
- { M_PI / 1.0, 0.0185185185185185036127 },
- { M_PI / 2.0, 0.000272567143730179811158 },
- { M_PI / 3.0, 2.38647043651461047433e-05 },
- { M_PI / 4.0, 4.2455377443222443279e-06 },
- { M_PI / 5.0, 1.11281001494389081528e-06 },
- { M_PI / 6.0, 3.72662000942734705475e-07 },
- { M_PI / 7.0, 1.47783685574284411325e-07 },
- { M_PI / 8.0, 6.63240432022601149057e-08 },
- { M_PI / 9.0, 3.2715520137536980553e-08 },
- { M_PI / 10.0, 1.73863223499021216974e-08 },
- { M_PI / 11.0, 9.81410988043554039085e-09 },
- };
- int table_size = (sizeof (table) / sizeof (table[0]));
-
- for (i = 0; i < table_size; i++)
- if (table[i].error < tolerance)
- return table[i].angle;
-
- ++i;
- do {
- angle = M_PI / i++;
- error = _arc_error_normalized (angle);
- } while (error > tolerance);
-
- return angle;
-}
-
-static int
-_cairo_gstate_arc_segments_needed (cairo_gstate_t *gstate,
- double angle,
- double radius)
-{
- double l1, l2, lmax;
- double max_angle;
-
- _cairo_matrix_compute_eigen_values (&gstate->ctm, &l1, &l2);
-
- l1 = fabs (l1);
- l2 = fabs (l2);
- if (l1 > l2)
- lmax = l1;
- else
- lmax = l2;
-
- max_angle = _arc_max_angle_for_tolerance_normalized (gstate->tolerance / (radius * lmax));
-
- return (int) ceil (angle / max_angle);
-}
-
-/* We want to draw a single spline approximating a circular arc radius
- R from angle A to angle B. Since we want a symmetric spline that
- matches the endpoints of the arc in position and slope, we know
- that the spline control points must be:
-
- (R * cos(A), R * sin(A))
- (R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
- (R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
- (R * cos(B), R * sin(B))
-
- for some value of h.
-
- "Approximation of circular arcs by cubic poynomials", Michael
- Goldapp, Computer Aided Geometric Design 8 (1991) 227-238, provides
- various values of h along with error analysis for each.
-
- From that paper, a very practical value of h is:
-
- h = 4/3 * tan(angle/4)
-
- This value does not give the spline with minimal error, but it does
- provide a very good approximation, (6th-order convergence), and the
- error expression is quite simple, (see the comment for
- _arc_error_normalized).
-*/
-static cairo_status_t
-_cairo_gstate_arc_segment (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle_A, double angle_B)
-{
- cairo_status_t status;
- double r_sin_A, r_cos_A;
- double r_sin_B, r_cos_B;
- double h;
-
- r_sin_A = radius * sin (angle_A);
- r_cos_A = radius * cos (angle_A);
- r_sin_B = radius * sin (angle_B);
- r_cos_B = radius * cos (angle_B);
-
- h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
-
- status = _cairo_gstate_curve_to (gstate,
- xc + r_cos_A - h * r_sin_A, yc + r_sin_A + h * r_cos_A,
- xc + r_cos_B + h * r_sin_B, yc + r_sin_B - h * r_cos_B,
- xc + r_cos_B, yc + r_sin_B);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gstate_arc_dir (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle_min,
- double angle_max,
- cairo_direction_t dir)
-{
- cairo_status_t status;
-
- while (angle_max - angle_min > 4 * M_PI)
- angle_max -= 2 * M_PI;
-
- /* Recurse if drawing arc larger than pi */
- if (angle_max - angle_min > M_PI) {
- double angle_mid = angle_min + (angle_max - angle_min) / 2.0;
- /* XXX: Something tells me this block could be condensed. */
- if (dir == CAIRO_DIRECTION_FORWARD) {
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_min, angle_mid, dir);
- if (status)
- return status;
-
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_mid, angle_max, dir);
- if (status)
- return status;
- } else {
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_mid, angle_max, dir);
- if (status)
- return status;
-
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_min, angle_mid, dir);
- if (status)
- return status;
- }
- } else {
- int i, segments;
- double angle, angle_step;
-
- segments = _cairo_gstate_arc_segments_needed (gstate,
- angle_max - angle_min,
- radius);
- angle_step = (angle_max - angle_min) / (double) segments;
-
- if (dir == CAIRO_DIRECTION_FORWARD) {
- angle = angle_min;
- } else {
- angle = angle_max;
- angle_step = - angle_step;
- }
-
- for (i = 0; i < segments; i++, angle += angle_step) {
- _cairo_gstate_arc_segment (gstate,
- xc, yc,
- radius,
- angle,
- angle + angle_step);
- }
-
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_arc (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle1, double angle2)
-{
- cairo_status_t status;
-
- if (radius <= 0.0)
- return CAIRO_STATUS_SUCCESS;
-
- while (angle2 < angle1)
- angle2 += 2 * M_PI;
-
- status = _cairo_gstate_line_to (gstate,
- xc + radius * cos (angle1),
- yc + radius * sin (angle1));
- if (status)
- return status;
-
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle1, angle2, CAIRO_DIRECTION_FORWARD);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_arc_negative (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle1, double angle2)
-{
- cairo_status_t status;
-
- if (radius <= 0.0)
- return CAIRO_STATUS_SUCCESS;
-
- while (angle2 > angle1)
- angle2 -= 2 * M_PI;
-
- status = _cairo_gstate_line_to (gstate,
- xc + radius * cos (angle1),
- yc + radius * sin (angle1));
- if (status)
- return status;
-
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle2, angle1, CAIRO_DIRECTION_REVERSE);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* XXX: NYI
-cairo_status_t
-_cairo_gstate_arc_to (cairo_gstate_t *gstate,
- double x1, double y1,
- double x2, double y2,
- double radius)
-{
-
-}
-*/
-
-cairo_status_t
-_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy)
-{
- cairo_distance_t distance;
-
- cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
-
- distance.dx = _cairo_fixed_from_double (dx);
- distance.dy = _cairo_fixed_from_double (dy);
-
- return _cairo_path_rel_move_to (&gstate->path, &distance);
-}
-
-cairo_status_t
-_cairo_gstate_rel_line_to (cairo_gstate_t *gstate, double dx, double dy)
-{
- cairo_distance_t distance;
-
- cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
-
- distance.dx = _cairo_fixed_from_double (dx);
- distance.dy = _cairo_fixed_from_double (dy);
-
- return _cairo_path_rel_line_to (&gstate->path, &distance);
-}
-
-cairo_status_t
-_cairo_gstate_rel_curve_to (cairo_gstate_t *gstate,
- double dx0, double dy0,
- double dx1, double dy1,
- double dx2, double dy2)
-{
- cairo_distance_t distance[3];
-
- cairo_matrix_transform_distance (&gstate->ctm, &dx0, &dy0);
- cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1);
- cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
-
- distance[0].dx = _cairo_fixed_from_double (dx0);
- distance[0].dy = _cairo_fixed_from_double (dy0);
-
- distance[1].dx = _cairo_fixed_from_double (dx1);
- distance[1].dy = _cairo_fixed_from_double (dy1);
-
- distance[2].dx = _cairo_fixed_from_double (dx2);
- distance[2].dy = _cairo_fixed_from_double (dy2);
-
- return _cairo_path_rel_curve_to (&gstate->path,
- &distance[0],
- &distance[1],
- &distance[2]);
-}
-
-/* XXX: NYI
-cairo_status_t
-_cairo_gstate_stroke_path (cairo_gstate_t *gstate)
-{
- cairo_status_t status;
-
- _cairo_pen_init (&gstate);
- return CAIRO_STATUS_SUCCESS;
-}
-*/
-
-cairo_status_t
-_cairo_gstate_close_path (cairo_gstate_t *gstate)
-{
- return _cairo_path_close_path (&gstate->path);
-}
-
-cairo_status_t
-_cairo_gstate_current_point (cairo_gstate_t *gstate, double *x_ret, double *y_ret)
-{
- cairo_status_t status;
- cairo_point_t point;
- double x, y;
-
- status = _cairo_path_current_point (&gstate->path, &point);
- if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
- x = 0.0;
- y = 0.0;
- } else {
- x = _cairo_fixed_to_double (point.x);
- y = _cairo_fixed_to_double (point.y);
- cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y);
- }
-
- if (x_ret)
- *x_ret = x;
- if (y_ret)
- *y_ret = y;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-typedef struct gstate_path_interpreter {
- cairo_matrix_t ctm_inverse;
- double tolerance;
- cairo_point_t current_point;
-
- cairo_move_to_func_t *move_to;
- cairo_line_to_func_t *line_to;
- cairo_curve_to_func_t *curve_to;
- cairo_close_path_func_t *close_path;
-
- void *closure;
-} gpi_t;
-
-static cairo_status_t
-_gpi_move_to (void *closure, cairo_point_t *point)
-{
- gpi_t *gpi = closure;
- double x, y;
-
- x = _cairo_fixed_to_double (point->x);
- y = _cairo_fixed_to_double (point->y);
-
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
-
- gpi->move_to (gpi->closure, x, y);
- gpi->current_point = *point;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_gpi_line_to (void *closure, cairo_point_t *point)
-{
- gpi_t *gpi = closure;
- double x, y;
-
- x = _cairo_fixed_to_double (point->x);
- y = _cairo_fixed_to_double (point->y);
-
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
-
- gpi->line_to (gpi->closure, x, y);
- gpi->current_point = *point;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_gpi_curve_to (void *closure,
- cairo_point_t *p1,
- cairo_point_t *p2,
- cairo_point_t *p3)
-{
- gpi_t *gpi = closure;
- cairo_status_t status;
- cairo_spline_t spline;
- double x1, y1, x2, y2, x3, y3;
-
- if (gpi->curve_to) {
- x1 = _cairo_fixed_to_double (p1->x);
- y1 = _cairo_fixed_to_double (p1->y);
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x1, &y1);
-
- x2 = _cairo_fixed_to_double (p2->x);
- y2 = _cairo_fixed_to_double (p2->y);
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x2, &y2);
-
- x3 = _cairo_fixed_to_double (p3->x);
- y3 = _cairo_fixed_to_double (p3->y);
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x3, &y3);
-
- gpi->curve_to (gpi->closure, x1, y1, x2, y2, x3, y3);
- } else {
- cairo_point_t *p0 = &gpi->current_point;
- int i;
- double x, y;
-
- status = _cairo_spline_init (&spline, p0, p1, p2, p3);
- if (status == CAIRO_INT_STATUS_DEGENERATE)
- return CAIRO_STATUS_SUCCESS;
-
- status = _cairo_spline_decompose (&spline, gpi->tolerance);
- if (status)
- return status;
-
- for (i=1; i < spline.num_points; i++) {
- x = _cairo_fixed_to_double (spline.points[i].x);
- y = _cairo_fixed_to_double (spline.points[i].y);
-
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
-
- gpi->line_to (gpi->closure, x, y);
- }
- }
-
- gpi->current_point = *p3;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_gpi_close_path (void *closure)
-{
- gpi_t *gpi = closure;
-
- gpi->close_path (gpi->closure);
-
- gpi->current_point.x = 0;
- gpi->current_point.y = 0;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* It's OK for curve_path to be NULL. In that case, all curves in the
- path will be decomposed into one or more calls to the line_to
- function, (according to the current tolerance). */
-cairo_status_t
-_cairo_gstate_interpret_path (cairo_gstate_t *gstate,
- cairo_move_to_func_t *move_to,
- cairo_line_to_func_t *line_to,
- cairo_curve_to_func_t *curve_to,
- cairo_close_path_func_t *close_path,
- void *closure)
-{
- cairo_path_t path;
- gpi_t gpi;
-
- /* Anything we want from gstate must be copied. We must not retain
- pointers into gstate. */
- _cairo_path_init_copy (&path, &gstate->path);
-
- cairo_matrix_copy (&gpi.ctm_inverse, &gstate->ctm_inverse);
- gpi.tolerance = gstate->tolerance;
-
- gpi.move_to = move_to;
- gpi.line_to = line_to;
- gpi.curve_to = curve_to;
- gpi.close_path = close_path;
- gpi.closure = closure;
-
- gpi.current_point.x = 0;
- gpi.current_point.y = 0;
-
- return _cairo_path_interpret (&path,
- CAIRO_DIRECTION_FORWARD,
- _gpi_move_to,
- _gpi_line_to,
- _gpi_curve_to,
- _gpi_close_path,
- &gpi);
-}
-
-/* XXX: gstate->alpha will be going away before too long, and when it
- * does, it may make sense for this function to just disappear.
- */
-static void
-_cairo_gstate_pattern_init_copy (cairo_gstate_t *gstate,
- cairo_pattern_union_t *pattern,
- cairo_pattern_t *src)
-{
- _cairo_pattern_init_copy (&pattern->base, src);
- _cairo_pattern_transform (&pattern->base, &gstate->ctm_inverse);
- _cairo_pattern_set_alpha (&pattern->base, gstate->alpha);
-}
-
-cairo_status_t
-_cairo_gstate_stroke (cairo_gstate_t *gstate)
-{
- cairo_status_t status;
- cairo_traps_t traps;
-
- if (gstate->line_width <= 0.0)
- return CAIRO_STATUS_SUCCESS;
-
- _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate);
-
- _cairo_traps_init (&traps);
-
- status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
- if (status) {
- _cairo_traps_fini (&traps);
- return status;
- }
-
- _cairo_gstate_clip_and_composite_trapezoids (gstate,
- gstate->pattern,
- gstate->operator,
- gstate->surface,
- &traps);
-
- _cairo_traps_fini (&traps);
-
- _cairo_gstate_new_path (gstate);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
- double x,
- double y,
- cairo_bool_t *inside_ret)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_traps_t traps;
-
- cairo_matrix_transform_point (&gstate->ctm, &x, &y);
-
- _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate);
-
- _cairo_traps_init (&traps);
-
- status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
- if (status)
- goto BAIL;
-
- *inside_ret = _cairo_traps_contain (&traps, x, y);
-
-BAIL:
- _cairo_traps_fini (&traps);
-
- return status;
-}
-
-/* XXX We currently have a confusing mix of boxes and rectangles as
- * exemplified by this function. A cairo_box_t is a rectangular area
- * represented by the coordinates of the upper left and lower right
- * corners, expressed in fixed point numbers. A cairo_rectangle_t is
- * also a rectangular area, but represented by the upper left corner
- * and the width and the height, as integer numbers.
- *
- * This function converts a cairo_box_t to a cairo_rectangle_t by
- * increasing the area to the nearest integer coordinates. We should
- * standardize on cairo_rectangle_t and cairo_rectangle_fixed_t, and
- * this function could be renamed to the more reasonable
- * _cairo_rectangle_fixed_round.
- */
-
-static void
-_cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_t *rectangle)
-{
- rectangle->x = _cairo_fixed_integer_floor (box->p1.x);
- rectangle->y = _cairo_fixed_integer_floor (box->p1.y);
- rectangle->width = _cairo_fixed_integer_ceil (box->p2.x) - rectangle->x;
- rectangle->height = _cairo_fixed_integer_ceil (box->p2.y) - rectangle->y;
-}
-
-static void
-_cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src)
-{
- int x1, y1, x2, y2;
-
- x1 = MAX (dest->x, src->x);
- y1 = MAX (dest->y, src->y);
- x2 = MIN (dest->x + dest->width, src->x + src->width);
- y2 = MIN (dest->y + dest->height, src->y + src->height);
-
- if (x1 >= x2 || y1 >= y2) {
- dest->x = 0;
- dest->y = 0;
- dest->width = 0;
- dest->height = 0;
- } else {
- dest->x = x1;
- dest->y = y1;
- dest->width = x2 - x1;
- dest->height = y2 - y1;
- }
-}
-
-static int
-_cairo_rectangle_empty (cairo_rectangle_t *rect)
-{
- return rect->width == 0 || rect->height == 0;
-}
-
-static void
-translate_traps (cairo_traps_t *traps, int x, int y)
-{
- cairo_fixed_t xoff, yoff;
- cairo_trapezoid_t *t;
- int i;
-
- /* Ugh. The cairo_composite/(Render) interface doesn't allow
- an offset for the trapezoids. Need to manually shift all
- the coordinates to align with the offset origin of the
- intermediate surface. */
-
- xoff = _cairo_fixed_from_int (x);
- yoff = _cairo_fixed_from_int (y);
-
- for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) {
- t->top += yoff;
- t->bottom += yoff;
- t->left.p1.x += xoff;
- t->left.p1.y += yoff;
- t->left.p2.x += xoff;
- t->left.p2.y += yoff;
- t->right.p1.x += xoff;
- t->right.p1.y += yoff;
- t->right.p2.x += xoff;
- t->right.p2.y += yoff;
- }
-}
-
-
-/* Warning: This call modifies the coordinates of traps */
-static cairo_status_t
-_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
- cairo_pattern_t *src,
- cairo_operator_t operator,
- cairo_surface_t *dst,
- cairo_traps_t *traps)
-{
- cairo_status_t status;
- cairo_pattern_union_t pattern;
- cairo_rectangle_t extents;
- cairo_box_t trap_extents;
-
- if (traps->num_traps == 0)
- return CAIRO_STATUS_SUCCESS;
-
- if (gstate->surface == NULL)
- return CAIRO_STATUS_NO_TARGET_SURFACE;
-
- _cairo_traps_extents (traps, &trap_extents);
- _cairo_box_round_to_rectangle (&trap_extents, &extents);
-
- if (gstate->clip.surface) {
- cairo_surface_t *intermediate;
- cairo_surface_pattern_t intermediate_pattern;
- cairo_color_t empty_color;
-
- _cairo_rectangle_intersect (&extents, &gstate->clip.rect);
-
- if (_cairo_rectangle_empty (&extents)) {
- status = CAIRO_STATUS_SUCCESS;
- goto BAIL1;
- }
-
- translate_traps (traps, -extents.x, -extents.y);
-
- _cairo_color_init (&empty_color);
- _cairo_color_set_alpha (&empty_color, 0.);
- intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
- CAIRO_FORMAT_A8,
- extents.width,
- extents.height,
- &empty_color);
- if (intermediate == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL1;
- }
-
- _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
-
- status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
- &pattern.base,
- intermediate,
- extents.x, extents.y,
- 0, 0,
- extents.width,
- extents.height,
- traps->traps,
- traps->num_traps);
- _cairo_pattern_fini (&pattern.base);
-
- if (status)
- goto BAIL2;
-
-
- _cairo_pattern_init_for_surface (&pattern.surface,
- gstate->clip.surface);
-
- status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- &pattern.base,
- NULL,
- intermediate,
- extents.x - gstate->clip.rect.x,
- extents.y - gstate->clip.rect.y,
- 0, 0,
- 0, 0,
- extents.width, extents.height);
- _cairo_pattern_fini (&pattern.base);
-
- if (status)
- goto BAIL2;
-
- _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
- _cairo_gstate_pattern_init_copy (gstate, &pattern, src);
-
- status = _cairo_surface_composite (operator,
- &pattern.base,
- &intermediate_pattern.base,
- dst,
- extents.x, extents.y,
- 0, 0,
- extents.x, extents.y,
- extents.width, extents.height);
-
- _cairo_pattern_fini (&pattern.base);
- _cairo_pattern_fini (&intermediate_pattern.base);
-
- BAIL2:
- cairo_surface_destroy (intermediate);
- BAIL1:
-
- if (status)
- return status;
-
- } else {
- if (gstate->clip.region) {
- pixman_box16_t box;
- pixman_box16_t *intersection_extents;
- pixman_region16_t *rect, *intersection;
-
- box.x1 = _cairo_fixed_integer_floor (trap_extents.p1.x);
- box.y1 = _cairo_fixed_integer_floor (trap_extents.p1.y);
- box.x2 = _cairo_fixed_integer_ceil (trap_extents.p2.x);
- box.y2 = _cairo_fixed_integer_ceil (trap_extents.p2.y);
-
- rect = pixman_region_create_simple (&box);
- if (rect == NULL)
- goto bail1;
- intersection = pixman_region_create();
- if (intersection == NULL)
- goto bail2;
-
- if (pixman_region_intersect (intersection, gstate->clip.region,
- rect) != PIXMAN_REGION_STATUS_SUCCESS)
- goto bail3;
- intersection_extents = pixman_region_extents (intersection);
-
- extents.x = intersection_extents->x1;
- extents.y = intersection_extents->y1;
- extents.width = intersection_extents->x2 - intersection_extents->x1;
- extents.height = intersection_extents->y2 - intersection_extents->y1;
- bail3:
- pixman_region_destroy (intersection);
- bail2:
- pixman_region_destroy (rect);
- bail1:
- ;
- }
-
- _cairo_gstate_pattern_init_copy (gstate, &pattern, src);
-
- status = _cairo_surface_composite_trapezoids (gstate->operator,
- &pattern.base, dst,
- extents.x, extents.y,
- extents.x, extents.y,
- extents.width,
- extents.height,
- traps->traps,
- traps->num_traps);
-
- _cairo_pattern_fini (&pattern.base);
-
- if (status)
- return status;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_fill (cairo_gstate_t *gstate)
-{
- cairo_status_t status;
- cairo_traps_t traps;
-
- _cairo_traps_init (&traps);
-
- status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
- if (status) {
- _cairo_traps_fini (&traps);
- return status;
- }
-
- _cairo_gstate_clip_and_composite_trapezoids (gstate,
- gstate->pattern,
- gstate->operator,
- gstate->surface,
- &traps);
-
- _cairo_traps_fini (&traps);
-
- _cairo_gstate_new_path (gstate);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_in_fill (cairo_gstate_t *gstate,
- double x,
- double y,
- cairo_bool_t *inside_ret)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_traps_t traps;
-
- cairo_matrix_transform_point (&gstate->ctm, &x, &y);
-
- _cairo_traps_init (&traps);
-
- status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
- if (status)
- goto BAIL;
-
- *inside_ret = _cairo_traps_contain (&traps, x, y);
-
-BAIL:
- _cairo_traps_fini (&traps);
-
- return status;
-}
-
-cairo_status_t
-_cairo_gstate_copy_page (cairo_gstate_t *gstate)
-{
- if (gstate->surface == NULL)
- return CAIRO_STATUS_NO_TARGET_SURFACE;
-
- return _cairo_surface_copy_page (gstate->surface);
-}
-
-cairo_status_t
-_cairo_gstate_show_page (cairo_gstate_t *gstate)
-{
- if (gstate->surface == NULL)
- return CAIRO_STATUS_NO_TARGET_SURFACE;
-
- return _cairo_surface_show_page (gstate->surface);
-}
-
-cairo_status_t
-_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
- double *x1, double *y1,
- double *x2, double *y2)
-{
- cairo_status_t status;
- cairo_traps_t traps;
- cairo_box_t extents;
-
- _cairo_traps_init (&traps);
-
- status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
- if (status)
- goto BAIL;
-
- _cairo_traps_extents (&traps, &extents);
-
- *x1 = _cairo_fixed_to_double (extents.p1.x);
- *y1 = _cairo_fixed_to_double (extents.p1.y);
- *x2 = _cairo_fixed_to_double (extents.p2.x);
- *y2 = _cairo_fixed_to_double (extents.p2.y);
-
- cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1);
- cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2);
-
-BAIL:
- _cairo_traps_fini (&traps);
-
- return status;
-}
-
-cairo_status_t
-_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
- double *x1, double *y1,
- double *x2, double *y2)
-{
- cairo_status_t status;
- cairo_traps_t traps;
- cairo_box_t extents;
-
- _cairo_traps_init (&traps);
-
- status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
- if (status)
- goto BAIL;
-
- _cairo_traps_extents (&traps, &extents);
-
- *x1 = _cairo_fixed_to_double (extents.p1.x);
- *y1 = _cairo_fixed_to_double (extents.p1.y);
- *x2 = _cairo_fixed_to_double (extents.p2.x);
- *y2 = _cairo_fixed_to_double (extents.p2.y);
-
- cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1);
- cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2);
-
-BAIL:
- _cairo_traps_fini (&traps);
-
- return status;
-}
-
-cairo_status_t
-_cairo_gstate_init_clip (cairo_gstate_t *gstate)
-{
- /* destroy any existing clip-region artifacts */
- if (gstate->clip.surface)
- cairo_surface_destroy (gstate->clip.surface);
- gstate->clip.surface = NULL;
-
- if (gstate->clip.region)
- pixman_region_destroy (gstate->clip.region);
- gstate->clip.region = NULL;
-
- /* reset the surface's clip to the whole surface */
- if (gstate->surface)
- _cairo_surface_set_clip_region (gstate->surface,
- gstate->clip.region);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static int
-extract_transformed_rectangle(cairo_matrix_t *mat,
- cairo_traps_t *tr,
- pixman_box16_t *box)
-{
- double a, b, c, d, tx, ty;
- cairo_status_t st;
-
- st = cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
- if (!(st == CAIRO_STATUS_SUCCESS && b == 0. && c == 0.))
- return 0;
-
- if (tr->num_traps == 1
- && tr->traps[0].left.p1.x == tr->traps[0].left.p2.x
- && tr->traps[0].right.p1.x == tr->traps[0].right.p2.x
- && tr->traps[0].left.p1.y == tr->traps[0].right.p1.y
- && tr->traps[0].left.p2.y == tr->traps[0].right.p2.y
- && _cairo_fixed_is_integer(tr->traps[0].left.p1.x)
- && _cairo_fixed_is_integer(tr->traps[0].left.p1.y)
- && _cairo_fixed_is_integer(tr->traps[0].left.p2.x)
- && _cairo_fixed_is_integer(tr->traps[0].left.p2.y)
- && _cairo_fixed_is_integer(tr->traps[0].right.p1.x)
- && _cairo_fixed_is_integer(tr->traps[0].right.p1.y)
- && _cairo_fixed_is_integer(tr->traps[0].right.p2.x)
- && _cairo_fixed_is_integer(tr->traps[0].right.p2.y)) {
-
- box->x1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.x);
- box->x2 = (short) _cairo_fixed_integer_part(tr->traps[0].right.p1.x);
- box->y1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.y);
- box->y2 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p2.y);
- return 1;
- }
- return 0;
-}
-
-/* Reset surface clip region to the one in the gstate */
-cairo_status_t
-_cairo_gstate_restore_external_state (cairo_gstate_t *gstate)
-{
- cairo_status_t status;
-
- status = CAIRO_STATUS_SUCCESS;
-
- if (gstate->surface)
- status = _cairo_surface_set_clip_region (gstate->surface,
- gstate->clip.region);
-
- /* If not supported we're already using surface clipping */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
- status = CAIRO_STATUS_SUCCESS;
-
- return status;
-}
-
-cairo_status_t
-_cairo_gstate_clip (cairo_gstate_t *gstate)
-{
- cairo_status_t status;
- cairo_pattern_union_t pattern;
- cairo_traps_t traps;
- cairo_color_t white_color;
- cairo_box_t extents;
- pixman_box16_t box;
-
- /* Fill the clip region as traps. */
-
- _cairo_traps_init (&traps);
- status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
- if (status) {
- _cairo_traps_fini (&traps);
- return status;
- }
-
- /* Check to see if we can represent these traps as a PixRegion. */
-
- if (extract_transformed_rectangle (&gstate->ctm, &traps, &box)) {
-
- pixman_region16_t *rect = NULL;
- pixman_region16_t *intersection = NULL;
-
- status = CAIRO_STATUS_SUCCESS;
- rect = pixman_region_create_simple (&box);
-
- if (rect == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
-
- } else {
-
- if (gstate->clip.region == NULL) {
- gstate->clip.region = rect;
- } else {
- intersection = pixman_region_create();
- if (pixman_region_intersect (intersection,
- gstate->clip.region, rect)
- == PIXMAN_REGION_STATUS_SUCCESS) {
- pixman_region_destroy (gstate->clip.region);
- gstate->clip.region = intersection;
- } else {
- status = CAIRO_STATUS_NO_MEMORY;
- }
- pixman_region_destroy (rect);
- }
-
- if (!status)
- status = _cairo_surface_set_clip_region (gstate->surface,
- gstate->clip.region);
- }
-
- if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
- _cairo_traps_fini (&traps);
- return status;
- }
-
- /* Fall through as status == CAIRO_INT_STATUS_UNSUPPORTED
- means that backend doesn't support clipping regions and
- mask surface clipping should be used instead. */
- }
-
- /* Otherwise represent the clip as a mask surface. */
-
- _cairo_color_init (&white_color);
-
- if (gstate->clip.surface == NULL) {
- _cairo_traps_extents (&traps, &extents);
- _cairo_box_round_to_rectangle (&extents, &gstate->clip.rect);
- gstate->clip.surface =
- _cairo_surface_create_similar_solid (gstate->surface,
- CAIRO_FORMAT_A8,
- gstate->clip.rect.width,
- gstate->clip.rect.height,
- &white_color);
- if (gstate->clip.surface == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- translate_traps (&traps, -gstate->clip.rect.x, -gstate->clip.rect.y);
- _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
-
- status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
- &pattern.base,
- gstate->clip.surface,
- 0, 0,
- 0, 0,
- gstate->clip.rect.width,
- gstate->clip.rect.height,
- traps.traps,
- traps.num_traps);
-
- _cairo_pattern_fini (&pattern.base);
-
- _cairo_traps_fini (&traps);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_show_surface (cairo_gstate_t *gstate,
- cairo_surface_t *surface,
- int width,
- int height)
-{
-
- /* We are dealing with 6 coordinate spaces in this function. this makes
- * it ugly.
- *
- * - "Image" space is the space of the surface we're reading pixels from.
- * it is the surface argument to this function. The surface has a
- * matrix attached to it which maps "user" space (see below) into
- * image space.
- *
- * - "Device" space is the space of the surface we're ultimately writing
- * pixels to. It is the current surface of the gstate argument to
- * this function.
- *
- * - "User" space is an arbitrary space defined by the user, defined
- * implicitly by the gstate's CTM. The CTM maps from user space to
- * device space. The CTM inverse (which is also kept at all times)
- * maps from device space to user space.
- *
- * - "Clip" space is the space of the surface being used to clip pixels
- * during compositing. Space-wise, it is a bounding box (offset+size)
- * within device space. This surface is usually smaller than the device
- * surface (and possibly the image surface too) and logically occupies
- * a bounding box around the "clip path", situated somewhere in device
- * space. The clip path is already painted on the clip surface.
- *
- * - "Intermediate" space is the subset of the Clip space that the
- * drawing will affect, and we allocate an intermediate surface
- * of this size so that we can paint in it.
- *
- * - "Pattern" space is another arbitrary space defined in the pattern
- * element of gstate. As pixels are read from image space, they are
- * combined with pixels being read from pattern space and pixels
- * already existing in device space. User coordinates are converted
- * to pattern space, similarly, using a matrix attached to the pattern.
- * (in fact, there is a 7th space in here, which is the space of the
- * surface acting as a source for the pattern)
- *
- * To composite these spaces, we temporarily change the image surface
- * so that it can be read and written in device coordinates; in a sense
- * this makes it "spatially compatible" with the clip and device spaces.
- *
- *
- * There is also some confusion about the interaction between a clip and
- * a pattern; it is assumed that in this "show surface" operation a pattern
- * is to be used as an auxiliary alpha mask. this might be wrong, but it's
- * what we're doing now.
- *
- * so, to follow the operations below, remember that in the compositing
- * model, each operation is always of the form ((src IN mask) OP dst).
- * that's the basic operation.
- *
- * so the compositing we are trying to do here, in general, involves 2
- * steps, going via a temporary surface:
- *
- * - combining clip and pattern pixels together into a mask channel.
- * this will be ((pattern IN clip) SRC temporary). it ignores the
- * pixels already in the temporary, overwriting it with the
- * pattern, clipped to the clip mask.
- *
- * - combining temporary and "image" pixels with "device" pixels,
- * with a user-provided porter/duff operator. this will be
- * ((image IN temporary) OP device).
- *
- * if there is no clip, the degenerate case is just the second step
- * with pattern standing in for temporary.
- *
- */
-
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_matrix_t image_to_user, image_to_device;
- double device_x, device_y;
- double device_width, device_height;
- cairo_surface_pattern_t pattern;
- cairo_box_t pattern_extents;
- cairo_rectangle_t extents;
-
- cairo_surface_get_matrix (surface, &image_to_user);
- cairo_matrix_invert (&image_to_user);
- cairo_matrix_multiply (&image_to_device, &image_to_user, &gstate->ctm);
-
- _cairo_gstate_current_point (gstate, &device_x, &device_y);
- device_width = width;
- device_height = height;
- _cairo_matrix_transform_bounding_box (&image_to_device,
- &device_x, &device_y,
- &device_width, &device_height);
-
- _cairo_pattern_init_for_surface (&pattern, surface);
-
- /* inherit surface attributes while surface attribute functions still
- exist */
- pattern.base.matrix = surface->matrix;
- pattern.base.filter = surface->filter;
- if (surface->repeat)
- pattern.base.extend = CAIRO_EXTEND_REPEAT;
- else
- pattern.base.extend = CAIRO_EXTEND_NONE;
-
- _cairo_pattern_transform (&pattern.base, &gstate->ctm_inverse);
- _cairo_pattern_set_alpha (&pattern.base, gstate->alpha);
-
- pattern_extents.p1.x = _cairo_fixed_from_double (device_x);
- pattern_extents.p1.y = _cairo_fixed_from_double (device_y);
- pattern_extents.p2.x = _cairo_fixed_from_double (device_x + device_width);
- pattern_extents.p2.y = _cairo_fixed_from_double (device_y + device_height);
- _cairo_box_round_to_rectangle (&pattern_extents, &extents);
-
- if (gstate->clip.surface)
- {
- _cairo_rectangle_intersect (&extents, &gstate->clip.rect);
-
- /* We only need to composite if the rectangle is not empty. */
- if (!_cairo_rectangle_empty (&extents)) {
- cairo_surface_pattern_t clip_pattern;
-
- _cairo_pattern_init_for_surface (&clip_pattern,
- gstate->clip.surface);
-
- status = _cairo_surface_composite (gstate->operator,
- &pattern.base,
- &clip_pattern.base,
- gstate->surface,
- extents.x, extents.y,
- 0, 0,
- extents.x, extents.y,
- extents.width, extents.height);
-
- _cairo_pattern_fini (&clip_pattern.base);
- }
- }
- else
- {
- /* XXX: The rendered size is sometimes 1 or 2 pixels short
- * from what I expect. Need to fix this.
- * KRH: I'm guessing this was due to rounding error when
- * passing double coordinates for integer arguments. Using
- * the extents rectangle should fix this, since it's properly
- * rounded. Is this still the case?
- */
- status = _cairo_surface_composite (gstate->operator,
- &pattern.base,
- NULL,
- gstate->surface,
- extents.x, extents.y,
- 0, 0,
- extents.x, extents.y,
- extents.width, extents.height);
-
- }
-
- _cairo_pattern_fini (&pattern.base);
-
- return status;
-}
-
-static void
-_cairo_gstate_unset_font (cairo_gstate_t *gstate)
-{
- if (gstate->font) {
- cairo_font_destroy (gstate->font);
- gstate->font = NULL;
- }
-}
-
-cairo_status_t
-_cairo_gstate_select_font (cairo_gstate_t *gstate,
- const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight)
-{
- char *new_family;
-
- new_family = strdup (family);
- if (!new_family)
- return CAIRO_STATUS_NO_MEMORY;
-
- _cairo_gstate_unset_font (gstate);
-
- gstate->font_family = new_family;
- gstate->font_slant = slant;
- gstate->font_weight = weight;
-
- cairo_matrix_set_identity (&gstate->font_matrix);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_scale_font (cairo_gstate_t *gstate,
- double scale)
-{
- _cairo_gstate_unset_font (gstate);
-
- return cairo_matrix_scale (&gstate->font_matrix, scale, scale);
-}
-
-cairo_status_t
-_cairo_gstate_transform_font (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
-{
- cairo_matrix_t tmp;
- double a, b, c, d, tx, ty;
-
- _cairo_gstate_unset_font (gstate);
-
- cairo_matrix_get_affine (matrix, &a, &b, &c, &d, &tx, &ty);
- cairo_matrix_set_affine (&tmp, a, b, c, d, 0, 0);
- return cairo_matrix_multiply (&gstate->font_matrix, &gstate->font_matrix, &tmp);
-}
-
-
-cairo_status_t
-_cairo_gstate_current_font (cairo_gstate_t *gstate,
- cairo_font_t **font)
-{
- cairo_status_t status;
-
- status = _cairo_gstate_ensure_font (gstate);
- if (status)
- return status;
-
- *font = gstate->font;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_gstate_set_font_transform (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
-{
- _cairo_gstate_unset_font (gstate);
-
- cairo_matrix_copy (&gstate->font_matrix, matrix);
-}
-
-void
-_cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
-{
- cairo_matrix_copy (matrix, &gstate->font_matrix);
-}
-
-/*
- * Like everything else in this file, fonts involve Too Many Coordinate Spaces;
- * it is easy to get confused about what's going on.
- *
- * The user's view
- * ---------------
- *
- * Users ask for things in user space. When cairo starts, a user space unit
- * is about 1/96 inch, which is similar to (but importantly different from)
- * the normal "point" units most users think in terms of. When a user
- * selects a font, its scale is set to "one user unit". The user can then
- * independently scale the user coordinate system *or* the font matrix, in
- * order to adjust the rendered size of the font.
- *
- * The only font type exposed to the user is cairo_font_t which is a
- * a font specialized to a particular scale matrix, CTM, and target
- * surface. The user is responsible for not using a cairo_font_t
- * after changing the parameters; doing so will produce garbled metrics.
- *
- *
- * The font's view
- * ---------------
- *
- * Fonts are designed and stored (in say .ttf files) in "font space", which
- * describes an "EM Square" (a design tile) and has some abstract number
- * such as 1000, 1024, or 2048 units per "EM". This is basically an
- * uninteresting space for us, but we need to remember that it exists.
- *
- * Font resources (from libraries or operating systems) render themselves
- * to a particular device. Since they do not want to make most programmers
- * worry about the font design space, the scaling API is simplified to
- * involve just telling the font the required pixel size of the EM square
- * (that is, in device space).
- *
- *
- * Cairo's gstate view
- * -------------------
- *
- * In addition to the CTM and CTM inverse, we keep a matrix in the gstate
- * called the "font matrix" which describes the user's most recent
- * font-scaling or font-transforming request. This is kept in terms of an
- * abstract scale factor, composed with the CTM and used to set the font's
- * pixel size. So if the user asks to "scale the font by 12", the matrix
- * is:
- *
- * [ 12.0, 0.0, 0.0, 12.0, 0.0, 0.0 ]
- *
- * It is an affine matrix, like all cairo matrices, but its tx and ty
- * components are always set to zero; we don't permit "nudging" fonts
- * around.
- *
- * In order to perform any action on a font, we must build an object
- * called a cairo_font_scale_t; this contains the central 2x2 matrix
- * resulting from "font matrix * CTM".
- *
- * We pass this to the font when making requests of it, which causes it to
- * reply for a particular [user request, device] combination, under the CTM
- * (to accomodate the "zoom in" == "bigger fonts" issue above).
- *
- * The other terms in our communication with the font are therefore in
- * device space. When we ask it to perform text->glyph conversion, it will
- * produce a glyph string in device space. Glyph vectors we pass to it for
- * measuring or rendering should be in device space. The metrics which we
- * get back from the font will be in device space. The contents of the
- * global glyph image cache will be in device space.
- *
- *
- * Cairo's public view
- * -------------------
- *
- * Since the values entering and leaving via public API calls are in user
- * space, the gstate functions typically need to multiply argumens by the
- * CTM (for user-input glyph vectors), and return values by the CTM inverse
- * (for font responses such as metrics or glyph vectors).
- *
- */
-
-void
-_cairo_gstate_current_font_scale (cairo_gstate_t *gstate,
- cairo_font_scale_t *sc)
-{
- cairo_matrix_t tmp;
- double dummy;
- cairo_matrix_multiply (&tmp, &gstate->font_matrix, &gstate->ctm);
- cairo_matrix_get_affine (&tmp,
- &sc->matrix[0][0],
- &sc->matrix[0][1],
- &sc->matrix[1][0],
- &sc->matrix[1][1],
- &dummy, &dummy);
-}
-
-static cairo_status_t
-_cairo_gstate_ensure_font (cairo_gstate_t *gstate)
-{
- cairo_font_scale_t sc;
- cairo_status_t status;
- const char *family;
-
- if (gstate->font)
- return CAIRO_STATUS_SUCCESS;
-
- _cairo_gstate_current_font_scale (gstate, &sc);
-
- if (gstate->font_family)
- family = gstate->font_family;
- else
- family = CAIRO_FONT_FAMILY_DEFAULT;
-
- status = _cairo_font_create (family,
- gstate->font_slant,
- gstate->font_weight,
- &sc,
- &gstate->font);
-
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
- cairo_font_extents_t *extents)
-{
- cairo_status_t status = _cairo_gstate_ensure_font (gstate);
- if (status)
- return status;
-
- return cairo_font_extents (gstate->font,
- &gstate->font_matrix,
- extents);
-}
-
-cairo_status_t
-_cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *nglyphs)
-{
- cairo_status_t status;
-
- cairo_point_t point;
- double origin_x, origin_y;
- int i;
-
- status = _cairo_gstate_ensure_font (gstate);
- if (status)
- return status;
-
- status = _cairo_path_current_point (&gstate->path, &point);
- if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
- origin_x = 0.0;
- origin_y = 0.0;
- } else {
- origin_x = _cairo_fixed_to_double (point.x);
- origin_y = _cairo_fixed_to_double (point.y);
- cairo_matrix_transform_point (&gstate->ctm_inverse,
- &origin_x, &origin_y);
- }
-
- status = _cairo_font_text_to_glyphs (gstate->font,
- utf8, glyphs, nglyphs);
-
- if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs))
- return status;
-
- /* The font responded in glyph space, starting from (0,0). Convert to
- user space by applying the font transform, then add any current point
- offset. */
-
- for (i = 0; i < *nglyphs; ++i) {
- cairo_matrix_transform_point (&gstate->font_matrix,
- &((*glyphs)[i].x),
- &((*glyphs)[i].y));
- (*glyphs)[i].x += origin_x;
- (*glyphs)[i].y += origin_y;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_set_font (cairo_gstate_t *gstate,
- cairo_font_t *font)
-{
- if (font != gstate->font) {
- if (gstate->font)
- cairo_font_destroy (gstate->font);
- gstate->font = font;
- if (gstate->font)
- cairo_font_reference (gstate->font);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
-{
- cairo_status_t status;
-
- status = _cairo_gstate_ensure_font (gstate);
- if (status)
- return status;
-
- cairo_font_glyph_extents (gstate->font,
- &gstate->font_matrix,
- glyphs, num_glyphs,
- extents);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
- cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_status_t status;
- int i;
- cairo_glyph_t *transformed_glyphs = NULL;
- cairo_pattern_union_t pattern;
- cairo_box_t bbox;
- cairo_rectangle_t extents;
-
- status = _cairo_gstate_ensure_font (gstate);
- if (status)
- return status;
-
- transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
- if (transformed_glyphs == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- for (i = 0; i < num_glyphs; ++i)
- {
- transformed_glyphs[i] = glyphs[i];
- cairo_matrix_transform_point (&gstate->ctm,
- &transformed_glyphs[i].x,
- &transformed_glyphs[i].y);
- }
-
- status = _cairo_font_glyph_bbox (gstate->font,
- transformed_glyphs, num_glyphs,
- &bbox);
- _cairo_box_round_to_rectangle (&bbox, &extents);
-
- if (status)
- goto CLEANUP_GLYPHS;
-
- if (gstate->clip.surface)
- {
- cairo_surface_t *intermediate;
- cairo_surface_pattern_t intermediate_pattern;
- cairo_color_t empty_color;
-
- _cairo_rectangle_intersect (&extents, &gstate->clip.rect);
-
- /* Shortcut if empty */
- if (_cairo_rectangle_empty (&extents)) {
- status = CAIRO_STATUS_SUCCESS;
- goto BAIL1;
- }
-
- _cairo_color_init (&empty_color);
- _cairo_color_set_alpha (&empty_color, .0);
- intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
- CAIRO_FORMAT_A8,
- extents.width,
- extents.height,
- &empty_color);
- if (intermediate == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL1;
- }
-
- /* move the glyphs again, from dev space to intermediate space */
- for (i = 0; i < num_glyphs; ++i)
- {
- transformed_glyphs[i].x -= extents.x;
- transformed_glyphs[i].y -= extents.y;
- }
-
- _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
-
- status = _cairo_font_show_glyphs (gstate->font,
- CAIRO_OPERATOR_ADD,
- &pattern.base, intermediate,
- extents.x, extents.y,
- 0, 0,
- extents.width, extents.height,
- transformed_glyphs, num_glyphs);
-
- _cairo_pattern_fini (&pattern.base);
-
- if (status)
- goto BAIL2;
-
- _cairo_pattern_init_for_surface (&pattern.surface,
- gstate->clip.surface);
-
- status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- &pattern.base,
- NULL,
- intermediate,
- extents.x - gstate->clip.rect.x,
- extents.y - gstate->clip.rect.y,
- 0, 0,
- 0, 0,
- extents.width, extents.height);
-
- _cairo_pattern_fini (&pattern.base);
-
- if (status)
- goto BAIL2;
-
- _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
- _cairo_gstate_pattern_init_copy (gstate, &pattern, gstate->pattern);
-
- status = _cairo_surface_composite (gstate->operator,
- &pattern.base,
- &intermediate_pattern.base,
- gstate->surface,
- extents.x, extents.y,
- 0, 0,
- extents.x, extents.y,
- extents.width, extents.height);
- _cairo_pattern_fini (&pattern.base);
- _cairo_pattern_fini (&intermediate_pattern.base);
-
- BAIL2:
- cairo_surface_destroy (intermediate);
- BAIL1:
- ;
- }
- else
- {
- _cairo_gstate_pattern_init_copy (gstate, &pattern, gstate->pattern);
-
- status = _cairo_font_show_glyphs (gstate->font,
- gstate->operator, &pattern.base,
- gstate->surface,
- extents.x, extents.y,
- extents.x, extents.y,
- extents.width, extents.height,
- transformed_glyphs, num_glyphs);
-
- _cairo_pattern_fini (&pattern.base);
- }
-
- CLEANUP_GLYPHS:
- free (transformed_glyphs);
-
- return status;
-}
-
-cairo_status_t
-_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
- cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_status_t status;
- int i;
- cairo_glyph_t *transformed_glyphs = NULL;
-
- transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
- if (transformed_glyphs == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- for (i = 0; i < num_glyphs; ++i)
- {
- transformed_glyphs[i] = glyphs[i];
- cairo_matrix_transform_point (&gstate->ctm,
- &(transformed_glyphs[i].x),
- &(transformed_glyphs[i].y));
- }
-
- status = _cairo_font_glyph_path (gstate->font,
- transformed_glyphs, num_glyphs,
- &gstate->path);
-
- free (transformed_glyphs);
- return status;
-}
diff --git a/src/cairo_hull.c b/src/cairo_hull.c
deleted file mode 100644
index c93d70625..000000000
--- a/src/cairo_hull.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2003 University of Southern California
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#include "cairoint.h"
-
-typedef struct cairo_hull
-{
- cairo_point_t point;
- cairo_slope_t slope;
- int discard;
-} cairo_hull_t;
-
-static cairo_hull_t *
-_cairo_hull_create (cairo_pen_vertex_t *vertices, int num_vertices)
-{
- int i;
- cairo_hull_t *hull;
- cairo_point_t *p, *extremum, tmp;
-
- extremum = &vertices[0].point;
- for (i = 1; i < num_vertices; i++) {
- p = &vertices[i].point;
- if (p->y < extremum->y || (p->y == extremum->y && p->x < extremum->x))
- extremum = p;
- }
- /* Put the extremal point at the beginning of the array */
- tmp = *extremum;
- *extremum = vertices[0].point;
- vertices[0].point = tmp;
-
- hull = malloc (num_vertices * sizeof (cairo_hull_t));
- if (hull == NULL)
- return NULL;
-
- for (i = 0; i < num_vertices; i++) {
- hull[i].point = vertices[i].point;
- _cairo_slope_init (&hull[i].slope, &hull[0].point, &hull[i].point);
-
- /* Discard all points coincident with the extremal point */
- if (i != 0 && hull[i].slope.dx == 0 && hull[i].slope.dy == 0)
- hull[i].discard = 1;
- else
- hull[i].discard = 0;
- }
-
- return hull;
-}
-
-static int
-_cairo_hull_vertex_compare (const void *av, const void *bv)
-{
- cairo_hull_t *a = (cairo_hull_t *) av;
- cairo_hull_t *b = (cairo_hull_t *) bv;
- int ret;
-
- ret = _cairo_slope_compare (&a->slope, &b->slope);
-
- /* In the case of two vertices with identical slope from the
- extremal point discard the nearer point. */
-
- if (ret == 0) {
- cairo_fixed_48_16_t a_dist, b_dist;
- a_dist = ((cairo_fixed_48_16_t) a->slope.dx * a->slope.dx +
- (cairo_fixed_48_16_t) a->slope.dy * a->slope.dy);
- b_dist = ((cairo_fixed_48_16_t) b->slope.dx * b->slope.dx +
- (cairo_fixed_48_16_t) b->slope.dy * b->slope.dy);
- if (a_dist < b_dist) {
- a->discard = 1;
- ret = -1;
- } else {
- b->discard = 1;
- ret = 1;
- }
- }
-
- return ret;
-}
-
-static int
-_cairo_hull_prev_valid (cairo_hull_t *hull, int num_hull, int index)
-{
- do {
- /* hull[0] is always valid, so don't test and wraparound */
- index--;
- } while (hull[index].discard);
-
- return index;
-}
-
-static int
-_cairo_hull_next_valid (cairo_hull_t *hull, int num_hull, int index)
-{
- do {
- index = (index + 1) % num_hull;
- } while (hull[index].discard);
-
- return index;
-}
-
-static cairo_status_t
-_cairo_hull_eliminate_concave (cairo_hull_t *hull, int num_hull)
-{
- int i, j, k;
- cairo_slope_t slope_ij, slope_jk;
-
- i = 0;
- j = _cairo_hull_next_valid (hull, num_hull, i);
- k = _cairo_hull_next_valid (hull, num_hull, j);
-
- do {
- _cairo_slope_init (&slope_ij, &hull[i].point, &hull[j].point);
- _cairo_slope_init (&slope_jk, &hull[j].point, &hull[k].point);
-
- /* Is the angle formed by ij and jk concave? */
- if (_cairo_slope_compare (&slope_ij, &slope_jk) >= 0) {
- if (i == k)
- return CAIRO_STATUS_SUCCESS;
- hull[j].discard = 1;
- j = i;
- i = _cairo_hull_prev_valid (hull, num_hull, j);
- } else {
- i = j;
- j = k;
- k = _cairo_hull_next_valid (hull, num_hull, j);
- }
- } while (j != 0);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_hull_to_pen (cairo_hull_t *hull, cairo_pen_vertex_t *vertices, int *num_vertices)
-{
- int i, j = 0;
-
- for (i = 0; i < *num_vertices; i++) {
- if (hull[i].discard)
- continue;
- vertices[j++].point = hull[i].point;
- }
-
- *num_vertices = j;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* Given a set of vertices, compute the convex hull using the Graham
- scan algorithm. */
-cairo_status_t
-_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices)
-{
- cairo_hull_t *hull;
- int num_hull = *num_vertices;
-
- hull = _cairo_hull_create (vertices, num_hull);
- if (hull == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- qsort (hull + 1, num_hull - 1,
- sizeof (cairo_hull_t), _cairo_hull_vertex_compare);
-
- _cairo_hull_eliminate_concave (hull, num_hull);
-
- _cairo_hull_to_pen (hull, vertices, num_vertices);
-
- free (hull);
-
- return CAIRO_STATUS_SUCCESS;
-}
diff --git a/src/cairo_image_surface.c b/src/cairo_image_surface.c
deleted file mode 100644
index 9745b3150..000000000
--- a/src/cairo_image_surface.c
+++ /dev/null
@@ -1,675 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2003 University of Southern California
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#include "cairoint.h"
-
-static const cairo_surface_backend_t cairo_image_surface_backend;
-
-static int
-_cairo_format_bpp (cairo_format_t format)
-{
- switch (format) {
- case CAIRO_FORMAT_A1:
- return 1;
- case CAIRO_FORMAT_A8:
- return 8;
- case CAIRO_FORMAT_RGB24:
- case CAIRO_FORMAT_ARGB32:
- default:
- return 32;
- }
-}
-
-static cairo_image_surface_t *
-_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
- cairo_format_t format)
-{
- cairo_image_surface_t *surface;
-
- surface = malloc (sizeof (cairo_image_surface_t));
- if (surface == NULL)
- return NULL;
-
- _cairo_surface_init (&surface->base, &cairo_image_surface_backend);
-
- surface->pixman_image = pixman_image;
-
- surface->format = format;
- surface->data = (char *) pixman_image_get_data (pixman_image);
- surface->owns_data = 0;
-
- surface->width = pixman_image_get_width (pixman_image);
- surface->height = pixman_image_get_height (pixman_image);
- surface->stride = pixman_image_get_stride (pixman_image);
- surface->depth = pixman_image_get_depth (pixman_image);
-
- return surface;
-}
-
-cairo_image_surface_t *
-_cairo_image_surface_create_with_masks (char *data,
- cairo_format_masks_t *format,
- int width,
- int height,
- int stride)
-{
- cairo_image_surface_t *surface;
- pixman_format_t *pixman_format;
- pixman_image_t *pixman_image;
-
- pixman_format = pixman_format_create_masks (format->bpp,
- format->alpha_mask,
- format->red_mask,
- format->green_mask,
- format->blue_mask);
-
- if (pixman_format == NULL)
- return NULL;
-
- pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format,
- width, height, format->bpp, stride);
-
- pixman_format_destroy (pixman_format);
-
- if (pixman_image == NULL)
- return NULL;
-
- surface = _cairo_image_surface_create_for_pixman_image (pixman_image,
- (cairo_format_t)-1);
-
- return surface;
-}
-
-static pixman_format_t *
-_create_pixman_format (cairo_format_t format)
-{
- switch (format) {
- case CAIRO_FORMAT_A1:
- return pixman_format_create (PIXMAN_FORMAT_NAME_A1);
- break;
- case CAIRO_FORMAT_A8:
- return pixman_format_create (PIXMAN_FORMAT_NAME_A8);
- break;
- case CAIRO_FORMAT_RGB24:
- return pixman_format_create (PIXMAN_FORMAT_NAME_RGB24);
- break;
- case CAIRO_FORMAT_ARGB32:
- default:
- return pixman_format_create (PIXMAN_FORMAT_NAME_ARGB32);
- break;
- }
-}
-
-/**
- * cairo_image_surface_create:
- * @format: format of pixels in the surface to create
- * @width: width of the surface, in pixels
- * @height: height of the surface, in pixels
- *
- * Creates an image surface of the specified format and
- * dimensions. The initial contents of the surface is undefined; you
- * must explicitely clear the buffer, using, for example,
- * cairo_rectangle() and cairo_fill() if you want it cleared.
- *
- * Return value: the newly created surface, or %NULL if it couldn't
- * be created because of lack of memory
- **/
-cairo_surface_t *
-cairo_image_surface_create (cairo_format_t format,
- int width,
- int height)
-{
- cairo_image_surface_t *surface;
- pixman_format_t *pixman_format;
- pixman_image_t *pixman_image;
-
- pixman_format = _create_pixman_format (format);
- if (pixman_format == NULL)
- return NULL;
-
- pixman_image = pixman_image_create (pixman_format, width, height);
-
- pixman_format_destroy (pixman_format);
-
- if (pixman_image == NULL)
- return NULL;
-
- surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format);
-
- return &surface->base;
-}
-
-/**
- * cairo_image_surface_create_for_data:
- * @data: a pointer to a buffer supplied by the application
- * in which to write contents.
- * @format: the format of pixels in the buffer
- * @width: the width of the image to be stored in the buffer
- * @height: the height of the image to be stored in the buffer
- * @stride: the number of bytes between the start of rows
- * in the buffer. Having this be specified separate from @width
- * allows for padding at the end of rows, or for writing
- * to a subportion of a larger image.
- *
- * Creates an image surface for the provided pixel data. The output
- * buffer must be kept around until the #cairo_surface_t is destroyed
- * or cairo_surface_finish() is called on the surface. The initial
- * contents of @buffer will be used as the inital image contents; you
- * must explicitely clear the buffer, using, for example,
- * cairo_rectangle() and cairo_fill() if you want it cleared.
- *
- * Return value: the newly created surface, or %NULL if it couldn't
- * be created because of lack of memory
- **/
-cairo_surface_t *
-cairo_image_surface_create_for_data (char *data,
- cairo_format_t format,
- int width,
- int height,
- int stride)
-{
- cairo_image_surface_t *surface;
- pixman_format_t *pixman_format;
- pixman_image_t *pixman_image;
-
- pixman_format = _create_pixman_format (format);
- if (pixman_format == NULL)
- return NULL;
-
- pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format,
- width, height,
- _cairo_format_bpp (format),
- stride);
-
- pixman_format_destroy (pixman_format);
-
- if (pixman_image == NULL)
- return NULL;
-
- surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format);
-
- return &surface->base;
-}
-
-static cairo_surface_t *
-_cairo_image_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- return cairo_image_surface_create (format, width, height);
-}
-
-static void
-_cairo_image_abstract_surface_destroy (void *abstract_surface)
-{
- cairo_image_surface_t *surface = abstract_surface;
-
- if (surface->pixman_image)
- pixman_image_destroy (surface->pixman_image);
-
- if (surface->owns_data) {
- free (surface->data);
- surface->data = NULL;
- }
-
- free (surface);
-}
-
-void
-_cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface)
-{
- surface->owns_data = 1;
-}
-
-static double
-_cairo_image_surface_pixels_per_inch (void *abstract_surface)
-{
- /* XXX: We'll want a way to let the user set this. */
- return 96.0;
-}
-
-static cairo_status_t
-_cairo_image_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- *image_out = abstract_surface;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_image_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_image_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect_out,
- void **image_extra)
-{
- cairo_image_surface_t *surface = abstract_surface;
-
- image_rect_out->x = 0;
- image_rect_out->y = 0;
- image_rect_out->width = surface->width;
- image_rect_out->height = surface->height;
-
- *image_out = surface;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_image_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_image_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- cairo_image_surface_t *surface = abstract_surface;
-
- if (src->backend == surface->base.backend) {
- *clone_out = src;
- cairo_surface_reference (src);
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-cairo_status_t
-_cairo_image_surface_set_matrix (cairo_image_surface_t *surface,
- cairo_matrix_t *matrix)
-{
- pixman_transform_t pixman_transform;
-
- pixman_transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
- pixman_transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
- pixman_transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
-
- pixman_transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
- pixman_transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
- pixman_transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
-
- pixman_transform.matrix[2][0] = 0;
- pixman_transform.matrix[2][1] = 0;
- pixman_transform.matrix[2][2] = _cairo_fixed_from_double (1);
-
- pixman_image_set_transform (surface->pixman_image, &pixman_transform);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t filter)
-{
- pixman_filter_t pixman_filter;
-
- switch (filter) {
- case CAIRO_FILTER_FAST:
- pixman_filter = PIXMAN_FILTER_FAST;
- break;
- case CAIRO_FILTER_GOOD:
- pixman_filter = PIXMAN_FILTER_GOOD;
- break;
- case CAIRO_FILTER_BEST:
- pixman_filter = PIXMAN_FILTER_BEST;
- break;
- case CAIRO_FILTER_NEAREST:
- pixman_filter = PIXMAN_FILTER_NEAREST;
- break;
- case CAIRO_FILTER_BILINEAR:
- pixman_filter = PIXMAN_FILTER_BILINEAR;
- break;
- default:
- pixman_filter = PIXMAN_FILTER_BEST;
- }
-
- pixman_image_set_filter (surface->pixman_image, pixman_filter);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat)
-{
- pixman_image_set_repeat (surface->pixman_image, repeat);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_set_attributes (cairo_image_surface_t *surface,
- cairo_surface_attributes_t *attributes)
-{
- cairo_int_status_t status;
-
- status = _cairo_image_surface_set_matrix (surface, &attributes->matrix);
- if (status)
- return status;
-
- switch (attributes->extend) {
- case CAIRO_EXTEND_NONE:
- _cairo_image_surface_set_repeat (surface, 0);
- break;
- case CAIRO_EXTEND_REPEAT:
- _cairo_image_surface_set_repeat (surface, 1);
- break;
- case CAIRO_EXTEND_REFLECT:
- /* XXX: Obviously wrong. */
- _cairo_image_surface_set_repeat (surface, 1);
- break;
- }
-
- status = _cairo_image_surface_set_filter (surface, attributes->filter);
-
- return status;
-}
-
-static pixman_operator_t
-_pixman_operator (cairo_operator_t operator)
-{
- switch (operator) {
- case CAIRO_OPERATOR_CLEAR:
- return PIXMAN_OPERATOR_CLEAR;
- case CAIRO_OPERATOR_SRC:
- return PIXMAN_OPERATOR_SRC;
- case CAIRO_OPERATOR_DST:
- return PIXMAN_OPERATOR_DST;
- case CAIRO_OPERATOR_OVER:
- return PIXMAN_OPERATOR_OVER;
- case CAIRO_OPERATOR_OVER_REVERSE:
- return PIXMAN_OPERATOR_OVER_REVERSE;
- case CAIRO_OPERATOR_IN:
- return PIXMAN_OPERATOR_IN;
- case CAIRO_OPERATOR_IN_REVERSE:
- return PIXMAN_OPERATOR_IN_REVERSE;
- case CAIRO_OPERATOR_OUT:
- return PIXMAN_OPERATOR_OUT;
- case CAIRO_OPERATOR_OUT_REVERSE:
- return PIXMAN_OPERATOR_OUT_REVERSE;
- case CAIRO_OPERATOR_ATOP:
- return PIXMAN_OPERATOR_ATOP;
- case CAIRO_OPERATOR_ATOP_REVERSE:
- return PIXMAN_OPERATOR_ATOP_REVERSE;
- case CAIRO_OPERATOR_XOR:
- return PIXMAN_OPERATOR_XOR;
- case CAIRO_OPERATOR_ADD:
- return PIXMAN_OPERATOR_ADD;
- case CAIRO_OPERATOR_SATURATE:
- return PIXMAN_OPERATOR_SATURATE;
- default:
- return PIXMAN_OPERATOR_OVER;
- }
-}
-
-static cairo_int_status_t
-_cairo_image_surface_composite (cairo_operator_t operator,
- cairo_pattern_t *src_pattern,
- cairo_pattern_t *mask_pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- cairo_surface_attributes_t src_attr, mask_attr;
- cairo_image_surface_t *dst = abstract_dst;
- cairo_image_surface_t *src;
- cairo_image_surface_t *mask;
- cairo_int_status_t status;
-
- status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
- &dst->base,
- src_x, src_y,
- mask_x, mask_y,
- width, height,
- (cairo_surface_t **) &src,
- (cairo_surface_t **) &mask,
- &src_attr, &mask_attr);
- if (status)
- return status;
-
- status = _cairo_image_surface_set_attributes (src, &src_attr);
- if (CAIRO_OK (status))
- {
- if (mask)
- {
- status = _cairo_image_surface_set_attributes (mask, &mask_attr);
- if (CAIRO_OK (status))
- pixman_composite (_pixman_operator (operator),
- src->pixman_image,
- mask->pixman_image,
- dst->pixman_image,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- mask_x + mask_attr.x_offset,
- mask_y + mask_attr.y_offset,
- dst_x, dst_y,
- width, height);
- }
- else
- {
- pixman_composite (_pixman_operator (operator),
- src->pixman_image,
- NULL,
- dst->pixman_image,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- 0, 0,
- dst_x, dst_y,
- width, height);
- }
- }
-
- if (mask)
- _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr);
-
- _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_fill_rectangles (void *abstract_surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- cairo_image_surface_t *surface = abstract_surface;
-
- pixman_color_t pixman_color;
-
- pixman_color.red = color->red_short;
- pixman_color.green = color->green_short;
- pixman_color.blue = color->blue_short;
- pixman_color.alpha = color->alpha_short;
-
- /* XXX: The pixman_rectangle_t cast is evil... it needs to go away somehow. */
- pixman_fill_rectangles (_pixman_operator(operator), surface->pixman_image,
- &pixman_color, (pixman_rectangle_t *) rects, num_rects);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- cairo_surface_attributes_t attributes;
- cairo_image_surface_t *dst = abstract_dst;
- cairo_image_surface_t *src;
- cairo_int_status_t status;
- int render_reference_x, render_reference_y;
- int render_src_x, render_src_y;
-
- status = _cairo_pattern_acquire_surface (pattern, &dst->base,
- src_x, src_y, width, height,
- (cairo_surface_t **) &src,
- &attributes);
- if (status)
- return status;
-
- if (traps[0].left.p1.y < traps[0].left.p2.y) {
- render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
- render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
- } else {
- render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
- render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
- }
-
- render_src_x = src_x + render_reference_x - dst_x;
- render_src_y = src_y + render_reference_y - dst_y;
-
- /* XXX: The pixman_trapezoid_t cast is evil and needs to go away
- * somehow. */
- status = _cairo_image_surface_set_attributes (src, &attributes);
- if (CAIRO_OK (status))
- pixman_composite_trapezoids (operator,
- src->pixman_image,
- dst->pixman_image,
- render_src_x + attributes.x_offset,
- render_src_y + attributes.y_offset,
- (pixman_trapezoid_t *) traps, num_traps);
-
- _cairo_pattern_release_surface (&dst->base, &src->base, &attributes);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_copy_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_image_abstract_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface;
-
- return _cairo_image_surface_set_clip_region (surface, region);
-}
-
-cairo_int_status_t
-_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
- pixman_region16_t *region)
-{
- if (region) {
- pixman_region16_t *rcopy;
-
- rcopy = pixman_region_create();
- /* pixman_image_set_clip_region expects to take ownership of the
- * passed-in region, so we create a copy to give it. */
- /* XXX: I think that's probably a bug in pixman. But its
- * memory management issues need auditing anyway, so a
- * workaround like this is fine for now. */
- pixman_region_copy (rcopy, region);
- pixman_image_set_clip_region (surface->pixman_image, rcopy);
- } else {
- pixman_image_set_clip_region (surface->pixman_image, region);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/**
- * _cairo_surface_is_image:
- * @surface: a #cairo_surface_t
- *
- * Checks if a surface is an #cairo_image_surface_t
- *
- * Return value: True if the surface is an image surface
- **/
-int
-_cairo_surface_is_image (cairo_surface_t *surface)
-{
- return surface->backend == &cairo_image_surface_backend;
-}
-
-static const cairo_surface_backend_t cairo_image_surface_backend = {
- _cairo_image_surface_create_similar,
- _cairo_image_abstract_surface_destroy,
- _cairo_image_surface_pixels_per_inch,
- _cairo_image_surface_acquire_source_image,
- _cairo_image_surface_release_source_image,
- _cairo_image_surface_acquire_dest_image,
- _cairo_image_surface_release_dest_image,
- _cairo_image_surface_clone_similar,
- _cairo_image_surface_composite,
- _cairo_image_surface_fill_rectangles,
- _cairo_image_surface_composite_trapezoids,
- _cairo_image_surface_copy_page,
- _cairo_image_surface_show_page,
- _cairo_image_abstract_surface_set_clip_region,
- NULL /* show_glyphs */
-};
diff --git a/src/cairo_matrix.c b/src/cairo_matrix.c
deleted file mode 100644
index 88e536e8a..000000000
--- a/src/cairo_matrix.c
+++ /dev/null
@@ -1,645 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2002 University of Southern California
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#define _GNU_SOURCE
-#include <stdlib.h>
-#include <math.h>
-
-#include "cairoint.h"
-
-static cairo_matrix_t const 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_create:
- *
- * Creates a new identity matrix.
- *
- * Return value: a newly created matrix; free with cairo_matrix_destroy(),
- * or %NULL if memory couldn't be allocated.
- **/
-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 */
-}
-
-/**
- * cairo_matrix_destroy:
- * @matrix: a #cairo_matrix_t
- *
- * Frees a matrix created with cairo_matrix_create.
- **/
-void
-cairo_matrix_destroy (cairo_matrix_t *matrix)
-{
- _cairo_matrix_fini (matrix);
- free (matrix);
-}
-
-/**
- * cairo_matrix_copy:
- * @matrix: a #cairo_matrix_t
- * @other: another #cairo_
- *
- * Modifies @matrix to be identical to @other.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-cairo_status_t
-cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other)
-{
- *matrix = *other;
-
- return CAIRO_STATUS_SUCCESS;
-}
-slim_hidden_def(cairo_matrix_copy);
-
-/**
- * cairo_matrix_set_identity:
- * @matrix: a #cairo_matrix_t
- *
- * Modifies @matrix to be an identity transformation.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-cairo_status_t
-cairo_matrix_set_identity (cairo_matrix_t *matrix)
-{
- *matrix = CAIRO_MATRIX_IDENTITY;
-
- return CAIRO_STATUS_SUCCESS;
-}
-slim_hidden_def(cairo_matrix_set_identity);
-
-/**
- * cairo_matrix_set_affine:
- * @matrix: a cairo_matrix_t
- * @a: a component of the affine transformation
- * @b: b component of the affine transformation
- * @c: c component of the affine transformation
- * @d: d component of the affine transformation
- * @tx: X translation component of the affine transformation
- * @ty: Y translation component of the affine transformation
- *
- * Sets @matrix to be the affine transformation given by
- * @a, b, @c, @d, @tx, @ty. The transformation is given
- * by:
- * <programlisting>
- * x_new = x * a + y * c + tx;
- * y_new = x * b + y * d + ty;
- * </programlisting>
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-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;
-}
-slim_hidden_def(cairo_matrix_set_affine);
-
-/**
- * cairo_matrix_get_affine:
- * @matrix: a @cairo_matrix_t
- * @a: location to store a component of affine transformation, or %NULL
- * @b: location to store b component of affine transformation, or %NULL
- * @c: location to store c component of affine transformation, or %NULL
- * @d: location to store d component of affine transformation, or %NULL
- * @tx: location to store X-translation component of affine transformation, or %NULL
- * @ty: location to store Y-translation component of affine transformation, or %NULL
- *
- * Gets the matrix values for the affine tranformation that @matrix represents.
- * See cairo_matrix_set_affine().
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-cairo_status_t
-cairo_matrix_get_affine (cairo_matrix_t *matrix,
- double *a, double *b,
- double *c, double *d,
- double *tx, double *ty)
-{
- if (a)
- *a = matrix->m[0][0];
- if (b)
- *b = matrix->m[0][1];
-
- if (c)
- *c = matrix->m[1][0];
- if (d)
- *d = matrix->m[1][1];
-
- if (tx)
- *tx = matrix->m[2][0];
- if (ty)
- *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_matrix_translate:
- * @matrix: a cairo_matrix_t
- * @tx: amount to rotate in the X direction
- * @ty: amount to rotate in the Y direction
- *
- * Applies a translation by @tx, @ty to the transformation in
- * @matrix. The new transformation is given by first translating by
- * @tx, @ty then applying the original transformation
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-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_matrix_scale:
- * @matrix: a #cairo_matrix_t
- * @sx: Scale factor in the X direction
- * @sy: Scale factor in the Y direction
- *
- * Applies scaling by @tx, @ty to the transformation in
- * @matrix. The new transformation is given by first scaling by @sx
- * and @sy then applying the original transformation
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-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);
-}
-slim_hidden_def(cairo_matrix_scale);
-
-cairo_status_t
-_cairo_matrix_set_rotate (cairo_matrix_t *matrix,
- double radians)
-{
- double s;
- double c;
-#if HAVE_SINCOS
- sincos (radians, &s, &c);
-#else
- s = sin (radians);
- c = cos (radians);
-#endif
- return cairo_matrix_set_affine (matrix,
- c, s,
- -s, c,
- 0, 0);
-}
-
-/**
- * cairo_matrix_rotate:
- * @matrix: a @cairo_matrix_t
- * @radians: angle of rotation, in radians. Angles are defined
- * so that an angle of 90 degrees (%M_PI radians) rotates the
- * positive X axis into the positive Y axis. With the default
- * Cairo choice of axis orientation, positive rotations are
- * clockwise.
- *
- * Applies rotation by @radians to the transformation in
- * @matrix. The new transformation is given by first rotating by
- * @radians then applying the original transformation
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-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_matrix_multiply:
- * @result: a @cairo_matrix_t in which to store the result
- * @a: a @cairo_matrix_t
- * @b: a @cairo_matrix_t
- *
- * Multiplies the affine transformations in @a and @b together
- * and stores the result in @result. The resulting transformation
- * is given by first applying the transformation in @b then
- * applying the transformation in @a.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-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;
-}
-slim_hidden_def(cairo_matrix_multiply);
-
-/**
- * cairo_matrix_transform_distance:
- * @matrix: a @cairo_matrix_t
- * @dx: a distance in the X direction. An in/out parameter
- * @dy: a distance in the Y direction. An in/out parameter
- *
- * Transforms the vector (@dx,@dy) by @matrix. Translation is
- * ignored. In terms of the components of the affine transformation:
- *
- * <programlisting>
- * dx2 = dx1 * a + dy1 * c;
- * dy2 = dx1 * b + dy1 * d;
- * </programlisting>
- *
- * Affine transformations are position invariant, so the same vector
- * always transforms to the same vector. If (@x1,@y1) transforms
- * to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to
- * (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-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;
-}
-slim_hidden_def(cairo_matrix_transform_distance);
-
-/**
- * cairo_matrix_transform_point:
- * @matrix: a @cairo_matrix_t
- * @x: X position. An in/out parameter
- * @y: Y position. An in/out parameter
- *
- * Transforms the point (@x, @y) by @matrix.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-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;
-}
-slim_hidden_def(cairo_matrix_transform_point);
-
-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_matrix_invert:
- * @matrix: a @cairo_matrix_t
- *
- * Changes @matrix to be the inverse of it's original value. Not
- * all transformation matrices have inverses; if the matrix
- * collapses points together (it is <firstterm>degenerate</firstterm>),
- * then it has no inverse and this function will fail.
- *
- * Returns: If @matrix has an inverse, modifies @matrix to
- * be the inverse matrix and returns %CAIRO_STATUS_SUCCESS. Otherwise,
- * returns %CAIRO_STATUS_INVALID_MATRIX.
- **/
-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;
-}
-slim_hidden_def(cairo_matrix_invert);
-
-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;
-}
-
-/* Compute the amount that each basis vector is scaled by. */
-cairo_status_t
-_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy, int x_major)
-{
- double det;
-
- _cairo_matrix_compute_determinant (matrix, &det);
-
- if (det == 0)
- *sx = *sy = 0;
- else
- {
- double x = x_major != 0;
- double y = x == 0;
- double major, minor;
-
- cairo_matrix_transform_distance (matrix, &x, &y);
- major = sqrt(x*x + y*y);
- /*
- * ignore mirroring
- */
- if (det < 0)
- det = -det;
- if (major)
- minor = det / major;
- else
- minor = 0.0;
- if (x_major)
- {
- *sx = major;
- *sy = minor;
- }
- else
- {
- *sx = minor;
- *sy = major;
- }
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_bool_t
-_cairo_matrix_is_integer_translation(cairo_matrix_t *mat,
- int *itx, int *ity)
-{
- double a, b, c, d, tx, ty;
- int ttx, tty;
- int ok = 0;
- cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
- ttx = _cairo_fixed_from_double (tx);
- tty = _cairo_fixed_from_double (ty);
- ok = ((a == 1.0)
- && (b == 0.0)
- && (c == 0.0)
- && (d == 1.0)
- && (_cairo_fixed_is_integer(ttx))
- && (_cairo_fixed_is_integer(tty)));
- if (ok) {
- *itx = _cairo_fixed_integer_part(ttx);
- *ity = _cairo_fixed_integer_part(tty);
- return TRUE;
- }
- return FALSE;
-}
diff --git a/src/cairo_path.c b/src/cairo_path.c
deleted file mode 100644
index 8314f601c..000000000
--- a/src/cairo_path.c
+++ /dev/null
@@ -1,495 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2002 University of Southern California
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#include <stdlib.h>
-#include "cairoint.h"
-
-/* private functions */
-static cairo_status_t
-_cairo_path_add (cairo_path_t *path, cairo_path_op_t op, cairo_point_t *points, 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_t 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, cairo_point_t *points, int num_points);
-
-void
-_cairo_path_init (cairo_path_t *path)
-{
- path->op_head = NULL;
- path->op_tail = NULL;
-
- path->arg_head = NULL;
- path->arg_tail = NULL;
-
- path->current_point.x = 0;
- path->current_point.y = 0;
- path->has_current_point = 0;
- path->last_move_point = path->current_point;
-}
-
-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);
- path->current_point = other->current_point;
- path->has_current_point = other->has_current_point;
- path->last_move_point = other->last_move_point;
-
- for (other_op = other->op_head; other_op; other_op = other_op->next) {
- op = _cairo_path_op_buf_create ();
- if (op == NULL) {
- _cairo_path_fini(path);
- 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) {
- _cairo_path_fini(path);
- 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;
-
- path->has_current_point = 0;
-}
-
-cairo_status_t
-_cairo_path_move_to (cairo_path_t *path, cairo_point_t *point)
-{
- cairo_status_t status;
-
- status = _cairo_path_add (path, CAIRO_PATH_OP_MOVE_TO, point, 1);
- if (status)
- return status;
-
- path->current_point = *point;
- path->has_current_point = 1;
- path->last_move_point = path->current_point;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_path_rel_move_to (cairo_path_t *path, cairo_distance_t *distance)
-{
- cairo_point_t point;
-
- point.x = path->current_point.x + distance->dx;
- point.y = path->current_point.y + distance->dy;
-
- return _cairo_path_move_to (path, &point);
-}
-
-cairo_status_t
-_cairo_path_line_to (cairo_path_t *path, cairo_point_t *point)
-{
- cairo_status_t status;
-
- status = _cairo_path_add (path, CAIRO_PATH_OP_LINE_TO, point, 1);
- if (status)
- return status;
-
- path->current_point = *point;
- path->has_current_point = 1;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_path_rel_line_to (cairo_path_t *path, cairo_distance_t *distance)
-{
- cairo_point_t point;
-
- point.x = path->current_point.x + distance->dx;
- point.y = path->current_point.y + distance->dy;
-
- return _cairo_path_line_to (path, &point);
-}
-
-cairo_status_t
-_cairo_path_curve_to (cairo_path_t *path,
- cairo_point_t *p0,
- cairo_point_t *p1,
- cairo_point_t *p2)
-{
- cairo_status_t status;
- cairo_point_t point[3];
-
- point[0] = *p0;
- point[1] = *p1;
- point[2] = *p2;
-
- status = _cairo_path_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
- if (status)
- return status;
-
- path->current_point = *p2;
- path->has_current_point = 1;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_path_rel_curve_to (cairo_path_t *path,
- cairo_distance_t *d0,
- cairo_distance_t *d1,
- cairo_distance_t *d2)
-{
- cairo_point_t p0, p1, p2;
-
- p0.x = path->current_point.x + d0->dx;
- p0.y = path->current_point.y + d0->dy;
-
- p1.x = path->current_point.x + d1->dx;
- p1.y = path->current_point.y + d1->dy;
-
- p2.x = path->current_point.x + d2->dx;
- p2.y = path->current_point.y + d2->dy;
-
- return _cairo_path_curve_to (path, &p0, &p1, &p2);
-}
-
-cairo_status_t
-_cairo_path_close_path (cairo_path_t *path)
-{
- cairo_status_t status;
-
- status = _cairo_path_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
- if (status)
- return status;
-
- path->current_point.x = path->last_move_point.x;
- path->current_point.y = path->last_move_point.y;
- path->has_current_point = 1;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_path_current_point (cairo_path_t *path, cairo_point_t *point)
-{
- if (! path->has_current_point)
- return CAIRO_STATUS_NO_CURRENT_POINT;
-
- *point = path->current_point;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_path_add (cairo_path_t *path, cairo_path_op_t op, cairo_point_t *points, int num_points)
-{
- 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_points + num_points > CAIRO_PATH_BUF_SZ) {
- status = _cairo_path_new_arg_buf (path);
- if (status)
- return status;
- }
- _cairo_path_arg_buf_add (path->arg_tail, points, num_points);
-
- 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_t 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_points = 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, cairo_point_t *points, int num_points)
-{
- int i;
-
- for (i=0; i < num_points; i++) {
- arg->points[arg->num_points++] = points[i];
- }
-}
-
-#define CAIRO_PATH_OP_MAX_ARGS 3
-
-static int const 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_direction_t dir,
- cairo_path_move_to_func_t *move_to,
- cairo_path_line_to_func_t *line_to,
- cairo_path_curve_to_func_t *curve_to,
- cairo_path_close_path_func_t *close_path,
- void *closure)
-{
- cairo_status_t status;
- int i, arg;
- cairo_path_op_buf_t *op_buf;
- cairo_path_op_t op;
- cairo_path_arg_buf_t *arg_buf = path->arg_head;
- int buf_i = 0;
- cairo_point_t point[CAIRO_PATH_OP_MAX_ARGS];
- int step = (dir == CAIRO_DIRECTION_FORWARD) ? 1 : -1;
-
- for (op_buf = (dir == CAIRO_DIRECTION_FORWARD) ? path->op_head : path->op_tail;
- op_buf;
- op_buf = (dir == CAIRO_DIRECTION_FORWARD) ? op_buf->next : op_buf->prev)
- {
- int start, stop;
- if (dir == CAIRO_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_DIRECTION_REVERSE) {
- if (buf_i == 0) {
- arg_buf = arg_buf->prev;
- buf_i = arg_buf->num_points;
- }
- buf_i -= num_args[op];
- }
-
- for (arg = 0; arg < num_args[op]; arg++) {
- point[arg] = arg_buf->points[buf_i];
- buf_i++;
- if (buf_i >= arg_buf->num_points) {
- arg_buf = arg_buf->next;
- buf_i = 0;
- }
- }
-
- if (dir == CAIRO_DIRECTION_REVERSE) {
- buf_i -= num_args[op];
- }
-
- switch (op) {
- case CAIRO_PATH_OP_MOVE_TO:
- status = (*move_to) (closure, &point[0]);
- break;
- case CAIRO_PATH_OP_LINE_TO:
- status = (*line_to) (closure, &point[0]);
- break;
- case CAIRO_PATH_OP_CURVE_TO:
- status = (*curve_to) (closure, &point[0], &point[1], &point[2]);
- break;
- case CAIRO_PATH_OP_CLOSE_PATH:
- default:
- status = (*close_path) (closure);
- break;
- }
- if (status)
- return status;
- }
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
diff --git a/src/cairo_path_bounds.c b/src/cairo_path_bounds.c
deleted file mode 100644
index 7c5772a82..000000000
--- a/src/cairo_path_bounds.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2003 University of Southern California
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#include "cairoint.h"
-
-typedef struct cairo_path_bounder {
- int has_point;
-
- cairo_fixed_t min_x;
- cairo_fixed_t min_y;
- cairo_fixed_t max_x;
- cairo_fixed_t max_y;
-} cairo_path_bounder_t;
-
-static void
-_cairo_path_bounder_init (cairo_path_bounder_t *bounder);
-
-static void
-_cairo_path_bounder_fini (cairo_path_bounder_t *bounder);
-
-static cairo_status_t
-_cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *point);
-
-static cairo_status_t
-_cairo_path_bounder_move_to (void *closure, cairo_point_t *point);
-
-static cairo_status_t
-_cairo_path_bounder_line_to (void *closure, cairo_point_t *point);
-
-static cairo_status_t
-_cairo_path_bounder_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d);
-
-static cairo_status_t
-_cairo_path_bounder_close_path (void *closure);
-
-static void
-_cairo_path_bounder_init (cairo_path_bounder_t *bounder)
-{
- bounder->has_point = 0;
-}
-
-static void
-_cairo_path_bounder_fini (cairo_path_bounder_t *bounder)
-{
- bounder->has_point = 0;
-}
-
-static cairo_status_t
-_cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *point)
-{
- if (bounder->has_point) {
- if (point->x < bounder->min_x)
- bounder->min_x = point->x;
-
- if (point->y < bounder->min_y)
- bounder->min_y = point->y;
-
- if (point->x > bounder->max_x)
- bounder->max_x = point->x;
-
- if (point->y > bounder->max_y)
- bounder->max_y = point->y;
- } else {
- bounder->min_x = point->x;
- bounder->min_y = point->y;
- bounder->max_x = point->x;
- bounder->max_y = point->y;
-
- bounder->has_point = 1;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_path_bounder_move_to (void *closure, cairo_point_t *point)
-{
- cairo_path_bounder_t *bounder = closure;
-
- _cairo_path_bounder_add_point (bounder, point);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_path_bounder_line_to (void *closure, cairo_point_t *point)
-{
- cairo_path_bounder_t *bounder = closure;
-
- _cairo_path_bounder_add_point (bounder, point);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_path_bounder_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d)
-{
- cairo_path_bounder_t *bounder = closure;
-
- _cairo_path_bounder_add_point (bounder, b);
- _cairo_path_bounder_add_point (bounder, c);
- _cairo_path_bounder_add_point (bounder, d);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_path_bounder_close_path (void *closure)
-{
- 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;
-
- cairo_path_bounder_t bounder;
-
- _cairo_path_bounder_init (&bounder);
-
- status = _cairo_path_interpret (path, CAIRO_DIRECTION_FORWARD,
- _cairo_path_bounder_move_to,
- _cairo_path_bounder_line_to,
- _cairo_path_bounder_curve_to,
- _cairo_path_bounder_close_path,
- &bounder);
- if (status) {
- *x1 = *y1 = *x2 = *y2 = 0.0;
- _cairo_path_bounder_fini (&bounder);
- return status;
- }
-
- *x1 = _cairo_fixed_to_double (bounder.min_x);
- *y1 = _cairo_fixed_to_double (bounder.min_y);
- *x2 = _cairo_fixed_to_double (bounder.max_x);
- *y2 = _cairo_fixed_to_double (bounder.max_y);
-
- _cairo_path_bounder_fini (&bounder);
-
- return CAIRO_STATUS_SUCCESS;
-}
diff --git a/src/cairo_path_fill.c b/src/cairo_path_fill.c
deleted file mode 100644
index dc79b6b96..000000000
--- a/src/cairo_path_fill.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2002 University of Southern California
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#include "cairoint.h"
-
-typedef struct cairo_filler {
- cairo_gstate_t *gstate;
- cairo_traps_t *traps;
-
- cairo_point_t current_point;
-
- cairo_polygon_t polygon;
-} cairo_filler_t;
-
-static void
-_cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_t *traps);
-
-static void
-_cairo_filler_fini (cairo_filler_t *filler);
-
-static cairo_status_t
-_cairo_filler_move_to (void *closure, cairo_point_t *point);
-
-static cairo_status_t
-_cairo_filler_line_to (void *closure, cairo_point_t *point);
-
-static cairo_status_t
-_cairo_filler_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d);
-
-static cairo_status_t
-_cairo_filler_close_path (void *closure);
-
-static void
-_cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_t *traps)
-{
- filler->gstate = gstate;
- filler->traps = traps;
-
- filler->current_point.x = 0;
- filler->current_point.y = 0;
-
- _cairo_polygon_init (&filler->polygon);
-}
-
-static void
-_cairo_filler_fini (cairo_filler_t *filler)
-{
- _cairo_polygon_fini (&filler->polygon);
-}
-
-static cairo_status_t
-_cairo_filler_move_to (void *closure, cairo_point_t *point)
-{
- cairo_status_t status;
- cairo_filler_t *filler = closure;
- cairo_polygon_t *polygon = &filler->polygon;
-
- status = _cairo_polygon_close (polygon);
- if (status)
- return status;
-
- status = _cairo_polygon_move_to (polygon, point);
- if (status)
- return status;
-
- filler->current_point = *point;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_filler_line_to (void *closure, cairo_point_t *point)
-{
- cairo_status_t status;
- cairo_filler_t *filler = closure;
- cairo_polygon_t *polygon = &filler->polygon;
-
- status = _cairo_polygon_line_to (polygon, point);
- if (status)
- return status;
-
- filler->current_point = *point;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_filler_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d)
-{
- int i;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_filler_t *filler = closure;
- cairo_polygon_t *polygon = &filler->polygon;
- cairo_gstate_t *gstate = filler->gstate;
- cairo_spline_t spline;
-
- status = _cairo_spline_init (&spline, &filler->current_point, 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 = 1; i < spline.num_points; i++) {
- status = _cairo_polygon_line_to (polygon, &spline.points[i]);
- if (status)
- break;
- }
-
- CLEANUP_SPLINE:
- _cairo_spline_fini (&spline);
-
- filler->current_point = *d;
-
- return status;
-}
-
-static cairo_status_t
-_cairo_filler_close_path (void *closure)
-{
- cairo_status_t status;
- cairo_filler_t *filler = closure;
- cairo_polygon_t *polygon = &filler->polygon;
-
- status = _cairo_polygon_close (polygon);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_filler_t filler;
-
- _cairo_filler_init (&filler, gstate, traps);
-
- status = _cairo_path_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_filler_move_to,
- _cairo_filler_line_to,
- _cairo_filler_curve_to,
- _cairo_filler_close_path,
- &filler);
- if (status)
- goto BAIL;
-
- status = _cairo_polygon_close (&filler.polygon);
- if (status)
- goto BAIL;
-
- status = _cairo_traps_tessellate_polygon (filler.traps,
- &filler.polygon,
- filler.gstate->fill_rule);
- if (status)
- goto BAIL;
-
-BAIL:
- _cairo_filler_fini (&filler);
-
- return status;
-}
-
diff --git a/src/cairo_path_stroke.c b/src/cairo_path_stroke.c
deleted file mode 100644
index 08b380902..000000000
--- a/src/cairo_path_stroke.c
+++ /dev/null
@@ -1,848 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2002 University of Southern California
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#include "cairoint.h"
-
-typedef struct cairo_stroker {
- cairo_gstate_t *gstate;
- cairo_traps_t *traps;
-
- int has_current_point;
- cairo_point_t current_point;
- cairo_point_t first_point;
-
- int has_current_face;
- cairo_stroke_face_t current_face;
-
- int has_first_face;
- cairo_stroke_face_t first_face;
-
- int dashed;
- int dash_index;
- int dash_on;
- double dash_remain;
-} cairo_stroker_t;
-
-/* private functions */
-static void
-_cairo_stroker_init (cairo_stroker_t *stroker, cairo_gstate_t *gstate, cairo_traps_t *traps);
-
-static void
-_cairo_stroker_fini (cairo_stroker_t *stroker);
-
-static cairo_status_t
-_cairo_stroker_move_to (void *closure, cairo_point_t *point);
-
-static cairo_status_t
-_cairo_stroker_line_to (void *closure, cairo_point_t *point);
-
-static cairo_status_t
-_cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point);
-
-static cairo_status_t
-_cairo_stroker_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d);
-
-static cairo_status_t
-_cairo_stroker_close_path (void *closure);
-
-static void
-_translate_point (cairo_point_t *point, cairo_point_t *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_t *stroker, cairo_stroke_face_t *in, cairo_stroke_face_t *out);
-
-static void
-_cairo_stroker_start_dash (cairo_stroker_t *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->dashed = 1;
- stroker->dash_index = i;
- stroker->dash_on = on;
- stroker->dash_remain = gstate->dash[i] - offset;
-}
-
-static void
-_cairo_stroker_step_dash (cairo_stroker_t *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_t *stroker, cairo_gstate_t *gstate, cairo_traps_t *traps)
-{
- stroker->gstate = gstate;
- stroker->traps = traps;
-
- stroker->has_current_point = 0;
- stroker->has_current_face = 0;
- stroker->has_first_face = 0;
-
- if (gstate->dash)
- _cairo_stroker_start_dash (stroker);
- else
- stroker->dashed = 0;
-}
-
-static void
-_cairo_stroker_fini (cairo_stroker_t *stroker)
-{
- /* nothing to do here */
-}
-
-static void
-_translate_point (cairo_point_t *point, cairo_point_t *offset)
-{
- point->x += offset->x;
- point->y += offset->y;
-}
-
-static int
-_cairo_stroker_face_clockwise (cairo_stroke_face_t *in, cairo_stroke_face_t *out)
-{
- cairo_slope_t in_slope, out_slope;
-
- _cairo_slope_init (&in_slope, &in->point, &in->cw);
- _cairo_slope_init (&out_slope, &out->point, &out->cw);
-
- return _cairo_slope_clockwise (&in_slope, &out_slope);
-}
-
-static cairo_status_t
-_cairo_stroker_join (cairo_stroker_t *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);
- cairo_point_t *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;
- cairo_point_t tri[3];
- cairo_pen_t *pen = &gstate->pen_regular;
-
- tri[0] = in->point;
- if (clockwise) {
- _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);
- } else {
- _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);
- }
-
- i = start;
- tri[1] = *inpt;
- while (i != stop) {
- tri[2] = in->point;
- _translate_point (&tri[2], &pen->vertices[i].point);
- _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] = *outpt;
-
- return _cairo_traps_tessellate_triangle (stroker->traps, tri);
- }
- case CAIRO_LINE_JOIN_MITER:
- default: {
- /* dot product of incoming slope vector with outgoing slope vector */
- double in_dot_out = ((-in->usr_vector.x * out->usr_vector.x)+
- (-in->usr_vector.y * out->usr_vector.y));
- double ml = gstate->miter_limit;
-
- /*
- * Check the miter limit -- lines meeting at an acute angle
- * can generate long miters, the limit converts them to bevel
- *
- * We want to know when the miter is within the miter limit.
- * That's straightforward to specify:
- *
- * secant (psi / 2) <= ml
- *
- * where psi is the angle between in and out
- *
- * secant(psi/2) = 1/sin(psi/2)
- * 1/sin(psi/2) <= ml
- * 1 <= ml sin(psi/2)
- * 1 <= ml² sin²(psi/2)
- * 2 <= ml² 2 sin²(psi/2)
- * 2·sin²(psi/2) = 1-cos(psi)
- * 2 <= ml² (1-cos(psi))
- *
- * in · out = |in| |out| cos (psi)
- *
- * in and out are both unit vectors, so:
- *
- * in · out = cos (psi)
- *
- * 2 <= ml² (1 - in · out)
- *
- */
- if (2 <= ml * ml * (1 - in_dot_out)) {
- double x1, y1, x2, y2;
- double mx, my;
- double dx1, dx2, dy1, dy2;
- cairo_polygon_t polygon;
- cairo_point_t outer;
-
- /*
- * we've got the points already transformed to device
- * space, but need to do some computation with them and
- * also need to transform the slope from user space to
- * device space
- */
- /* outer point of incoming line face */
- x1 = _cairo_fixed_to_double (inpt->x);
- y1 = _cairo_fixed_to_double (inpt->y);
- dx1 = in->usr_vector.x;
- dy1 = in->usr_vector.y;
- cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1);
-
- /* outer point of outgoing line face */
- x2 = _cairo_fixed_to_double (outpt->x);
- y2 = _cairo_fixed_to_double (outpt->y);
- dx2 = out->usr_vector.x;
- dy2 = out->usr_vector.y;
- cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
-
- /*
- * Compute the location of the outer corner of the miter.
- * That's pretty easy -- just the intersection of the two
- * outer edges. We've got slopes and points on each
- * of those edges. Compute my directly, then compute
- * mx by using the edge with the larger dy; that avoids
- * dividing by values close to zero.
- */
- my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
- (dx1 * dy2 - dx2 * dy1));
- if (fabs (dy1) >= fabs (dy2))
- mx = (my - y1) * dx1 / dy1 + x1;
- else
- mx = (my - y2) * dx2 / dy2 + x2;
-
- /*
- * Draw the quadrilateral
- */
- outer.x = _cairo_fixed_from_double (mx);
- outer.y = _cairo_fixed_from_double (my);
- _cairo_polygon_init (&polygon);
- _cairo_polygon_move_to (&polygon, &in->point);
- _cairo_polygon_line_to (&polygon, inpt);
- _cairo_polygon_line_to (&polygon, &outer);
- _cairo_polygon_line_to (&polygon, outpt);
- _cairo_polygon_close (&polygon);
- 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: {
- cairo_point_t tri[3];
- tri[0] = in->point;
- tri[1] = *inpt;
- tri[2] = *outpt;
-
- return _cairo_traps_tessellate_triangle (stroker->traps, tri);
- }
- }
-}
-
-static cairo_status_t
-_cairo_stroker_cap (cairo_stroker_t *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_t slope;
- cairo_point_t 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->point;
- tri[1] = f->cw;
- for (i=start; i != stop; i = (i+1) % pen->num_vertices) {
- tri[2] = f->point;
- _translate_point (&tri[2], &pen->vertices[i].point);
- _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_t fvector;
- cairo_point_t occw, ocw;
- cairo_polygon_t 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 = _cairo_fixed_from_double (dx);
- fvector.dy = _cairo_fixed_from_double (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_init (&polygon);
- _cairo_polygon_move_to (&polygon, &f->cw);
- _cairo_polygon_line_to (&polygon, &ocw);
- _cairo_polygon_line_to (&polygon, &occw);
- _cairo_polygon_line_to (&polygon, &f->ccw);
- _cairo_polygon_close (&polygon);
-
- 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 (cairo_point_t *point, cairo_slope_t *slope, cairo_gstate_t *gstate, cairo_stroke_face_t *face)
-{
- double mag, det;
- double line_dx, line_dy;
- double face_dx, face_dy;
- cairo_point_double_t usr_vector;
- cairo_point_t offset_ccw, offset_cw;
-
- line_dx = _cairo_fixed_to_double (slope->dx);
- line_dy = _cairo_fixed_to_double (slope->dy);
-
- /* faces are normal in user space, not device space */
- cairo_matrix_transform_distance (&gstate->ctm_inverse, &line_dx, &line_dy);
-
- mag = sqrt (line_dx * line_dx + line_dy * line_dy);
- if (mag == 0) {
- /* XXX: Can't compute other face points. Do we want a tag in the face for this case? */
- return;
- }
-
- /* normalize to unit length */
- line_dx /= mag;
- line_dy /= mag;
-
- usr_vector.x = line_dx;
- usr_vector.y = line_dy;
-
- /*
- * rotate to get a line_width/2 vector along the face, note that
- * the vector must be rotated the right direction in device space,
- * but by 90° in user space. So, the rotation depends on
- * whether the ctm reflects or not, and that can be determined
- * by looking at the determinant of the matrix.
- */
- _cairo_matrix_compute_determinant (&gstate->ctm, &det);
- if (det >= 0)
- {
- face_dx = - line_dy * (gstate->line_width / 2.0);
- face_dy = line_dx * (gstate->line_width / 2.0);
- }
- else
- {
- face_dx = line_dy * (gstate->line_width / 2.0);
- face_dy = - line_dx * (gstate->line_width / 2.0);
- }
-
- /* back to device space */
- cairo_matrix_transform_distance (&gstate->ctm, &face_dx, &face_dy);
-
- offset_ccw.x = _cairo_fixed_from_double (face_dx);
- offset_ccw.y = _cairo_fixed_from_double (face_dy);
- offset_cw.x = -offset_ccw.x;
- offset_cw.y = -offset_ccw.y;
-
- face->ccw = *point;
- _translate_point (&face->ccw, &offset_ccw);
-
- face->point = *point;
-
- face->cw = *point;
- _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_t *stroker, cairo_point_t *p1, cairo_point_t *p2,
- cairo_stroke_face_t *start, cairo_stroke_face_t *end)
-{
- cairo_status_t status;
- cairo_gstate_t *gstate = stroker->gstate;
- cairo_polygon_t polygon;
- cairo_slope_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;
- }
-
- _cairo_slope_init (&slope, p1, p2);
- _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);
-
- /* XXX: I should really check the return value of the
- move_to/line_to functions here to catch out of memory
- conditions. But since that would be ugly, I'd prefer to add a
- status flag to the polygon object that I could check only once
- at then end of this sequence, (like we do with cairo_t
- already). */
- _cairo_polygon_init (&polygon);
- _cairo_polygon_move_to (&polygon, &start->cw);
- _cairo_polygon_line_to (&polygon, &start->ccw);
- _cairo_polygon_line_to (&polygon, &end->ccw);
- _cairo_polygon_line_to (&polygon, &end->cw);
- _cairo_polygon_close (&polygon);
-
- /* XXX: We can't use tessellate_rectangle as the matrix may have
- skewed this into a non-rectangular shape. Perhaps it would be
- worth checking the matrix for skew so that the common case
- could use the faster tessellate_rectangle rather than
- tessellate_polygon? */
- status = _cairo_traps_tessellate_polygon (stroker->traps,
- &polygon, CAIRO_FILL_RULE_WINDING);
-
- _cairo_polygon_fini (&polygon);
-
- return status;
-}
-
-static cairo_status_t
-_cairo_stroker_move_to (void *closure, cairo_point_t *point)
-{
- cairo_stroker_t *stroker = closure;
-
- stroker->first_point = *point;
- stroker->current_point = *point;
- stroker->has_current_point = 1;
-
- stroker->has_first_face = 0;
- stroker->has_current_face = 0;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_stroker_line_to (void *closure, cairo_point_t *point)
-{
- cairo_status_t status;
- cairo_stroker_t *stroker = closure;
- cairo_stroke_face_t start, end;
- cairo_point_t *p1 = &stroker->current_point;
- cairo_point_t *p2 = point;
-
- if (!stroker->has_current_point)
- return _cairo_stroker_move_to (stroker, point);
-
- 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->has_current_face) {
- status = _cairo_stroker_join (stroker, &stroker->current_face, &start);
- if (status)
- return status;
- } else {
- if (!stroker->has_first_face) {
- stroker->first_face = start;
- stroker->has_first_face = 1;
- }
- }
- stroker->current_face = end;
- stroker->has_current_face = 1;
-
- stroker->current_point = *point;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/*
- * Dashed lines. Cap each dash end, join around turns when on
- */
-static cairo_status_t
-_cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_stroker_t *stroker = closure;
- cairo_gstate_t *gstate = stroker->gstate;
- double mag, remain, tmp;
- double dx, dy;
- double dx2, dy2;
- cairo_point_t fd1, fd2;
- int first = 1;
- cairo_stroke_face_t sub_start, sub_end;
- cairo_point_t *p1 = &stroker->current_point;
- cairo_point_t *p2 = point;
-
- if (!stroker->has_current_point)
- return _cairo_stroker_move_to (stroker, point);
-
- dx = _cairo_fixed_to_double (p2->x - p1->x);
- dy = _cairo_fixed_to_double (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 = _cairo_fixed_from_double (dx2);
- fd2.y = _cairo_fixed_from_double (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 current_face, else
- * if at start of sub-path, mark position, else
- * cap
- */
- if (stroker->has_current_face) {
- status = _cairo_stroker_join (stroker, &stroker->current_face, &sub_start);
- if (status)
- return status;
- } else {
- if (!stroker->has_first_face) {
- stroker->first_face = sub_start;
- stroker->has_first_face = 1;
- } 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->current_face = sub_end;
- stroker->has_current_face = 1;
- }
- } else {
- /*
- * If starting with off dash, check previous face
- * and cap if necessary
- */
- if (first) {
- if (stroker->has_current_face) {
- status = _cairo_stroker_cap (stroker, &stroker->current_face);
- if (status)
- return status;
- }
- }
- if (!remain)
- stroker->has_current_face = 0;
- }
- _cairo_stroker_step_dash (stroker, tmp);
- fd1 = fd2;
- first = 0;
- }
-
- stroker->current_point = *point;
-
- return status;
-}
-
-static cairo_status_t
-_cairo_stroker_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_stroker_t *stroker = closure;
- cairo_gstate_t *gstate = stroker->gstate;
- cairo_spline_t spline;
- cairo_pen_t pen;
- cairo_stroke_face_t start, end;
- cairo_point_t extra_points[4];
- cairo_point_t *a = &stroker->current_point;
-
- 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->has_current_face) {
- status = _cairo_stroker_join (stroker, &stroker->current_face, &start);
- if (status)
- return status;
- } else {
- if (!stroker->has_first_face) {
- stroker->first_face = start;
- stroker->has_first_face = 1;
- }
- }
- stroker->current_face = end;
- stroker->has_current_face = 1;
-
- extra_points[0] = start.cw;
- extra_points[0].x -= start.point.x;
- extra_points[0].y -= start.point.y;
- extra_points[1] = start.ccw;
- extra_points[1].x -= start.point.x;
- extra_points[1].y -= start.point.y;
- extra_points[2] = end.cw;
- extra_points[2].x -= end.point.x;
- extra_points[2].y -= end.point.y;
- extra_points[3] = end.ccw;
- extra_points[3].x -= end.point.x;
- extra_points[3].y -= end.point.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);
-
- stroker->current_point = *d;
-
- return status;
-}
-
-static cairo_status_t
-_cairo_stroker_close_path (void *closure)
-{
- cairo_status_t status;
- cairo_stroker_t *stroker = closure;
-
- if (stroker->has_current_point) {
- if (stroker->dashed)
- status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point);
- else
- status = _cairo_stroker_line_to (stroker, &stroker->first_point);
- if (status)
- return status;
- }
-
- if (stroker->has_first_face && stroker->has_current_face) {
- status = _cairo_stroker_join (stroker, &stroker->current_face, &stroker->first_face);
- if (status)
- return status;
- }
-
- stroker->has_first_face = 0;
- stroker->has_current_face = 0;
- stroker->has_current_point = 0;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_stroker_t stroker;
-
- _cairo_stroker_init (&stroker, gstate, traps);
-
- if (gstate->dash)
- status = _cairo_path_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_stroker_move_to,
- _cairo_stroker_line_to_dashed,
- _cairo_stroker_curve_to,
- _cairo_stroker_close_path,
- &stroker);
- else
- status = _cairo_path_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_stroker_move_to,
- _cairo_stroker_line_to,
- _cairo_stroker_curve_to,
- _cairo_stroker_close_path,
- &stroker);
- if (status)
- goto BAIL;
-
- if (stroker.has_first_face) {
- cairo_point_t t;
- /* The initial cap needs an outward facing vector. Reverse everything */
- stroker.first_face.usr_vector.x = -stroker.first_face.usr_vector.x;
- stroker.first_face.usr_vector.y = -stroker.first_face.usr_vector.y;
- stroker.first_face.dev_vector.dx = -stroker.first_face.dev_vector.dx;
- stroker.first_face.dev_vector.dy = -stroker.first_face.dev_vector.dy;
- t = stroker.first_face.cw;
- stroker.first_face.cw = stroker.first_face.ccw;
- stroker.first_face.ccw = t;
- status = _cairo_stroker_cap (&stroker, &stroker.first_face);
- if (status)
- goto BAIL;
- }
-
- if (stroker.has_current_face) {
- status = _cairo_stroker_cap (&stroker, &stroker.current_face);
- if (status)
- goto BAIL;
- }
-
-BAIL:
- _cairo_stroker_fini (&stroker);
-
- return status;
-}
diff --git a/src/cairo_pattern.c b/src/cairo_pattern.c
deleted file mode 100644
index 283c36dbd..000000000
--- a/src/cairo_pattern.c
+++ /dev/null
@@ -1,1325 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2004 David Reveman
- *
- * 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 David
- * Reveman not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. David Reveman makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL DAVID REVEMAN 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: David Reveman <davidr@novell.com>
- */
-
-#include "cairoint.h"
-
-typedef void (*cairo_shader_function_t) (unsigned char *color0,
- unsigned char *color1,
- cairo_fixed_t factor,
- uint32_t *pixel);
-
-typedef struct _cairo_shader_color_stop {
- cairo_fixed_t offset;
- cairo_fixed_48_16_t scale;
- int id;
- unsigned char color_char[4];
-} cairo_shader_color_stop_t;
-
-typedef struct _cairo_shader_op {
- cairo_shader_color_stop_t *stops;
- int n_stops;
- cairo_extend_t extend;
- cairo_shader_function_t shader_function;
-} cairo_shader_op_t;
-
-#define MULTIPLY_COLORCOMP(c1, c2) \
- ((unsigned char) \
- ((((unsigned char) (c1)) * (int) ((unsigned char) (c2))) / 0xff))
-
-static void
-_cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
-{
- pattern->type = type;
- pattern->ref_count = 1;
- pattern->extend = CAIRO_EXTEND_DEFAULT;
- pattern->filter = CAIRO_FILTER_DEFAULT;
- pattern->alpha = 1.0;
-
- _cairo_matrix_init (&pattern->matrix);
-}
-
-static cairo_status_t
-_cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern,
- cairo_gradient_pattern_t *other)
-{
- if (other->base.type == CAIRO_PATTERN_LINEAR)
- {
- cairo_linear_pattern_t *dst = (cairo_linear_pattern_t *) pattern;
- cairo_linear_pattern_t *src = (cairo_linear_pattern_t *) other;
-
- *dst = *src;
- }
- else
- {
- cairo_radial_pattern_t *dst = (cairo_radial_pattern_t *) pattern;
- cairo_radial_pattern_t *src = (cairo_radial_pattern_t *) other;
-
- *dst = *src;
- }
-
- if (other->n_stops)
- {
- pattern->stops = malloc (other->n_stops * sizeof (cairo_color_stop_t));
- if (!pattern->stops)
- return CAIRO_STATUS_NO_MEMORY;
-
- memcpy (pattern->stops, other->stops,
- other->n_stops * sizeof (cairo_color_stop_t));
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other)
-{
- switch (other->type) {
- case CAIRO_PATTERN_SOLID: {
- cairo_solid_pattern_t *dst = (cairo_solid_pattern_t *) pattern;
- cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) other;
-
- *dst = *src;
- } break;
- case CAIRO_PATTERN_SURFACE: {
- cairo_surface_pattern_t *dst = (cairo_surface_pattern_t *) pattern;
- cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) other;
-
- *dst = *src;
- cairo_surface_reference (dst->surface);
- } break;
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL: {
- cairo_gradient_pattern_t *dst = (cairo_gradient_pattern_t *) pattern;
- cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) other;
- cairo_status_t status;
-
- status = _cairo_gradient_pattern_init_copy (dst, src);
- if (status)
- return status;
- } break;
- }
-
- pattern->ref_count = 1;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_pattern_fini (cairo_pattern_t *pattern)
-{
- switch (pattern->type) {
- case CAIRO_PATTERN_SOLID:
- break;
- case CAIRO_PATTERN_SURFACE: {
- cairo_surface_pattern_t *fini = (cairo_surface_pattern_t *) pattern;
-
- cairo_surface_destroy (fini->surface);
- } break;
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL: {
- cairo_gradient_pattern_t *fini = (cairo_gradient_pattern_t *) pattern;
-
- if (fini->n_stops)
- free (fini->stops);
- } break;
- }
-}
-
-void
-_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
- double red,
- double green,
- double blue)
-{
- _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SOLID);
-
- pattern->red = red;
- pattern->green = green;
- pattern->blue = blue;
-}
-
-void
-_cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
- cairo_surface_t *surface)
-{
- _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SURFACE);
-
- pattern->surface = surface;
- cairo_surface_reference (surface);
-}
-
-static void
-_cairo_pattern_init_gradient (cairo_gradient_pattern_t *pattern,
- cairo_pattern_type_t type)
-{
- _cairo_pattern_init (&pattern->base, type);
-
- pattern->stops = 0;
- pattern->n_stops = 0;
-}
-
-void
-_cairo_pattern_init_linear (cairo_linear_pattern_t *pattern,
- double x0, double y0, double x1, double y1)
-{
- _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_LINEAR);
-
- pattern->point0.x = x0;
- pattern->point0.y = y0;
- pattern->point1.x = x1;
- pattern->point1.y = y1;
-}
-
-void
-_cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
- double cx0, double cy0, double radius0,
- double cx1, double cy1, double radius1)
-{
- _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_RADIAL);
-
- pattern->center0.x = cx0;
- pattern->center0.y = cy0;
- pattern->radius0 = fabs (radius0);
- pattern->center1.x = cx1;
- pattern->center1.y = cy1;
- pattern->radius1 = fabs (radius1);
-}
-
-cairo_pattern_t *
-_cairo_pattern_create_solid (double red, double green, double blue)
-{
- cairo_solid_pattern_t *pattern;
-
- pattern = malloc (sizeof (cairo_solid_pattern_t));
- if (pattern == NULL)
- return NULL;
-
- _cairo_pattern_init_solid (pattern, red, green, blue);
-
- return &pattern->base;
-}
-
-cairo_pattern_t *
-cairo_pattern_create_for_surface (cairo_surface_t *surface)
-{
- cairo_surface_pattern_t *pattern;
-
- pattern = malloc (sizeof (cairo_surface_pattern_t));
- if (pattern == NULL)
- return NULL;
-
- _cairo_pattern_init_for_surface (pattern, surface);
-
- /* this will go away when we completely remove the surface attributes */
- if (surface->repeat)
- pattern->base.extend = CAIRO_EXTEND_REPEAT;
- else
- pattern->base.extend = CAIRO_EXTEND_DEFAULT;
-
- return &pattern->base;
-}
-
-cairo_pattern_t *
-cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
-{
- cairo_linear_pattern_t *pattern;
-
- pattern = malloc (sizeof (cairo_linear_pattern_t));
- if (pattern == NULL)
- return NULL;
-
- _cairo_pattern_init_linear (pattern, x0, y0, x1, y1);
-
- return &pattern->base.base;
-}
-
-cairo_pattern_t *
-cairo_pattern_create_radial (double cx0, double cy0, double radius0,
- double cx1, double cy1, double radius1)
-{
- cairo_radial_pattern_t *pattern;
-
- pattern = malloc (sizeof (cairo_radial_pattern_t));
- if (pattern == NULL)
- return NULL;
-
- _cairo_pattern_init_radial (pattern, cx0, cy0, radius0, cx1, cy1, radius1);
-
- return &pattern->base.base;
-}
-
-void
-cairo_pattern_reference (cairo_pattern_t *pattern)
-{
- if (pattern == NULL)
- return;
-
- pattern->ref_count++;
-}
-
-void
-cairo_pattern_destroy (cairo_pattern_t *pattern)
-{
- if (pattern == NULL)
- return;
-
- pattern->ref_count--;
- if (pattern->ref_count)
- return;
-
- _cairo_pattern_fini (pattern);
- free (pattern);
-}
-
-static cairo_status_t
-_cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern,
- double offset,
- double red,
- double green,
- double blue,
- double alpha)
-{
- cairo_color_stop_t *stop;
-
- pattern->n_stops++;
- pattern->stops = realloc (pattern->stops,
- pattern->n_stops * sizeof (cairo_color_stop_t));
- if (pattern->stops == NULL) {
- pattern->n_stops = 0;
-
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- stop = &pattern->stops[pattern->n_stops - 1];
-
- stop->offset = _cairo_fixed_from_double (offset);
-
- _cairo_color_init (&stop->color);
- _cairo_color_set_rgb (&stop->color, red, green, blue);
- _cairo_color_set_alpha (&stop->color, alpha);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
- double offset,
- double red,
- double green,
- double blue,
- double alpha)
-{
- if (pattern->type != CAIRO_PATTERN_LINEAR &&
- pattern->type != CAIRO_PATTERN_RADIAL)
- {
- /* XXX: CAIRO_STATUS_INVALID_PATTERN? */
- return CAIRO_STATUS_SUCCESS;
- }
-
- _cairo_restrict_value (&offset, 0.0, 1.0);
- _cairo_restrict_value (&red, 0.0, 1.0);
- _cairo_restrict_value (&green, 0.0, 1.0);
- _cairo_restrict_value (&blue, 0.0, 1.0);
- _cairo_restrict_value (&alpha, 0.0, 1.0);
-
- return _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern,
- offset,
- red, green, blue,
- alpha);
-}
-
-cairo_status_t
-cairo_pattern_set_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
-{
- return cairo_matrix_copy (&pattern->matrix, matrix);
-}
-
-cairo_status_t
-cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
-{
- return cairo_matrix_copy (matrix, &pattern->matrix);
-}
-
-cairo_status_t
-cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter)
-{
- pattern->filter = filter;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_filter_t
-cairo_pattern_get_filter (cairo_pattern_t *pattern)
-{
- return pattern->filter;
-}
-
-cairo_status_t
-cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend)
-{
- pattern->extend = extend;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_extend_t
-cairo_pattern_get_extend (cairo_pattern_t *pattern)
-{
- return pattern->extend;
-}
-
-cairo_status_t
-_cairo_pattern_get_rgb (cairo_pattern_t *pattern,
- double *red,
- double *green,
- double *blue)
-{
-
- if (pattern->type == CAIRO_PATTERN_SOLID)
- {
- cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
-
- *red = solid->red;
- *green = solid->green;
- *blue = solid->blue;
- } else
- *red = *green = *blue = 1.0;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha)
-{
- pattern->alpha = alpha;
-}
-
-void
-_cairo_pattern_transform (cairo_pattern_t *pattern,
- cairo_matrix_t *ctm_inverse)
-{
- cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix);
-}
-
-#define INTERPOLATE_COLOR_NEAREST(c1, c2, factor) \
- ((factor < 32768)? c1: c2)
-
-static void
-_cairo_pattern_shader_nearest (unsigned char *color0,
- unsigned char *color1,
- cairo_fixed_t factor,
- uint32_t *pixel)
-{
- *pixel =
- ((INTERPOLATE_COLOR_NEAREST (color0[3], color1[3], factor) << 24) |
- (INTERPOLATE_COLOR_NEAREST (color0[0], color1[0], factor) << 16) |
- (INTERPOLATE_COLOR_NEAREST (color0[1], color1[1], factor) << 8) |
- (INTERPOLATE_COLOR_NEAREST (color0[2], color1[2], factor) << 0));
-}
-
-#undef INTERPOLATE_COLOR_NEAREST
-
-#define INTERPOLATE_COLOR_LINEAR(c1, c2, factor) \
- (((c2 * factor) + (c1 * (65536 - factor))) / 65536)
-
-static void
-_cairo_pattern_shader_linear (unsigned char *color0,
- unsigned char *color1,
- cairo_fixed_t factor,
- uint32_t *pixel)
-{
- *pixel = ((INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor) << 24) |
- (INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor) << 16) |
- (INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor) << 8) |
- (INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor) << 0));
-}
-
-#define E_MINUS_ONE 1.7182818284590452354
-
-static void
-_cairo_pattern_shader_gaussian (unsigned char *color0,
- unsigned char *color1,
- cairo_fixed_t factor,
- uint32_t *pixel)
-{
- double f = ((double) factor) / 65536.0;
-
- factor = (cairo_fixed_t) (((exp (f * f) - 1.0) / E_MINUS_ONE) * 65536);
-
- *pixel = ((INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor) << 24) |
- (INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor) << 16) |
- (INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor) << 8) |
- (INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor) << 0));
-}
-
-#undef INTERPOLATE_COLOR_LINEAR
-
-static int
-_cairo_shader_color_stop_compare (const void *elem1, const void *elem2)
-{
- cairo_shader_color_stop_t *s1 = (cairo_shader_color_stop_t *) elem1;
- cairo_shader_color_stop_t *s2 = (cairo_shader_color_stop_t *) elem2;
-
- return
- (s1->offset == s2->offset) ?
- /* equal offsets, sort on id */
- ((s1->id < s2->id) ? -1 : 1) :
- /* sort on offset */
- ((s1->offset < s2->offset) ? -1 : 1);
-}
-
-static cairo_status_t
-_cairo_pattern_shader_init (cairo_gradient_pattern_t *pattern,
- cairo_shader_op_t *op)
-{
- int i;
-
- op->stops = malloc (pattern->n_stops * sizeof (cairo_shader_color_stop_t));
- if (!op->stops)
- return CAIRO_STATUS_NO_MEMORY;
-
- for (i = 0; i < pattern->n_stops; i++)
- {
- op->stops[i].color_char[0] = pattern->stops[i].color.red * 0xff;
- op->stops[i].color_char[1] = pattern->stops[i].color.green * 0xff;
- op->stops[i].color_char[2] = pattern->stops[i].color.blue * 0xff;
- op->stops[i].color_char[3] = pattern->stops[i].color.alpha *
- pattern->base.alpha * 0xff;
- op->stops[i].offset = pattern->stops[i].offset;
- op->stops[i].id = i;
- }
-
- /* sort stops in ascending order */
- qsort (op->stops, pattern->n_stops, sizeof (cairo_shader_color_stop_t),
- _cairo_shader_color_stop_compare);
-
- for (i = 0; i < pattern->n_stops - 1; i++)
- {
- op->stops[i + 1].scale = op->stops[i + 1].offset - op->stops[i].offset;
- if (op->stops[i + 1].scale == 65536)
- op->stops[i + 1].scale = 0;
- }
-
- op->n_stops = pattern->n_stops;
- op->extend = pattern->base.extend;
-
- /* XXX: this is wrong, the filter should not be used for selecting
- color stop interpolation function. function should always be 'linear'
- and filter should be used for computing pixels. */
- switch (pattern->base.filter) {
- case CAIRO_FILTER_FAST:
- case CAIRO_FILTER_NEAREST:
- op->shader_function = _cairo_pattern_shader_nearest;
- break;
- case CAIRO_FILTER_GAUSSIAN:
- op->shader_function = _cairo_pattern_shader_gaussian;
- break;
- case CAIRO_FILTER_GOOD:
- case CAIRO_FILTER_BEST:
- case CAIRO_FILTER_BILINEAR:
- op->shader_function = _cairo_pattern_shader_linear;
- break;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_pattern_shader_fini (cairo_shader_op_t *op)
-{
- if (op->stops)
- free (op->stops);
-}
-
-/* Find two color stops bounding the given offset. If the given offset
- * is before the first or after the last stop offset, the nearest
- * offset is returned twice.
- */
-static void
-_cairo_shader_op_find_color_stops (cairo_shader_op_t *op,
- cairo_fixed_t offset,
- cairo_shader_color_stop_t *stops[2])
-{
- int i;
-
- /* Before first stop. */
- if (offset <= op->stops[0].offset) {
- stops[0] = &op->stops[0];
- stops[1] = &op->stops[0];
- return;
- }
-
- /* Between two stops. */
- for (i = 0; i < op->n_stops - 1; i++) {
- if (offset <= op->stops[i + 1].offset) {
- stops[0] = &op->stops[i];
- stops[1] = &op->stops[i + 1];
- return;
- }
- }
-
- /* After last stop. */
- stops[0] = &op->stops[op->n_stops - 1];
- stops[1] = &op->stops[op->n_stops - 1];
-}
-
-static void
-_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
- cairo_fixed_t factor,
- uint32_t *pixel)
-{
- cairo_shader_color_stop_t *stops[2];
-
- switch (op->extend) {
- case CAIRO_EXTEND_REPEAT:
- factor -= factor & 0xffff0000;
- break;
- case CAIRO_EXTEND_REFLECT:
- if (factor < 0 || factor > 65536) {
- if ((factor >> 16) % 2)
- factor = 65536 - (factor - (factor & 0xffff0000));
- else
- factor -= factor & 0xffff0000;
- }
- break;
- case CAIRO_EXTEND_NONE:
- break;
- }
-
- _cairo_shader_op_find_color_stops (op, factor, stops);
-
- /* take offset as new 0 of coordinate system */
- factor -= stops[0]->offset;
-
- /* difference between two offsets == 0, abrubt change */
- if (stops[1]->scale)
- factor = ((cairo_fixed_48_16_t) factor << 16) /
- stops[1]->scale;
-
- op->shader_function (stops[0]->color_char,
- stops[1]->color_char,
- factor, pixel);
-
- /* multiply alpha */
- if (((unsigned char) (*pixel >> 24)) != 0xff) {
- *pixel = (*pixel & 0xff000000) |
- (MULTIPLY_COLORCOMP (*pixel >> 16, *pixel >> 24) << 16) |
- (MULTIPLY_COLORCOMP (*pixel >> 8, *pixel >> 24) << 8) |
- (MULTIPLY_COLORCOMP (*pixel >> 0, *pixel >> 24) << 0);
- }
-}
-
-static cairo_status_t
-_cairo_image_data_set_linear (cairo_linear_pattern_t *pattern,
- double offset_x,
- double offset_y,
- uint32_t *pixels,
- int width,
- int height)
-{
- int x, y;
- cairo_point_double_t point0, point1;
- double a, b, c, d, tx, ty;
- double scale, start, dx, dy, factor;
- cairo_shader_op_t op;
- cairo_status_t status;
-
- status = _cairo_pattern_shader_init (&pattern->base, &op);
- if (status)
- return status;
-
- /* We compute the position in the linear gradient for
- * a point q as:
- *
- * [q . (p1 - p0) - p0 . (p1 - p0)] / (p1 - p0) ^ 2
- *
- * The computation is done in pattern space. The
- * calculation could be heavily optimized by using the
- * fact that 'factor' increases linearly in both
- * directions.
- */
- point0.x = pattern->point0.x;
- point0.y = pattern->point0.y;
- point1.x = pattern->point1.x;
- point1.y = pattern->point1.y;
-
- cairo_matrix_get_affine (&pattern->base.base.matrix,
- &a, &b, &c, &d, &tx, &ty);
-
- dx = point1.x - point0.x;
- dy = point1.y - point0.y;
- scale = dx * dx + dy * dy;
- scale = (scale) ? 1.0 / scale : 1.0;
-
- start = dx * point0.x + dy * point0.y;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- double qx_device = x + offset_x;
- double qy_device = y + offset_y;
-
- /* transform fragment into pattern space */
- double qx = a * qx_device + c * qy_device + tx;
- double qy = b * qx_device + d * qy_device + ty;
-
- factor = ((dx * qx + dy * qy) - start) * scale;
-
- _cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++);
- }
- }
-
- _cairo_pattern_shader_fini (&op);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern,
- double offset_x,
- double offset_y,
- int width,
- int height,
- cairo_bool_t *is_horizontal,
- cairo_bool_t *is_vertical)
-{
- cairo_point_double_t point0, point1;
- double a, b, c, d, tx, ty;
- double scale, start, dx, dy;
- cairo_fixed_t factors[3];
- int i;
-
- /* To classidy a pattern as horizontal or vertical, we first
- * compute the (fixed point) factors at the corners of the
- * pattern. We actually only need 3/4 corners, so we skip the
- * fourth.
- */
- point0.x = pattern->point0.x;
- point0.y = pattern->point0.y;
- point1.x = pattern->point1.x;
- point1.y = pattern->point1.y;
-
- cairo_matrix_get_affine (&pattern->base.base.matrix,
- &a, &b, &c, &d, &tx, &ty);
-
- dx = point1.x - point0.x;
- dy = point1.y - point0.y;
- scale = dx * dx + dy * dy;
- scale = (scale) ? 1.0 / scale : 1.0;
-
- start = dx * point0.x + dy * point0.y;
-
- for (i = 0; i < 3; i++) {
- double qx_device = (i % 2) * (width - 1) + offset_x;
- double qy_device = (i / 2) * (height - 1) + offset_y;
-
- /* transform fragment into pattern space */
- double qx = a * qx_device + c * qy_device + tx;
- double qy = b * qx_device + d * qy_device + ty;
-
- factors[i] = _cairo_fixed_from_double (((dx * qx + dy * qy) - start) * scale);
- }
-
- /* We consider a pattern to be vertical if the fixed point factor
- * at the two upper corners is the same. We could accept a small
- * change, but determining what change is acceptable would require
- * sorting the stops in the pattern and looking at the differences.
- *
- * Horizontal works the same way with the two left corners.
- */
-
- *is_vertical = factors[1] == factors[0];
- *is_horizontal = factors[2] == factors[0];
-}
-
-static cairo_status_t
-_cairo_image_data_set_radial (cairo_radial_pattern_t *pattern,
- double offset_x,
- double offset_y,
- uint32_t *pixels,
- int width,
- int height)
-{
- int x, y, aligned_circles;
- cairo_point_double_t c0, c1;
- double px, py, ex, ey;
- double a, b, c, d, tx, ty;
- double r0, r1, c0_e_x, c0_e_y, c0_e, c1_e_x, c1_e_y, c1_e,
- c0_c1_x, c0_c1_y, c0_c1, angle_c0, c1_y, y_x, c0_y, c0_x, r1_2,
- denumerator, fraction, factor;
- cairo_shader_op_t op;
- cairo_status_t status;
-
- status = _cairo_pattern_shader_init (&pattern->base, &op);
- if (status)
- return status;
-
- c0.x = pattern->center0.x;
- c0.y = pattern->center0.y;
- r0 = pattern->radius0;
- c1.x = pattern->center1.x;
- c1.y = pattern->center1.y;
- r1 = pattern->radius1;
-
- if (c0.x != c1.x || c0.y != c1.y) {
- aligned_circles = 0;
- c0_c1_x = c1.x - c0.x;
- c0_c1_y = c1.y - c0.y;
- c0_c1 = sqrt (c0_c1_x * c0_c1_x + c0_c1_y * c0_c1_y);
- r1_2 = r1 * r1;
- } else {
- aligned_circles = 1;
- r1 = 1.0 / (r1 - r0);
- r1_2 = c0_c1 = 0.0; /* shut up compiler */
- }
-
- cairo_matrix_get_affine (&pattern->base.base.matrix,
- &a, &b, &c, &d, &tx, &ty);
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- px = x + offset_x;
- py = y + offset_y;
-
- /* transform fragment */
- ex = a * px + c * py + tx;
- ey = b * px + d * py + ty;
-
- if (aligned_circles) {
- ex = ex - c1.x;
- ey = ey - c1.y;
-
- factor = (sqrt (ex * ex + ey * ey) - r0) * r1;
- } else {
- /*
- y (ex, ey)
- c0 -------------------+---------- x
- \ | __--
- \ | __--
- \ | __--
- \ | __-- r1
- \ | __--
- c1 --
-
- We need to calulate distance c0->x; the distance from
- the inner circle center c0, through fragment position
- (ex, ey) to point x where it crosses the outer circle.
-
- From points c0, c1 and (ex, ey) we get angle C0. With
- angle C0 we calculate distance c1->y and c0->y and by
- knowing c1->y and r1, we also know y->x. Adding y->x to
- c0->y gives us c0->x. The gradient offset can then be
- calculated as:
-
- offset = (c0->e - r0) / (c0->x - r0)
-
- */
-
- c0_e_x = ex - c0.x;
- c0_e_y = ey - c0.y;
- c0_e = sqrt (c0_e_x * c0_e_x + c0_e_y * c0_e_y);
-
- c1_e_x = ex - c1.x;
- c1_e_y = ey - c1.y;
- c1_e = sqrt (c1_e_x * c1_e_x + c1_e_y * c1_e_y);
-
- denumerator = -2.0 * c0_e * c0_c1;
-
- if (denumerator != 0.0) {
- fraction = (c1_e * c1_e - c0_e * c0_e - c0_c1 * c0_c1) /
- denumerator;
-
- if (fraction > 1.0)
- fraction = 1.0;
- else if (fraction < -1.0)
- fraction = -1.0;
-
- angle_c0 = acos (fraction);
-
- c0_y = cos (angle_c0) * c0_c1;
- c1_y = sin (angle_c0) * c0_c1;
-
- y_x = sqrt (r1_2 - c1_y * c1_y);
- c0_x = y_x + c0_y;
-
- factor = (c0_e - r0) / (c0_x - r0);
- } else
- factor = -r0;
- }
-
- _cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++);
- }
- }
-
- _cairo_pattern_shader_fini (&op);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
- cairo_surface_t *dst,
- int x,
- int y,
- unsigned int width,
- unsigned int height,
- cairo_surface_t **out,
- cairo_surface_attributes_t *attr)
-{
- cairo_image_surface_t *image;
- cairo_status_t status;
- uint32_t *data;
- cairo_bool_t repeat = FALSE;
-
- if (pattern->base.type == CAIRO_PATTERN_LINEAR) {
- cairo_bool_t is_horizontal;
- cairo_bool_t is_vertical;
-
- _cairo_linear_pattern_classify ((cairo_linear_pattern_t *)pattern,
- x, y, width, height,
- &is_horizontal, &is_vertical);
- if (is_horizontal) {
- height = 1;
- repeat = TRUE;
- }
- if (is_vertical) {
- width = 1;
- repeat = TRUE;
- }
- }
-
- data = malloc (width * height * 4);
- if (!data)
- return CAIRO_STATUS_NO_MEMORY;
-
- if (pattern->base.type == CAIRO_PATTERN_LINEAR)
- {
- cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
-
- status = _cairo_image_data_set_linear (linear, x, y, data,
- width, height);
- }
- else
- {
- cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
-
- status = _cairo_image_data_set_radial (radial, x, y, data,
- width, height);
- }
-
- if (status) {
- free (data);
- return status;
- }
-
- image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data ((char *) data,
- CAIRO_FORMAT_ARGB32,
- width, height,
- width * 4);
-
- if (image == NULL) {
- free (data);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- _cairo_image_surface_assume_ownership_of_data (image);
-
- status = _cairo_surface_clone_similar (dst, &image->base, out);
-
- cairo_surface_destroy (&image->base);
-
- attr->x_offset = -x;
- attr->y_offset = -y;
- cairo_matrix_set_identity (&attr->matrix);
- attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
- attr->filter = CAIRO_FILTER_NEAREST;
- attr->acquired = FALSE;
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern,
- cairo_surface_t *dst,
- int x,
- int y,
- unsigned int width,
- unsigned int height,
- cairo_surface_t **out,
- cairo_surface_attributes_t *attribs)
-{
- cairo_color_t color;
-
- _cairo_color_init (&color);
- _cairo_color_set_rgb (&color, pattern->red, pattern->green, pattern->blue);
- _cairo_color_set_alpha (&color, pattern->base.alpha);
-
- *out = _cairo_surface_create_similar_solid (dst,
- CAIRO_FORMAT_ARGB32,
- 1, 1,
- &color);
-
- if (*out == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- attribs->x_offset = attribs->y_offset = 0;
- cairo_matrix_set_identity (&attribs->matrix);
- attribs->extend = CAIRO_EXTEND_REPEAT;
- attribs->filter = CAIRO_FILTER_NEAREST;
- attribs->acquired = FALSE;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-/**
- * _cairo_pattern_is_opaque
- *
- * Convenience function to determine whether a pattern has an opaque
- * alpha value. This is done by testing whether the pattern's alpha
- * value when converted to a byte is 255, so if a backend actually
- * supported deep alpha channels this function might not do the right
- * thing.
- *
- * Note that for a gradient or surface pattern, the overall resulting
- * alpha for the pattern can be non-opaque even this function returns
- * %TRUE, since the resulting alpha is the multiplication of the
- * alpha of the gradient or surface with the pattern's alpha. In
- * the future, alpha will be moved from the base pattern to the
- * solid pattern subtype, at which point this function should
- * probably be renamed to _cairo_pattern_is_opaque_solid()
- *
- * Return value: %TRUE if the pattern is opaque
- **/
-cairo_bool_t
-_cairo_pattern_is_opaque (cairo_pattern_t *pattern)
-{
- return (pattern->alpha >= ((double)0xff00 / (double)0xffff));
-}
-
-static cairo_int_status_t
-_cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern,
- cairo_surface_t *dst,
- int x,
- int y,
- unsigned int width,
- unsigned int height,
- cairo_surface_t **out,
- cairo_surface_attributes_t *attr)
-{
- cairo_int_status_t status;
-
- attr->acquired = FALSE;
-
- /* handle pattern opacity */
- if (!_cairo_pattern_is_opaque (&pattern->base))
- {
- cairo_surface_pattern_t tmp;
- cairo_color_t color;
-
- _cairo_color_init (&color);
- _cairo_color_set_alpha (&color, pattern->base.alpha);
-
- *out = _cairo_surface_create_similar_solid (dst,
- CAIRO_FORMAT_ARGB32,
- width, height,
- &color);
- if (*out == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- status = _cairo_pattern_init_copy (&tmp.base, &pattern->base);
- if (CAIRO_OK (status))
- {
- tmp.base.alpha = 1.0;
- status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- &tmp.base,
- NULL,
- *out,
- x, y, 0, 0, 0, 0,
- width, height);
-
- _cairo_pattern_fini (&tmp.base);
- }
-
- if (status) {
- cairo_surface_destroy (*out);
- return status;
- }
-
- attr->x_offset = -x;
- attr->y_offset = -y;
- attr->extend = CAIRO_EXTEND_NONE;
- attr->filter = CAIRO_FILTER_NEAREST;
-
- cairo_matrix_set_identity (&attr->matrix);
- }
- else
- {
- int tx, ty;
-
- if (_cairo_surface_is_image (dst))
- {
- cairo_image_surface_t *image;
-
- status = _cairo_surface_acquire_source_image (pattern->surface,
- &image,
- &attr->extra);
- if (CAIRO_OK (status))
- *out = &image->base;
-
- attr->acquired = TRUE;
- }
- else
- status = _cairo_surface_clone_similar (dst, pattern->surface, out);
-
- attr->extend = pattern->base.extend;
- attr->filter = pattern->base.filter;
- if (_cairo_matrix_is_integer_translation (&pattern->base.matrix,
- &tx, &ty))
- {
- cairo_matrix_set_identity (&attr->matrix);
- attr->x_offset = tx;
- attr->y_offset = ty;
- }
- else
- {
- attr->matrix = pattern->base.matrix;
- attr->x_offset = attr->y_offset = 0;
- }
- }
-
- return status;
-}
-
-/**
- * _cairo_pattern_acquire_surface:
- * @pattern: a #cairo_pattern_t
- * @dst: destination surface
- * @x: X coordinate in source corresponding to left side of destination area
- * @y: Y coordinate in source corresponding to top side of destination area
- * @width: width of destination area
- * @height: height of destination area
- * @surface_out: location to store a pointer to a surface
- * @attributes: surface attributes that destination backend should apply to
- * the returned surface
- *
- * A convenience function to obtain a surface to use as the source for
- * drawing on @dst.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if a surface was stored in @surface_out.
- **/
-cairo_int_status_t
-_cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
- cairo_surface_t *dst,
- int x,
- int y,
- unsigned int width,
- unsigned int height,
- cairo_surface_t **surface_out,
- cairo_surface_attributes_t *attributes)
-{
- switch (pattern->type) {
- case CAIRO_PATTERN_SOLID: {
- cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) pattern;
-
- return _cairo_pattern_acquire_surface_for_solid (src, dst,
- x, y, width, height,
- surface_out,
- attributes);
- } break;
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL: {
- cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) pattern;
-
- /* fast path for gradients with less than 2 color stops */
- if (src->n_stops < 2)
- {
- cairo_solid_pattern_t solid;
-
- if (src->n_stops)
- {
- _cairo_pattern_init_solid (&solid,
- src->stops->color.red,
- src->stops->color.green,
- src->stops->color.blue);
- _cairo_pattern_set_alpha (&solid.base,
- src->stops->color.alpha);
- }
- else
- {
- _cairo_pattern_init_solid (&solid, 0.0, 0.0, 0.0);
- _cairo_pattern_set_alpha (&solid.base, 0.0);
- }
-
- return _cairo_pattern_acquire_surface_for_solid (&solid, dst,
- x, y,
- width, height,
- surface_out,
- attributes);
- }
- else
- return _cairo_pattern_acquire_surface_for_gradient (src, dst,
- x, y,
- width, height,
- surface_out,
- attributes);
- } break;
- case CAIRO_PATTERN_SURFACE: {
- cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) pattern;
-
- return _cairo_pattern_acquire_surface_for_surface (src, dst,
- x, y, width, height,
- surface_out,
- attributes);
- } break;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-/**
- * _cairo_pattern_release_surface:
- * @pattern: a #cairo_pattern_t
- * @info: pointer to #cairo_surface_attributes_t filled in by
- * _cairo_pattern_acquire_surface
- *
- * Releases resources obtained by _cairo_pattern_acquire_surface.
- **/
-void
-_cairo_pattern_release_surface (cairo_surface_t *dst,
- cairo_surface_t *surface,
- cairo_surface_attributes_t *attributes)
-{
- if (attributes->acquired)
- _cairo_surface_release_source_image (dst,
- (cairo_image_surface_t *) surface,
- attributes->extra);
- else
- cairo_surface_destroy (surface);
-}
-
-cairo_int_status_t
-_cairo_pattern_acquire_surfaces (cairo_pattern_t *src,
- cairo_pattern_t *mask,
- cairo_surface_t *dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- unsigned int width,
- unsigned int height,
- cairo_surface_t **src_out,
- cairo_surface_t **mask_out,
- cairo_surface_attributes_t *src_attributes,
- cairo_surface_attributes_t *mask_attributes)
-{
- cairo_int_status_t status;
-
- cairo_pattern_union_t tmp;
- cairo_bool_t src_opaque, mask_opaque;
- double src_alpha, mask_alpha;
-
- src_opaque = _cairo_pattern_is_opaque (src);
- mask_opaque = !mask || _cairo_pattern_is_opaque (mask);
-
- /* For surface patterns, we move any translucency from src->alpha
- * to mask->alpha so we can use the source unchanged. Otherwise we
- * move the translucency from mask->alpha to src->alpha so that
- * we can drop the mask if possible.
- */
- if (src->type == CAIRO_PATTERN_SURFACE)
- {
- if (mask) {
- mask_opaque = mask_opaque && src_opaque;
- mask_alpha = mask->alpha * src->alpha;
- } else {
- mask_opaque = src_opaque;
- mask_alpha = src->alpha;
- }
-
- src_alpha = 1.0;
- src_opaque = TRUE;
- }
- else
- {
- if (mask)
- {
- src_opaque = mask_opaque && src_opaque;
- src_alpha = mask->alpha * src->alpha;
- /* FIXME: This needs changing when we support RENDER
- * style 4-channel masks.
- */
- if (mask->type == CAIRO_PATTERN_SOLID)
- mask = NULL;
- } else
- src_alpha = src->alpha;
-
- mask_alpha = 1.0;
- mask_opaque = TRUE;
- }
-
- _cairo_pattern_init_copy (&tmp.base, src);
- _cairo_pattern_set_alpha (&tmp.base, src_alpha);
-
- status = _cairo_pattern_acquire_surface (&tmp.base, dst,
- src_x, src_y,
- width, height,
- src_out, src_attributes);
-
- _cairo_pattern_fini (&tmp.base);
-
- if (status)
- return status;
-
- if (mask || !mask_opaque)
- {
- if (mask)
- _cairo_pattern_init_copy (&tmp.base, mask);
- else
- _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0);
-
- _cairo_pattern_set_alpha (&tmp.base, mask_alpha);
-
- status = _cairo_pattern_acquire_surface (&tmp.base, dst,
- mask_x, mask_y,
- width, height,
- mask_out, mask_attributes);
-
- _cairo_pattern_fini (&tmp.base);
-
- if (status)
- {
- _cairo_pattern_release_surface (dst, *src_out, src_attributes);
- return status;
- }
- }
- else
- {
- *mask_out = NULL;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
diff --git a/src/cairo_pdf_surface.c b/src/cairo_pdf_surface.c
deleted file mode 100644
index fee918355..000000000
--- a/src/cairo_pdf_surface.c
+++ /dev/null
@@ -1,2222 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2004 Red Hat, Inc
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Kristian Høgsberg <krh@redhat.com>
- */
-
-#include "cairoint.h"
-#include "cairo-pdf.h"
-/* XXX: Eventually, we need to handle other font backends */
-#include "cairo-ft-private.h"
-
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_OUTLINE_H
-#include FT_TRUETYPE_TAGS_H
-#include FT_TRUETYPE_TABLES_H
-
-#include <time.h>
-#include <zlib.h>
-
-/* Issues:
- *
- * - Why doesn't pages inherit /alpha%d GS dictionaries from the Pages
- * object?
- *
- * - We embed an image in the stream each time it's composited. We
- * could add generation counters to surfaces and remember the stream
- * ID for a particular generation for a particular surface.
- *
- * - Multi stop gradients. What are the exponential interpolation
- * functions, could they be used for gradients?
- *
- * - Clipping: must be able to reset clipping
- *
- * - Images of other formats than 8 bit RGBA.
- *
- * - Backend specific meta data.
- *
- * - Surface patterns.
- *
- * - Alpha channels in gradients.
- *
- * - Should/does cairo support drawing into a scratch surface and then
- * using that as a fill pattern? For this backend, that would involve
- * using a tiling pattern (4.6.2). How do you create such a scratch
- * surface? cairo_surface_create_similar() ?
- *
- * - What if you create a similiar surface and does show_page and then
- * does show_surface on another surface?
- *
- * - Output TM so page scales to the right size - PDF default user
- * space has 1 unit = 1 / 72 inch.
- *
- * - Add test case for RGBA images.
- *
- * - Add test case for RGBA gradients.
- *
- * - Pattern extend isn't honoured by image backend.
- *
- * - Coordinate space for create_similar() args?
- *
- * - Investigate /Matrix entry in content stream dicts for pages
- * instead of outputting the cm operator in every page.
- */
-
-typedef struct ft_subset_glyph ft_subset_glyph_t;
-struct ft_subset_glyph {
- int parent_index;
- unsigned long location;
-};
-
-typedef struct cairo_pdf_font_backend cairo_pdf_font_backend_t;
-struct cairo_pdf_font_backend {
- int (*use_glyph) (void *abstract_font,
- int glyph);
- cairo_status_t (*generate) (void *abstract_font,
- const char **data,
- unsigned long *length);
- void (*destroy) (void *abstract_font);
-};
-
-typedef struct cairo_pdf_font cairo_pdf_font_t;
-struct cairo_pdf_font {
- cairo_pdf_font_backend_t *backend;
- cairo_unscaled_font_t *unscaled_font;
- unsigned int font_id;
- char *base_font;
- int num_glyphs;
- int *widths;
- long x_min, y_min, x_max, y_max;
- long ascent, descent;
-};
-
-typedef struct cairo_pdf_ft_font cairo_pdf_ft_font_t;
-struct cairo_pdf_ft_font {
- cairo_pdf_font_t base;
- ft_subset_glyph_t *glyphs;
- FT_Face face;
- unsigned long *checksum_location;
- cairo_array_t output;
- int *parent_to_subset;
- cairo_status_t status;
-};
-
-typedef struct cairo_pdf_object cairo_pdf_object_t;
-typedef struct cairo_pdf_resource cairo_pdf_resource_t;
-typedef struct cairo_pdf_stream cairo_pdf_stream_t;
-typedef struct cairo_pdf_document cairo_pdf_document_t;
-typedef struct cairo_pdf_surface cairo_pdf_surface_t;
-
-struct cairo_pdf_object {
- long offset;
-};
-
-struct cairo_pdf_resource {
- unsigned int id;
-};
-
-struct cairo_pdf_stream {
- unsigned int id;
- unsigned int length_id;
- long start_offset;
-};
-
-struct cairo_pdf_document {
- FILE *file;
- unsigned long refcount;
-
- double width_inches;
- double height_inches;
- double x_ppi;
- double y_ppi;
-
- unsigned int next_available_id;
- unsigned int pages_id;
-
- cairo_pdf_stream_t *current_stream;
-
- cairo_array_t objects;
- cairo_array_t pages;
-
- cairo_array_t fonts;
-};
-
-struct cairo_pdf_surface {
- cairo_surface_t base;
-
- double width_inches;
- double height_inches;
-
- cairo_pdf_document_t *document;
- cairo_pdf_stream_t *current_stream;
-
- cairo_array_t patterns;
- cairo_array_t xobjects;
- cairo_array_t streams;
- cairo_array_t alphas;
- cairo_array_t fonts;
-};
-
-
-static cairo_pdf_document_t *
-_cairo_pdf_document_create (FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch);
-
-static void
-_cairo_pdf_document_destroy (cairo_pdf_document_t *document);
-
-static void
-_cairo_pdf_document_reference (cairo_pdf_document_t *document);
-
-static unsigned int
-_cairo_pdf_document_new_object (cairo_pdf_document_t *document);
-
-static cairo_status_t
-_cairo_pdf_document_add_page (cairo_pdf_document_t *document,
- cairo_pdf_surface_t *surface);
-
-static void
-_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface);
-
-static cairo_pdf_stream_t *
-_cairo_pdf_document_open_stream (cairo_pdf_document_t *document,
- const char *extra_entries);
-static cairo_surface_t *
-_cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document,
- double width_inches,
- double height_inches);
-static void
-_cairo_pdf_surface_add_stream (cairo_pdf_surface_t *surface,
- cairo_pdf_stream_t *stream);
-static void
-_cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface);
-
-static const cairo_surface_backend_t cairo_pdf_surface_backend;
-
-/* Truetype font subsetting code */
-
-#define ARRAY_LENGTH(a) ( (sizeof (a)) / (sizeof ((a)[0])) )
-
-#define SFNT_VERSION 0x00010000
-
-#ifdef WORDS_BIGENDIAN
-
-#define cpu_to_be16(v) (v)
-#define be16_to_cpu(v) (v)
-#define cpu_to_be32(v) (v)
-#define be32_to_cpu(v) (v)
-
-#else
-
-static inline unsigned short
-cpu_to_be16(unsigned short v)
-{
- return (v << 8) | (v >> 8);
-}
-
-static inline unsigned short
-be16_to_cpu(unsigned short v)
-{
- return cpu_to_be16 (v);
-}
-
-static inline unsigned long
-cpu_to_be32(unsigned long v)
-{
- return (cpu_to_be16 (v) << 16) | cpu_to_be16 (v >> 16);
-}
-
-static inline unsigned long
-be32_to_cpu(unsigned long v)
-{
- return cpu_to_be32 (v);
-}
-
-#endif
-
-static cairo_pdf_font_backend_t cairo_pdf_ft_font_backend;
-
-static int
-cairo_pdf_font_use_glyph (cairo_pdf_font_t *font, int glyph)
-{
- return font->backend->use_glyph (font, glyph);
-}
-
-static cairo_status_t
-cairo_pdf_font_generate (cairo_pdf_font_t *font,
- const char **data, unsigned long *length)
-{
- return font->backend->generate (font, data, length);
-}
-
-static void
-cairo_pdf_font_destroy (cairo_pdf_font_t *font)
-{
- font->backend->destroy (font);
-}
-
-static cairo_pdf_font_t *
-cairo_pdf_ft_font_create (cairo_pdf_document_t *document,
- cairo_unscaled_font_t *unscaled_font)
-{
- FT_Face face;
- cairo_pdf_ft_font_t *font;
- unsigned long size;
- int i, j;
-
- face = _cairo_ft_unscaled_font_lock_face (unscaled_font);
-
- /* We currently only support freetype truetype fonts. */
- size = 0;
- if (!FT_IS_SFNT (face) ||
- FT_Load_Sfnt_Table (face, TTAG_glyf, 0, NULL, &size) != 0)
- return NULL;
-
- font = malloc (sizeof (cairo_pdf_ft_font_t));
- if (font == NULL)
- return NULL;
-
- font->base.unscaled_font = unscaled_font;
- _cairo_unscaled_font_reference (unscaled_font);
- font->base.backend = &cairo_pdf_ft_font_backend;
- font->base.font_id = _cairo_pdf_document_new_object (document);
-
- _cairo_array_init (&font->output, sizeof (char));
- if (_cairo_array_grow_by (&font->output, 4096) != CAIRO_STATUS_SUCCESS)
- goto fail1;
-
- font->base.unscaled_font = unscaled_font;
- _cairo_unscaled_font_reference (unscaled_font);
- font->glyphs = calloc (face->num_glyphs + 1, sizeof (ft_subset_glyph_t));
- if (font->glyphs == NULL)
- goto fail2;
-
- font->parent_to_subset = calloc (face->num_glyphs, sizeof (int));
- if (font->parent_to_subset == NULL)
- goto fail3;
-
- font->base.num_glyphs = 1;
- font->base.x_min = face->bbox.xMin;
- font->base.y_min = face->bbox.yMin;
- font->base.x_max = face->bbox.xMax;
- font->base.y_max = face->bbox.yMax;
- font->base.ascent = face->ascender;
- font->base.descent = face->descender;
- font->base.base_font = strdup (face->family_name);
- if (font->base.base_font == NULL)
- goto fail4;
-
- for (i = 0, j = 0; font->base.base_font[j]; j++) {
- if (font->base.base_font[j] == ' ')
- continue;
- font->base.base_font[i++] = font->base.base_font[j];
- }
- font->base.base_font[i] = '\0';
-
- font->base.widths = calloc (face->num_glyphs, sizeof (int));
- if (font->base.widths == NULL)
- goto fail5;
-
- _cairo_ft_unscaled_font_unlock_face (unscaled_font);
-
- font->status = CAIRO_STATUS_SUCCESS;
-
- return &font->base;
-
- fail5:
- free (font->base.base_font);
- fail4:
- free (font->parent_to_subset);
- fail3:
- free (font->glyphs);
- fail2:
- _cairo_array_fini (&font->output);
- fail1:
- free (font);
- return NULL;
-}
-
-static void
-cairo_pdf_ft_font_destroy (void *abstract_font)
-{
- cairo_pdf_ft_font_t *font = abstract_font;
-
- _cairo_unscaled_font_destroy (font->base.unscaled_font);
- free (font->base.base_font);
- free (font->parent_to_subset);
- free (font->glyphs);
- _cairo_array_fini (&font->output);
- free (font);
-}
-
-static void *
-cairo_pdf_ft_font_write (cairo_pdf_ft_font_t *font,
- const void *data, size_t length)
-{
- void *p;
-
- p = _cairo_array_append (&font->output, data, length);
- if (p == NULL)
- font->status = CAIRO_STATUS_NO_MEMORY;
-
- return p;
-}
-
-static void
-cairo_pdf_ft_font_write_be16 (cairo_pdf_ft_font_t *font,
- unsigned short value)
-{
- unsigned short be16_value;
-
- be16_value = cpu_to_be16 (value);
- cairo_pdf_ft_font_write (font, &be16_value, sizeof be16_value);
-}
-
-static void
-cairo_pdf_ft_font_write_be32 (cairo_pdf_ft_font_t *font, unsigned long value)
-{
- unsigned long be32_value;
-
- be32_value = cpu_to_be32 (value);
- cairo_pdf_ft_font_write (font, &be32_value, sizeof be32_value);
-}
-
-static unsigned long
-cairo_pdf_ft_font_align_output (cairo_pdf_ft_font_t *font)
-{
- int length, aligned;
- static const char pad[4];
-
- length = _cairo_array_num_elements (&font->output);
- aligned = (length + 3) & ~3;
- cairo_pdf_ft_font_write (font, pad, aligned - length);
-
- return aligned;
-}
-
-static int
-cairo_pdf_ft_font_write_cmap_table (cairo_pdf_ft_font_t *font, unsigned long tag)
-{
- int i;
-
- cairo_pdf_ft_font_write_be16 (font, 0);
- cairo_pdf_ft_font_write_be16 (font, 1);
-
- cairo_pdf_ft_font_write_be16 (font, 1);
- cairo_pdf_ft_font_write_be16 (font, 0);
- cairo_pdf_ft_font_write_be32 (font, 12);
-
- /* Output a format 6 encoding table. */
-
- cairo_pdf_ft_font_write_be16 (font, 6);
- cairo_pdf_ft_font_write_be16 (font, 10 + 2 * (font->base.num_glyphs - 1));
- cairo_pdf_ft_font_write_be16 (font, 0);
- cairo_pdf_ft_font_write_be16 (font, 1); /* First glyph */
- cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs - 1);
- for (i = 1; i < font->base.num_glyphs; i++)
- cairo_pdf_ft_font_write_be16 (font, i);
-
- return font->status;
-}
-
-static int
-cairo_pdf_ft_font_write_generic_table (cairo_pdf_ft_font_t *font,
- unsigned long tag)
-{
- char *buffer;
- unsigned long size;
-
- size = 0;
- FT_Load_Sfnt_Table (font->face, tag, 0, NULL, &size);
- buffer = cairo_pdf_ft_font_write (font, NULL, size);
- FT_Load_Sfnt_Table (font->face, tag, 0, buffer, &size);
-
- return 0;
-}
-
-static int
-cairo_pdf_ft_font_write_glyf_table (cairo_pdf_ft_font_t *font,
- unsigned long tag)
-{
- unsigned long start_offset, index, size;
- TT_Header *header;
- unsigned long begin, end;
- char *buffer;
- int i;
- union {
- unsigned char *bytes;
- unsigned short *short_offsets;
- unsigned long *long_offsets;
- } u;
-
- header = FT_Get_Sfnt_Table (font->face, ft_sfnt_head);
- if (header->Index_To_Loc_Format == 0)
- size = sizeof (short) * (font->face->num_glyphs + 1);
- else
- size = sizeof (long) * (font->face->num_glyphs + 1);
-
- u.bytes = malloc (size);
- if (u.bytes == NULL) {
- font->status = CAIRO_STATUS_NO_MEMORY;
- return font->status;
- }
- FT_Load_Sfnt_Table (font->face, TTAG_loca, 0, u.bytes, &size);
-
- start_offset = _cairo_array_num_elements (&font->output);
- for (i = 0; i < font->base.num_glyphs; i++) {
- index = font->glyphs[i].parent_index;
- if (header->Index_To_Loc_Format == 0) {
- begin = be16_to_cpu (u.short_offsets[index]) * 2;
- end = be16_to_cpu (u.short_offsets[index + 1]) * 2;
- }
- else {
- begin = be32_to_cpu (u.long_offsets[index]);
- end = be32_to_cpu (u.long_offsets[index + 1]);
- }
-
- size = end - begin;
-
- font->glyphs[i].location =
- cairo_pdf_ft_font_align_output (font) - start_offset;
- buffer = cairo_pdf_ft_font_write (font, NULL, size);
- if (buffer == NULL)
- break;
- FT_Load_Sfnt_Table (font->face, TTAG_glyf, begin, buffer, &size);
- /* FIXME: remap composite glyphs */
- }
-
- font->glyphs[i].location =
- cairo_pdf_ft_font_align_output (font) - start_offset;
-
- free (u.bytes);
-
- return font->status;
-}
-
-static int
-cairo_pdf_ft_font_write_head_table (cairo_pdf_ft_font_t *font,
- unsigned long tag)
-{
- TT_Header *head;
-
- head = FT_Get_Sfnt_Table (font->face, ft_sfnt_head);
-
- cairo_pdf_ft_font_write_be32 (font, head->Table_Version);
- cairo_pdf_ft_font_write_be32 (font, head->Font_Revision);
-
- font->checksum_location =
- (unsigned long *) _cairo_array_index (&font->output, 0) +
- _cairo_array_num_elements (&font->output) / sizeof (long);
- cairo_pdf_ft_font_write_be32 (font, 0);
- cairo_pdf_ft_font_write_be32 (font, head->Magic_Number);
-
- cairo_pdf_ft_font_write_be16 (font, head->Flags);
- cairo_pdf_ft_font_write_be16 (font, head->Units_Per_EM);
-
- cairo_pdf_ft_font_write_be32 (font, head->Created[0]);
- cairo_pdf_ft_font_write_be32 (font, head->Created[1]);
- cairo_pdf_ft_font_write_be32 (font, head->Modified[0]);
- cairo_pdf_ft_font_write_be32 (font, head->Modified[1]);
-
- cairo_pdf_ft_font_write_be16 (font, head->xMin);
- cairo_pdf_ft_font_write_be16 (font, head->yMin);
- cairo_pdf_ft_font_write_be16 (font, head->xMax);
- cairo_pdf_ft_font_write_be16 (font, head->yMax);
-
- cairo_pdf_ft_font_write_be16 (font, head->Mac_Style);
- cairo_pdf_ft_font_write_be16 (font, head->Lowest_Rec_PPEM);
-
- cairo_pdf_ft_font_write_be16 (font, head->Font_Direction);
- cairo_pdf_ft_font_write_be16 (font, head->Index_To_Loc_Format);
- cairo_pdf_ft_font_write_be16 (font, head->Glyph_Data_Format);
-
- return font->status;
-}
-
-static int cairo_pdf_ft_font_write_hhea_table (cairo_pdf_ft_font_t *font, unsigned long tag)
-{
- TT_HoriHeader *hhea;
-
- hhea = FT_Get_Sfnt_Table (font->face, ft_sfnt_hhea);
-
- cairo_pdf_ft_font_write_be32 (font, hhea->Version);
- cairo_pdf_ft_font_write_be16 (font, hhea->Ascender);
- cairo_pdf_ft_font_write_be16 (font, hhea->Descender);
- cairo_pdf_ft_font_write_be16 (font, hhea->Line_Gap);
-
- cairo_pdf_ft_font_write_be16 (font, hhea->advance_Width_Max);
-
- cairo_pdf_ft_font_write_be16 (font, hhea->min_Left_Side_Bearing);
- cairo_pdf_ft_font_write_be16 (font, hhea->min_Right_Side_Bearing);
- cairo_pdf_ft_font_write_be16 (font, hhea->xMax_Extent);
- cairo_pdf_ft_font_write_be16 (font, hhea->caret_Slope_Rise);
- cairo_pdf_ft_font_write_be16 (font, hhea->caret_Slope_Run);
- cairo_pdf_ft_font_write_be16 (font, hhea->caret_Offset);
-
- cairo_pdf_ft_font_write_be16 (font, 0);
- cairo_pdf_ft_font_write_be16 (font, 0);
- cairo_pdf_ft_font_write_be16 (font, 0);
- cairo_pdf_ft_font_write_be16 (font, 0);
-
- cairo_pdf_ft_font_write_be16 (font, hhea->metric_Data_Format);
- cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs);
-
- return font->status;
-}
-
-static int
-cairo_pdf_ft_font_write_hmtx_table (cairo_pdf_ft_font_t *font,
- unsigned long tag)
-{
- unsigned long entry_size;
- short *p;
- int i;
-
- for (i = 0; i < font->base.num_glyphs; i++) {
- entry_size = 2 * sizeof (short);
- p = cairo_pdf_ft_font_write (font, NULL, entry_size);
- FT_Load_Sfnt_Table (font->face, TTAG_hmtx,
- font->glyphs[i].parent_index * entry_size,
- (FT_Byte *) p, &entry_size);
- font->base.widths[i] = be16_to_cpu (p[0]);
- }
-
- return font->status;
-}
-
-static int
-cairo_pdf_ft_font_write_loca_table (cairo_pdf_ft_font_t *font,
- unsigned long tag)
-{
- int i;
- TT_Header *header;
-
- header = FT_Get_Sfnt_Table (font->face, ft_sfnt_head);
-
- if (header->Index_To_Loc_Format == 0) {
- for (i = 0; i < font->base.num_glyphs + 1; i++)
- cairo_pdf_ft_font_write_be16 (font, font->glyphs[i].location / 2);
- }
- else {
- for (i = 0; i < font->base.num_glyphs + 1; i++)
- cairo_pdf_ft_font_write_be32 (font, font->glyphs[i].location);
- }
-
- return font->status;
-}
-
-static int
-cairo_pdf_ft_font_write_maxp_table (cairo_pdf_ft_font_t *font,
- unsigned long tag)
-{
- TT_MaxProfile *maxp;
-
- maxp = FT_Get_Sfnt_Table (font->face, ft_sfnt_maxp);
-
- cairo_pdf_ft_font_write_be32 (font, maxp->version);
- cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxPoints);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxContours);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxCompositePoints);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxCompositeContours);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxZones);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxTwilightPoints);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxStorage);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxFunctionDefs);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxInstructionDefs);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxStackElements);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxSizeOfInstructions);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxComponentElements);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxComponentDepth);
-
- return font->status;
-}
-
-typedef struct table table_t;
-struct table {
- unsigned long tag;
- int (*write) (cairo_pdf_ft_font_t *font, unsigned long tag);
-};
-
-static const table_t truetype_tables[] = {
- { TTAG_cmap, cairo_pdf_ft_font_write_cmap_table },
- { TTAG_cvt, cairo_pdf_ft_font_write_generic_table },
- { TTAG_fpgm, cairo_pdf_ft_font_write_generic_table },
- { TTAG_glyf, cairo_pdf_ft_font_write_glyf_table },
- { TTAG_head, cairo_pdf_ft_font_write_head_table },
- { TTAG_hhea, cairo_pdf_ft_font_write_hhea_table },
- { TTAG_hmtx, cairo_pdf_ft_font_write_hmtx_table },
- { TTAG_loca, cairo_pdf_ft_font_write_loca_table },
- { TTAG_maxp, cairo_pdf_ft_font_write_maxp_table },
- { TTAG_name, cairo_pdf_ft_font_write_generic_table },
- { TTAG_prep, cairo_pdf_ft_font_write_generic_table },
-};
-
-static cairo_status_t
-cairo_pdf_ft_font_write_offset_table (cairo_pdf_ft_font_t *font)
-{
- unsigned short search_range, entry_selector, range_shift;
- int num_tables;
-
- num_tables = ARRAY_LENGTH (truetype_tables);
- search_range = 1;
- entry_selector = 0;
- while (search_range * 2 <= num_tables) {
- search_range *= 2;
- entry_selector++;
- }
- search_range *= 16;
- range_shift = num_tables * 16 - search_range;
-
- cairo_pdf_ft_font_write_be32 (font, SFNT_VERSION);
- cairo_pdf_ft_font_write_be16 (font, num_tables);
- cairo_pdf_ft_font_write_be16 (font, search_range);
- cairo_pdf_ft_font_write_be16 (font, entry_selector);
- cairo_pdf_ft_font_write_be16 (font, range_shift);
-
- cairo_pdf_ft_font_write (font, NULL, ARRAY_LENGTH (truetype_tables) * 16);
-
- return font->status;
-}
-
-static unsigned long
-cairo_pdf_ft_font_calculate_checksum (cairo_pdf_ft_font_t *font,
- unsigned long start, unsigned long end)
-{
- unsigned long *padded_end;
- unsigned long *p;
- unsigned long checksum;
- char *data;
-
- checksum = 0;
- data = _cairo_array_index (&font->output, 0);
- p = (unsigned long *) (data + start);
- padded_end = (unsigned long *) (data + ((end + 3) & ~3));
- while (p < padded_end)
- checksum += *p++;
-
- return checksum;
-}
-
-static void
-cairo_pdf_ft_font_update_entry (cairo_pdf_ft_font_t *font, int index, unsigned long tag,
- unsigned long start, unsigned long end)
-{
- unsigned long *entry;
-
- entry = _cairo_array_index (&font->output, 12 + 16 * index);
- entry[0] = cpu_to_be32 (tag);
- entry[1] = cpu_to_be32 (cairo_pdf_ft_font_calculate_checksum (font, start, end));
- entry[2] = cpu_to_be32 (start);
- entry[3] = cpu_to_be32 (end - start);
-}
-
-static cairo_status_t
-cairo_pdf_ft_font_generate (void *abstract_font,
- const char **data, unsigned long *length)
-{
- cairo_pdf_ft_font_t *font = abstract_font;
- unsigned long start, end, next, checksum;
- int i;
-
- font->face = _cairo_ft_unscaled_font_lock_face (font->base.unscaled_font);
-
- if (cairo_pdf_ft_font_write_offset_table (font))
- goto fail;
-
- start = cairo_pdf_ft_font_align_output (font);
- end = start;
-
- end = 0;
- for (i = 0; i < ARRAY_LENGTH (truetype_tables); i++) {
- if (truetype_tables[i].write (font, truetype_tables[i].tag))
- goto fail;
-
- end = _cairo_array_num_elements (&font->output);
- next = cairo_pdf_ft_font_align_output (font);
- cairo_pdf_ft_font_update_entry (font, i, truetype_tables[i].tag,
- start, end);
- start = next;
- }
-
- checksum =
- 0xb1b0afba - cairo_pdf_ft_font_calculate_checksum (font, 0, end);
- *font->checksum_location = cpu_to_be32 (checksum);
-
- *data = _cairo_array_index (&font->output, 0);
- *length = _cairo_array_num_elements (&font->output);
-
- fail:
- _cairo_ft_unscaled_font_unlock_face (font->base.unscaled_font);
- font->face = NULL;
-
- return font->status;
-}
-
-static int
-cairo_pdf_ft_font_use_glyph (void *abstract_font, int glyph)
-{
- cairo_pdf_ft_font_t *font = abstract_font;
-
- if (font->parent_to_subset[glyph] == 0) {
- font->parent_to_subset[glyph] = font->base.num_glyphs;
- font->glyphs[font->base.num_glyphs].parent_index = glyph;
- font->base.num_glyphs++;
- }
-
- return font->parent_to_subset[glyph];
-}
-
-static cairo_pdf_font_backend_t cairo_pdf_ft_font_backend = {
- cairo_pdf_ft_font_use_glyph,
- cairo_pdf_ft_font_generate,
- cairo_pdf_ft_font_destroy
-};
-
-/* PDF Generation */
-
-static unsigned int
-_cairo_pdf_document_new_object (cairo_pdf_document_t *document)
-{
- cairo_pdf_object_t object;
-
- object.offset = ftell (document->file);
- if (_cairo_array_append (&document->objects, &object, 1) == NULL)
- return 0;
-
- return document->next_available_id++;
-}
-
-static void
-_cairo_pdf_document_update_object (cairo_pdf_document_t *document,
- unsigned int id)
-{
- cairo_pdf_object_t *object;
-
- object = _cairo_array_index (&document->objects, id - 1);
- object->offset = ftell (document->file);
-}
-
-static void
-_cairo_pdf_surface_add_stream (cairo_pdf_surface_t *surface,
- cairo_pdf_stream_t *stream)
-{
- _cairo_array_append (&surface->streams, &stream, 1);
- surface->current_stream = stream;
-}
-
-static void
-_cairo_pdf_surface_add_pattern (cairo_pdf_surface_t *surface, unsigned int id)
-{
- cairo_pdf_resource_t resource;
-
- resource.id = id;
- _cairo_array_append (&surface->patterns, &resource, 1);
-}
-
-static void
-_cairo_pdf_surface_add_xobject (cairo_pdf_surface_t *surface, unsigned int id)
-{
- cairo_pdf_resource_t resource;
- int i, num_resources;
-
- num_resources = _cairo_array_num_elements (&surface->xobjects);
- for (i = 0; i < num_resources; i++) {
- _cairo_array_copy_element (&surface->xobjects, i, &resource);
- if (resource.id == id)
- return;
- }
-
- resource.id = id;
- _cairo_array_append (&surface->xobjects, &resource, 1);
-}
-
-static unsigned int
-_cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface, double alpha)
-{
- int num_alphas, i;
- double other;
-
- num_alphas = _cairo_array_num_elements (&surface->alphas);
- for (i = 0; i < num_alphas; i++) {
- _cairo_array_copy_element (&surface->alphas, i, &other);
- if (alpha == other)
- return i;
- }
-
- _cairo_array_append (&surface->alphas, &alpha, 1);
- return _cairo_array_num_elements (&surface->alphas) - 1;
-}
-
-static void
-_cairo_pdf_surface_add_font (cairo_pdf_surface_t *surface, unsigned int id)
-{
- cairo_pdf_resource_t resource;
- int i, num_fonts;
-
- num_fonts = _cairo_array_num_elements (&surface->fonts);
- for (i = 0; i < num_fonts; i++) {
- _cairo_array_copy_element (&surface->fonts, i, &resource);
- if (resource.id == id)
- return;
- }
-
- resource.id = id;
- _cairo_array_append (&surface->fonts, &resource, 1);
-}
-
-cairo_surface_t *
-cairo_pdf_surface_create (FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch)
-{
- cairo_pdf_document_t *document;
- cairo_surface_t *surface;
-
- document = _cairo_pdf_document_create (file,
- width_inches,
- height_inches,
- x_pixels_per_inch,
- y_pixels_per_inch);
- if (document == NULL)
- return NULL;
-
- surface = _cairo_pdf_surface_create_for_document (document,
- width_inches,
- height_inches);
-
- _cairo_pdf_document_destroy (document);
-
- return surface;
-}
-
-static cairo_surface_t *
-_cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document,
- double width_inches,
- double height_inches)
-{
- cairo_pdf_surface_t *surface;
-
- surface = malloc (sizeof (cairo_pdf_surface_t));
- if (surface == NULL)
- return NULL;
-
- _cairo_surface_init (&surface->base, &cairo_pdf_surface_backend);
-
- surface->width_inches = width_inches;
- surface->height_inches = height_inches;
-
- _cairo_pdf_document_reference (document);
- surface->document = document;
- _cairo_array_init (&surface->streams, sizeof (cairo_pdf_stream_t *));
- _cairo_array_init (&surface->patterns, sizeof (cairo_pdf_resource_t));
- _cairo_array_init (&surface->xobjects, sizeof (cairo_pdf_resource_t));
- _cairo_array_init (&surface->alphas, sizeof (double));
- _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_resource_t));
-
- return &surface->base;
-}
-
-static void
-_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
-{
- int num_streams, i;
- cairo_pdf_stream_t *stream;
-
- num_streams = _cairo_array_num_elements (&surface->streams);
- for (i = 0; i < num_streams; i++) {
- _cairo_array_copy_element (&surface->streams, i, &stream);
- free (stream);
- }
-
- _cairo_array_truncate (&surface->streams, 0);
- _cairo_array_truncate (&surface->patterns, 0);
- _cairo_array_truncate (&surface->xobjects, 0);
- _cairo_array_truncate (&surface->alphas, 0);
- _cairo_array_truncate (&surface->fonts, 0);
-}
-
-static cairo_surface_t *
-_cairo_pdf_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- cairo_pdf_surface_t *template = abstract_src;
-
- return _cairo_pdf_surface_create_for_document (template->document,
- width, height);
-}
-
-static cairo_pdf_stream_t *
-_cairo_pdf_document_open_stream (cairo_pdf_document_t *document,
- const char *extra_entries)
-{
- FILE *file = document->file;
- cairo_pdf_stream_t *stream;
-
- stream = malloc (sizeof (cairo_pdf_stream_t));
- if (stream == NULL) {
- return NULL;
- }
-
- stream->id = _cairo_pdf_document_new_object (document);
- stream->length_id = _cairo_pdf_document_new_object (document);
-
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Length %d 0 R\r\n"
- "%s"
- ">>\r\n"
- "stream\r\n",
- stream->id,
- stream->length_id,
- extra_entries);
-
- stream->start_offset = ftell (file);
-
- document->current_stream = stream;
-
- return stream;
-}
-
-static void
-_cairo_pdf_document_close_stream (cairo_pdf_document_t *document)
-{
- FILE *file = document->file;
- long length;
- cairo_pdf_stream_t *stream;
-
- stream = document->current_stream;
- if (stream == NULL)
- return;
-
- length = ftell(file) - stream->start_offset;
- fprintf (file,
- "\r\n"
- "endstream\r\n"
- "endobj\r\n");
-
- _cairo_pdf_document_update_object (document, stream->length_id);
- fprintf (file,
- "%d 0 obj\r\n"
- " %ld\r\n"
- "endobj\r\n",
- stream->length_id,
- length);
-
- document->current_stream = NULL;
-}
-
-static void
-_cairo_pdf_surface_destroy (void *abstract_surface)
-{
- cairo_pdf_surface_t *surface = abstract_surface;
- cairo_pdf_document_t *document = surface->document;
-
- if (surface->current_stream == document->current_stream)
- _cairo_pdf_document_close_stream (document);
-
- _cairo_pdf_document_destroy (document);
-
- free (surface);
-}
-
-/* XXX: We should re-work this interface to return both X/Y ppi values. */
-static double
-_cairo_pdf_surface_pixels_per_inch (void *abstract_surface)
-{
- cairo_pdf_surface_t *surface = abstract_surface;
-
- return surface->document->y_ppi;
-}
-
-static void
-_cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface)
-{
- cairo_pdf_document_t *document = surface->document;
- cairo_pdf_stream_t *stream;
- FILE *file = document->file;
- char extra[200];
-
- if (document->current_stream == NULL ||
- document->current_stream != surface->current_stream) {
- _cairo_pdf_document_close_stream (document);
- snprintf (extra, sizeof extra,
- " /Type /XObject\r\n"
- " /Subtype /Form\r\n"
- " /BBox [ 0 0 %f %f ]\r\n",
- surface->width_inches * document->x_ppi,
- surface->height_inches * document->y_ppi);
- stream = _cairo_pdf_document_open_stream (document, extra);
- _cairo_pdf_surface_add_stream (surface, stream);
-
- /* If this is the first stream we open for this surface,
- * output the cairo to PDF transformation matrix. */
- if (_cairo_array_num_elements (&surface->streams) == 1)
- fprintf (file, "1 0 0 -1 0 %f cm\r\n",
- document->height_inches * document->y_ppi);
- }
-}
-
-static cairo_status_t
-_cairo_pdf_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static void
-_cairo_pdf_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_pdf_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect,
- void **image_extra)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static void
-_cairo_pdf_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_pdf_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static void *
-compress_dup (const void *data, unsigned long data_size,
- unsigned long *compressed_size)
-{
- void *compressed;
-
- /* Bound calculation taken from zlib. */
- *compressed_size = data_size + (data_size >> 12) + (data_size >> 14) + 11;
- compressed = malloc (*compressed_size);
- if (compressed == NULL)
- return NULL;
-
- compress (compressed, compressed_size, data, data_size);
-
- return compressed;
-}
-
-static unsigned int
-emit_image_data (cairo_pdf_document_t *document,
- cairo_image_surface_t *image)
-{
- FILE *file = document->file;
- cairo_pdf_stream_t *stream;
- char entries[200];
- char *rgb, *compressed;
- int i, x, y;
- unsigned long rgb_size, compressed_size;
- pixman_bits_t *pixel;
-
- rgb_size = image->height * image->width * 3;
- rgb = malloc (rgb_size);
- if (rgb == NULL)
- return 0;
-
- i = 0;
- for (y = 0; y < image->height; y++) {
- pixel = (pixman_bits_t *) (image->data + y * image->stride);
-
- for (x = 0; x < image->width; x++, pixel++) {
- rgb[i++] = (*pixel & 0x00ff0000) >> 16;
- rgb[i++] = (*pixel & 0x0000ff00) >> 8;
- rgb[i++] = (*pixel & 0x000000ff) >> 0;
- }
- }
-
- compressed = compress_dup (rgb, rgb_size, &compressed_size);
- if (compressed == NULL) {
- free (rgb);
- return 0;
- }
-
- _cairo_pdf_document_close_stream (document);
-
- snprintf (entries, sizeof entries,
- " /Type /XObject\r\n"
- " /Subtype /Image\r\n"
- " /Width %d\r\n"
- " /Height %d\r\n"
- " /ColorSpace /DeviceRGB\r\n"
- " /BitsPerComponent 8\r\n"
- " /Filter /FlateDecode\r\n",
- image->width, image->height);
-
- stream = _cairo_pdf_document_open_stream (document, entries);
- fwrite (compressed, 1, compressed_size, file);
- _cairo_pdf_document_close_stream (document);
-
- free (rgb);
- free (compressed);
-
- return stream->id;
-}
-
-static cairo_int_status_t
-_cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst,
- cairo_surface_pattern_t *pattern)
-{
- cairo_pdf_document_t *document = dst->document;
- FILE *file = document->file;
- unsigned id;
- cairo_matrix_t i2u;
- cairo_status_t status;
- cairo_image_surface_t *image;
- cairo_surface_t *src;
- void *image_extra;
-
- src = pattern->surface;
- status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
- if (!CAIRO_OK (status))
- return status;
-
- id = emit_image_data (dst->document, image);
- if (id == 0) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto bail;
- }
-
- _cairo_pdf_surface_add_xobject (dst, id);
-
- _cairo_pdf_surface_ensure_stream (dst);
-
- cairo_matrix_copy (&i2u, &pattern->base.matrix);
- cairo_matrix_invert (&i2u);
- cairo_matrix_translate (&i2u, 0, image->height);
- cairo_matrix_scale (&i2u, image->width, -image->height);
-
- fprintf (file,
- "q %f %f %f %f %f %f cm /res%d Do Q\r\n",
- i2u.m[0][0], i2u.m[0][1],
- i2u.m[1][0], i2u.m[1][1],
- i2u.m[2][0], i2u.m[2][1],
- id);
-
- bail:
- _cairo_surface_release_source_image (src, image, image_extra);
-
- return status;
-}
-
-/* The contents of the surface is already transformed into PDF units,
- * but when we composite the surface we may want to use a different
- * space. The problem I see now is that the show_surface snippet
- * creates a surface 1x1, which in the snippet environment is the
- * entire surface. When compositing the surface, cairo gives us the
- * 1x1 to 256x256 matrix. This would be fine if cairo didn't actually
- * also transform the drawing to the surface. Should the CTM be part
- * of the current target surface?
- */
-
-static cairo_int_status_t
-_cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst,
- cairo_surface_pattern_t *pattern)
-{
- cairo_pdf_document_t *document = dst->document;
- FILE *file = document->file;
- cairo_matrix_t i2u;
- cairo_pdf_stream_t *stream;
- int num_streams, i;
- cairo_pdf_surface_t *src;
-
- _cairo_pdf_surface_ensure_stream (dst);
-
- src = (cairo_pdf_surface_t *) pattern->surface;
-
- cairo_matrix_copy (&i2u, &src->base.matrix);
- cairo_matrix_invert (&i2u);
- cairo_matrix_scale (&i2u,
- 1.0 / (src->width_inches * document->x_ppi),
- 1.0 / (src->height_inches * document->y_ppi));
-
- fprintf (file,
- "q %f %f %f %f %f %f cm",
- i2u.m[0][0], i2u.m[0][1],
- i2u.m[1][0], i2u.m[1][1],
- i2u.m[2][0], i2u.m[2][1]);
-
- num_streams = _cairo_array_num_elements (&src->streams);
- for (i = 0; i < num_streams; i++) {
- _cairo_array_copy_element (&src->streams, i, &stream);
- fprintf (file,
- " /res%d Do",
- stream->id);
-
- _cairo_pdf_surface_add_xobject (dst, stream->id);
-
- }
-
- fprintf (file, " Q\r\n");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_pdf_surface_composite (cairo_operator_t operator,
- cairo_pattern_t *src_pattern,
- cairo_pattern_t *mask_pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- cairo_pdf_surface_t *dst = abstract_dst;
- cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) src_pattern;
-
- if (mask_pattern)
- return CAIRO_STATUS_SUCCESS;
-
- if (src_pattern->type != CAIRO_PATTERN_SURFACE)
- return CAIRO_STATUS_SUCCESS;
-
- if (src->surface->backend == &cairo_pdf_surface_backend)
- return _cairo_pdf_surface_composite_pdf (dst, src);
- else
- return _cairo_pdf_surface_composite_image (dst, src);
-}
-
-static cairo_int_status_t
-_cairo_pdf_surface_fill_rectangles (void *abstract_surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- cairo_pdf_surface_t *surface = abstract_surface;
- cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
- int i;
-
- _cairo_pdf_surface_ensure_stream (surface);
-
- fprintf (file,
- "%f %f %f rg\r\n",
- color->red, color->green, color->blue);
-
- for (i = 0; i < num_rects; i++) {
- fprintf (file,
- "%d %d %d %d re f\r\n",
- rects[i].x, rects[i].y,
- rects[i].width, rects[i].height);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-emit_solid_pattern (cairo_pdf_surface_t *surface,
- cairo_solid_pattern_t *pattern)
-{
- cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
- unsigned int alpha;
-
- alpha = _cairo_pdf_surface_add_alpha (surface, pattern->base.alpha);
- _cairo_pdf_surface_ensure_stream (surface);
- fprintf (file,
- "%f %f %f rg /a%d gs\r\n",
- pattern->red,
- pattern->green,
- pattern->blue,
- alpha);
-}
-
-static void
-emit_surface_pattern (cairo_pdf_surface_t *dst,
- cairo_surface_pattern_t *pattern)
-{
- cairo_pdf_document_t *document = dst->document;
- FILE *file = document->file;
- cairo_pdf_stream_t *stream;
- cairo_image_surface_t *image;
- void *image_extra;
- cairo_status_t status;
- char entries[250];
- unsigned int id, alpha;
- cairo_matrix_t pm;
-
- if (pattern->surface->backend == &cairo_pdf_surface_backend) {
- return;
- }
-
- status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
- if (!CAIRO_OK (status))
- return;
-
- _cairo_pdf_document_close_stream (document);
-
- id = emit_image_data (dst->document, image);
-
- /* BBox must be smaller than XStep by YStep or acroread wont
- * display the pattern. */
-
- cairo_matrix_set_identity (&pm);
- cairo_matrix_scale (&pm, image->width, image->height);
- cairo_matrix_copy (&pm, &pattern->base.matrix);
- cairo_matrix_invert (&pm);
-
- snprintf (entries, sizeof entries,
- " /BBox [ 0 0 256 256 ]\r\n"
- " /XStep 256\r\n"
- " /YStep 256\r\n"
- " /PatternType 1\r\n"
- " /TilingType 1\r\n"
- " /PaintType 1\r\n"
- " /Resources << /XObject << /res%d %d 0 R >> >>\r\n"
- " /Matrix [ %f %f %f %f %f %f ]\r\n",
- id, id,
- pm.m[0][0], pm.m[0][1],
- pm.m[1][0], pm.m[1][1],
- pm.m[2][0], pm.m[2][1]);
-
- stream = _cairo_pdf_document_open_stream (document, entries);
-
- /* FIXME: emit code to show surface here. */
-
- _cairo_pdf_surface_add_pattern (dst, stream->id);
-
- _cairo_pdf_surface_ensure_stream (dst);
- alpha = _cairo_pdf_surface_add_alpha (dst, 1.0);
- fprintf (file,
- "/Pattern cs /res%d scn /a%d gs\r\n",
- stream->id, alpha);
-
- _cairo_surface_release_source_image (pattern->surface, image, image_extra);
-}
-
-static unsigned int
-emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern)
-{
- cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
- unsigned int function_id;
-
- function_id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /FunctionType 0\r\n"
- " /Domain [ 0.0 1.0 ]\r\n"
- " /Size [ 2 ]\r\n"
- " /BitsPerSample 8\r\n"
- " /Range [ 0.0 1.0 0.0 1.0 0.0 1.0 ]\r\n"
- " /Length 6\r\n"
- ">>\r\n"
- "stream\r\n",
- function_id);
-
- fputc (pattern->stops[0].color.red * 0xff, file);
- fputc (pattern->stops[0].color.green * 0xff, file);
- fputc (pattern->stops[0].color.blue * 0xff, file);
- fputc (pattern->stops[1].color.red * 0xff, file);
- fputc (pattern->stops[1].color.green * 0xff, file);
- fputc (pattern->stops[1].color.blue * 0xff, file);
-
- fprintf (file,
- "\r\n"
- "endstream\r\n"
- "endobj\r\n");
-
- return function_id;
-}
-
-static void
-emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *pattern)
-{
- cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
- unsigned int function_id, pattern_id, alpha;
- double x0, y0, x1, y1;
- cairo_matrix_t p2u;
-
- _cairo_pdf_document_close_stream (document);
-
- function_id = emit_pattern_stops (surface, &pattern->base);
-
- cairo_matrix_copy (&p2u, &pattern->base.base.matrix);
- cairo_matrix_invert (&p2u);
-
- x0 = pattern->point0.x;
- y0 = pattern->point0.y;
- cairo_matrix_transform_point (&p2u, &x0, &y0);
- x1 = pattern->point1.x;
- y1 = pattern->point1.y;
- cairo_matrix_transform_point (&p2u, &x1, &y1);
-
- pattern_id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Type /Pattern\r\n"
- " /PatternType 2\r\n"
- " /Matrix [ 1 0 0 -1 0 %f ]\r\n"
- " /Shading\r\n"
- " << /ShadingType 2\r\n"
- " /ColorSpace /DeviceRGB\r\n"
- " /Coords [ %f %f %f %f ]\r\n"
- " /Function %d 0 R\r\n"
- " /Extend [ true true ]\r\n"
- " >>\r\n"
- ">>\r\n"
- "endobj\r\n",
- pattern_id,
- document->height_inches * document->y_ppi,
- x0, y0, x1, y1,
- function_id);
-
- _cairo_pdf_surface_add_pattern (surface, pattern_id);
-
- _cairo_pdf_surface_ensure_stream (surface);
- alpha = _cairo_pdf_surface_add_alpha (surface, 1.0);
-
- /* Use pattern */
- fprintf (file,
- "/Pattern cs /res%d scn /a%d gs\r\n",
- pattern_id, alpha);
-}
-
-static void
-emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *pattern)
-{
- cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
- unsigned int function_id, pattern_id, alpha;
- double x0, y0, x1, y1, r0, r1;
- cairo_matrix_t p2u;
-
- _cairo_pdf_document_close_stream (document);
-
- function_id = emit_pattern_stops (surface, &pattern->base);
-
- cairo_matrix_copy (&p2u, &pattern->base.base.matrix);
- cairo_matrix_invert (&p2u);
-
- x0 = pattern->center0.x;
- y0 = pattern->center0.y;
- r0 = pattern->radius0;
- cairo_matrix_transform_point (&p2u, &x0, &y0);
- x1 = pattern->center1.x;
- y1 = pattern->center1.y;
- r1 = pattern->radius1;
- cairo_matrix_transform_point (&p2u, &x1, &y1);
-
- /* FIXME: This is surely crack, but how should you scale a radius
- * in a non-orthogonal coordinate system? */
- cairo_matrix_transform_distance (&p2u, &r0, &r1);
-
- /* FIXME: There is a difference between the cairo gradient extend
- * semantics and PDF extend semantics. PDFs extend=false means
- * that nothing is painted outside the gradient boundaries,
- * whereas cairo takes this to mean that the end color is padded
- * to infinity. Setting extend=true in PDF gives the cairo default
- * behavoir, not yet sure how to implement the cairo mirror and
- * repeat behaviour. */
- pattern_id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Type /Pattern\r\n"
- " /PatternType 2\r\n"
- " /Matrix [ 1 0 0 -1 0 %f ]\r\n"
- " /Shading\r\n"
- " << /ShadingType 3\r\n"
- " /ColorSpace /DeviceRGB\r\n"
- " /Coords [ %f %f %f %f %f %f ]\r\n"
- " /Function %d 0 R\r\n"
- " /Extend [ true true ]\r\n"
- " >>\r\n"
- ">>\r\n"
- "endobj\r\n",
- pattern_id,
- document->height_inches * document->y_ppi,
- x0, y0, r0, x1, y1, r1,
- function_id);
-
- _cairo_pdf_surface_add_pattern (surface, pattern_id);
-
- _cairo_pdf_surface_ensure_stream (surface);
- alpha = _cairo_pdf_surface_add_alpha (surface, 1.0);
-
- /* Use pattern */
- fprintf (file,
- "/Pattern cs /res%d scn /a%d gs\r\n",
- pattern_id, alpha);
-}
-
-static void
-emit_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
-{
- switch (pattern->type) {
- case CAIRO_PATTERN_SOLID:
- emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
- break;
-
- case CAIRO_PATTERN_SURFACE:
- emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern);
- break;
-
- case CAIRO_PATTERN_LINEAR:
- emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern);
- break;
-
- case CAIRO_PATTERN_RADIAL:
- emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern);
- break;
- }
-}
-
-static double
-intersect (cairo_line_t *line, cairo_fixed_t y)
-{
- return _cairo_fixed_to_double (line->p1.x) +
- _cairo_fixed_to_double (line->p2.x - line->p1.x) *
- _cairo_fixed_to_double (y - line->p1.y) /
- _cairo_fixed_to_double (line->p2.y - line->p1.y);
-}
-
-static cairo_int_status_t
-_cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_dst,
- int x_src,
- int y_src,
- int x_dst,
- int y_dst,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- cairo_pdf_surface_t *surface = abstract_dst;
- cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
- int i;
-
- emit_pattern (surface, pattern);
-
- /* After the above switch the current stream should belong to this
- * surface, so no need to _cairo_pdf_surface_ensure_stream() */
- assert (document->current_stream != NULL &&
- document->current_stream == surface->current_stream);
-
- for (i = 0; i < num_traps; i++) {
- double left_x1, left_x2, right_x1, right_x2;
-
- left_x1 = intersect (&traps[i].left, traps[i].top);
- left_x2 = intersect (&traps[i].left, traps[i].bottom);
- right_x1 = intersect (&traps[i].right, traps[i].top);
- right_x2 = intersect (&traps[i].right, traps[i].bottom);
-
- fprintf (file,
- "%f %f m %f %f l %f %f l %f %f l h\r\n",
- left_x1, _cairo_fixed_to_double (traps[i].top),
- left_x2, _cairo_fixed_to_double (traps[i].bottom),
- right_x2, _cairo_fixed_to_double (traps[i].bottom),
- right_x1, _cairo_fixed_to_double (traps[i].top));
- }
-
- fprintf (file,
- "f\r\n");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_pdf_surface_copy_page (void *abstract_surface)
-{
- cairo_pdf_surface_t *surface = abstract_surface;
- cairo_pdf_document_t *document = surface->document;
-
- return _cairo_pdf_document_add_page (document, surface);
-}
-
-static cairo_int_status_t
-_cairo_pdf_surface_show_page (void *abstract_surface)
-{
- cairo_pdf_surface_t *surface = abstract_surface;
- cairo_pdf_document_t *document = surface->document;
- cairo_int_status_t status;
-
- status = _cairo_pdf_document_add_page (document, surface);
- if (status == CAIRO_STATUS_SUCCESS)
- _cairo_pdf_surface_clear (surface);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_pdf_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_pdf_font_t *
-_cairo_pdf_document_get_font (cairo_pdf_document_t *document,
- cairo_font_t *font)
-{
- cairo_unscaled_font_t *unscaled_font;
- cairo_pdf_font_t *pdf_font;
- unsigned int num_fonts, i;
-
- unscaled_font = _cairo_ft_font_get_unscaled_font (font);
-
- num_fonts = _cairo_array_num_elements (&document->fonts);
- for (i = 0; i < num_fonts; i++) {
- _cairo_array_copy_element (&document->fonts, i, &pdf_font);
- if (pdf_font->unscaled_font == unscaled_font)
- return pdf_font;
- }
-
- /* FIXME: Figure out here which font backend is in use and call
- * the appropriate constructor. */
- pdf_font = cairo_pdf_ft_font_create (document, unscaled_font);
- if (pdf_font == NULL)
- return NULL;
-
- if (_cairo_array_append (&document->fonts, &pdf_font, 1) == NULL) {
- cairo_pdf_font_destroy (pdf_font);
- return NULL;
- }
-
- return pdf_font;
-}
-
-static cairo_status_t
-_cairo_pdf_surface_show_glyphs (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_pdf_surface_t *surface = abstract_surface;
- cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
- cairo_pdf_font_t *pdf_font;
- int i, index;
-
- pdf_font = _cairo_pdf_document_get_font (document, font);
- if (pdf_font == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- emit_pattern (surface, pattern);
-
- fprintf (file, "BT /res%u 1 Tf", pdf_font->font_id);
- for (i = 0; i < num_glyphs; i++) {
-
- index = cairo_pdf_font_use_glyph (pdf_font, glyphs[i].index);
-
- fprintf (file,
- " %f %f %f %f %f %f Tm (\\%o) Tj",
- font->scale.matrix[0][0],
- font->scale.matrix[0][1],
- font->scale.matrix[1][0],
- -font->scale.matrix[1][1],
- glyphs[i].x,
- glyphs[i].y,
- index);
- }
- fprintf (file, " ET\r\n");
-
- _cairo_pdf_surface_add_font (surface, pdf_font->font_id);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static const cairo_surface_backend_t cairo_pdf_surface_backend = {
- _cairo_pdf_surface_create_similar,
- _cairo_pdf_surface_destroy,
- _cairo_pdf_surface_pixels_per_inch,
- _cairo_pdf_surface_acquire_source_image,
- _cairo_pdf_surface_release_source_image,
- _cairo_pdf_surface_acquire_dest_image,
- _cairo_pdf_surface_release_dest_image,
- _cairo_pdf_surface_clone_similar,
- _cairo_pdf_surface_composite,
- _cairo_pdf_surface_fill_rectangles,
- _cairo_pdf_surface_composite_trapezoids,
- _cairo_pdf_surface_copy_page,
- _cairo_pdf_surface_show_page,
- _cairo_pdf_surface_set_clip_region,
- _cairo_pdf_surface_show_glyphs
-};
-
-static cairo_pdf_document_t *
-_cairo_pdf_document_create (FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch)
-{
- cairo_pdf_document_t *document;
-
- document = malloc (sizeof (cairo_pdf_document_t));
- if (document == NULL)
- return NULL;
-
- document->file = file;
- document->refcount = 1;
- document->width_inches = width_inches;
- document->height_inches = height_inches;
- document->x_ppi = x_pixels_per_inch;
- document->y_ppi = y_pixels_per_inch;
-
- _cairo_array_init (&document->objects, sizeof (cairo_pdf_object_t));
- _cairo_array_init (&document->pages, sizeof (unsigned int));
- document->next_available_id = 1;
-
- document->current_stream = NULL;
-
- document->pages_id = _cairo_pdf_document_new_object (document);
-
- _cairo_array_init (&document->fonts, sizeof (cairo_pdf_font_t *));
-
- /* Document header */
- fprintf (file, "%%PDF-1.4\r\n");
-
- return document;
-}
-
-static unsigned int
-_cairo_pdf_document_write_info (cairo_pdf_document_t *document)
-{
- FILE *file = document->file;
- unsigned int id;
-
- id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Creator (cairographics.org)\r\n"
- " /Producer (cairographics.org)\r\n"
- ">>\r\n"
- "endobj\r\n",
- id);
-
- return id;
-}
-
-static void
-_cairo_pdf_document_write_pages (cairo_pdf_document_t *document)
-{
- FILE *file = document->file;
- unsigned int page_id;
- int num_pages, i;
-
- _cairo_pdf_document_update_object (document, document->pages_id);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Type /Pages\r\n"
- " /Kids [ ",
- document->pages_id);
-
- num_pages = _cairo_array_num_elements (&document->pages);
- for (i = 0; i < num_pages; i++) {
- _cairo_array_copy_element (&document->pages, i, &page_id);
- fprintf (file, "%d 0 R ", page_id);
- }
-
- fprintf (file, "]\r\n");
- fprintf (file, " /Count %d\r\n", num_pages);
-
- /* TODO: Figure out wich other defaults to be inherited by /Page
- * objects. */
- fprintf (file,
- " /MediaBox [ 0 0 %f %f ]\r\n"
- ">>\r\n"
- "endobj\r\n",
- document->width_inches * document->x_ppi,
- document->height_inches * document->y_ppi);
-}
-
-static cairo_status_t
-_cairo_pdf_document_write_fonts (cairo_pdf_document_t *document)
-{
- FILE *file = document->file;
- cairo_pdf_font_t *font;
- int num_fonts, i, j;
- const char *data;
- char *compressed;
- unsigned long data_size, compressed_size;
- unsigned int stream_id, descriptor_id;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
- num_fonts = _cairo_array_num_elements (&document->fonts);
- for (i = 0; i < num_fonts; i++) {
- _cairo_array_copy_element (&document->fonts, i, &font);
-
- status = cairo_pdf_font_generate (font, &data, &data_size);
- if (status)
- goto fail;
-
- compressed = compress_dup (data, data_size, &compressed_size);
- if (compressed == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto fail;
- }
-
- stream_id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Filter /FlateDecode\r\n"
- " /Length %lu\r\n"
- " /Length1 %lu\r\n"
- ">>\r\n"
- "stream\r\n",
- stream_id,
- compressed_size,
- data_size);
- fwrite (compressed, 1, compressed_size, file);
- fprintf (file,
- "\r\n"
- "endstream\r\n"
- "endobj\r\n");
- free (compressed);
-
- descriptor_id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Type /FontDescriptor\r\n"
- " /FontName /7%s\r\n"
- " /Flags 4\r\n"
- " /FontBBox [ %ld %ld %ld %ld ]\r\n"
- " /ItalicAngle 0\r\n"
- " /Ascent %ld\r\n"
- " /Descent %ld\r\n"
- " /CapHeight 500\r\n"
- " /StemV 80\r\n"
- " /StemH 80\r\n"
- " /FontFile2 %u 0 R\r\n"
- ">>\r\n"
- "endobj\r\n",
- descriptor_id,
- font->base_font,
- font->x_min,
- font->y_min,
- font->x_max,
- font->y_max,
- font->ascent,
- font->descent,
- stream_id);
-
- _cairo_pdf_document_update_object (document, font->font_id);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Type /Font\r\n"
- " /Subtype /TrueType\r\n"
- " /BaseFont /%s\r\n"
- " /FirstChar 0\r\n"
- " /LastChar %d\r\n"
- " /FontDescriptor %d 0 R\r\n"
- " /Widths ",
- font->font_id,
- font->base_font,
- font->num_glyphs,
- descriptor_id);
-
- fprintf (file,
- "[");
-
- for (j = 0; j < font->num_glyphs; j++)
- fprintf (file,
- " %d",
- font->widths[j]);
-
- fprintf (file,
- " ]\r\n"
- ">>\r\n"
- "endobj\r\n");
-
- fail:
- cairo_pdf_ft_font_destroy (font);
- }
-
- return status;
-}
-
-static unsigned int
-_cairo_pdf_document_write_catalog (cairo_pdf_document_t *document)
-{
- FILE *file = document->file;
- unsigned int id;
-
- id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Type /Catalog\r\n"
- " /Pages %d 0 R\r\n"
- ">>\r\n"
- "endobj\r\n",
- id, document->pages_id);
-
- return id;
-}
-
-static long
-_cairo_pdf_document_write_xref (cairo_pdf_document_t *document)
-{
- FILE *file = document->file;
- cairo_pdf_object_t *object;
- int num_objects, i;
- long offset;
-
- num_objects = _cairo_array_num_elements (&document->objects);
-
- offset = ftell(file);
- fprintf (document->file,
- "xref\r\n"
- "%d %d\r\n",
- 0, num_objects + 1);
-
- fprintf (file, "0000000000 65535 f\r\n");
- for (i = 0; i < num_objects; i++) {
- object = _cairo_array_index (&document->objects, i);
- fprintf (file, "%010ld 00000 n\r\n", object->offset);
- }
-
- return offset;
-}
-
-static void
-_cairo_pdf_document_reference (cairo_pdf_document_t *document)
-{
- document->refcount++;
-}
-
-static void
-_cairo_pdf_document_destroy (cairo_pdf_document_t *document)
-{
- FILE *file = document->file;
- long offset;
- unsigned int info_id, catalog_id;
-
- document->refcount--;
- if (document->refcount > 0)
- return;
-
- _cairo_pdf_document_close_stream (document);
- _cairo_pdf_document_write_pages (document);
- _cairo_pdf_document_write_fonts (document);
- info_id = _cairo_pdf_document_write_info (document);
- catalog_id = _cairo_pdf_document_write_catalog (document);
- offset = _cairo_pdf_document_write_xref (document);
-
- fprintf (file,
- "trailer\r\n"
- "<< /Size %d\r\n"
- " /Root %d 0 R\r\n"
- " /Info %d 0 R\r\n"
- ">>\r\n",
- document->next_available_id,
- catalog_id,
- info_id);
-
- fprintf (file,
- "startxref\r\n"
- "%ld\r\n"
- "%%%%EOF\r\n",
- offset);
-
- free (document);
-}
-
-static cairo_status_t
-_cairo_pdf_document_add_page (cairo_pdf_document_t *document,
- cairo_pdf_surface_t *surface)
-{
- cairo_pdf_stream_t *stream;
- cairo_pdf_resource_t *res;
- FILE *file = document->file;
- unsigned int page_id;
- double alpha;
- int num_streams, num_alphas, num_resources, i;
-
- _cairo_pdf_document_close_stream (document);
-
- page_id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /Type /Page\r\n"
- " /Parent %d 0 R\r\n"
- " /Contents [",
- page_id,
- document->pages_id);
-
- num_streams = _cairo_array_num_elements (&surface->streams);
- for (i = 0; i < num_streams; i++) {
- _cairo_array_copy_element (&surface->streams, i, &stream);
- fprintf (file,
- " %d 0 R",
- stream->id);
- }
-
- fprintf (file,
- " ]\r\n"
- " /Resources <<\r\n");
-
- num_resources = _cairo_array_num_elements (&surface->fonts);
- if (num_resources > 0) {
- fprintf (file,
- " /Font <<");
-
- for (i = 0; i < num_resources; i++) {
- res = _cairo_array_index (&surface->fonts, i);
- fprintf (file,
- " /res%d %d 0 R",
- res->id, res->id);
- }
-
- fprintf (file,
- " >>\r\n");
- }
-
- num_alphas = _cairo_array_num_elements (&surface->alphas);
- if (num_alphas > 0) {
- fprintf (file,
- " /ExtGState <<\r\n");
-
- for (i = 0; i < num_alphas; i++) {
- _cairo_array_copy_element (&surface->alphas, i, &alpha);
- fprintf (file,
- " /a%d << /ca %f >>\r\n",
- i, alpha);
- }
-
- fprintf (file,
- " >>\r\n");
- }
-
- num_resources = _cairo_array_num_elements (&surface->patterns);
- if (num_resources > 0) {
- fprintf (file,
- " /Pattern <<");
- for (i = 0; i < num_resources; i++) {
- res = _cairo_array_index (&surface->patterns, i);
- fprintf (file,
- " /res%d %d 0 R",
- res->id, res->id);
- }
-
- fprintf (file,
- " >>\r\n");
- }
-
- num_resources = _cairo_array_num_elements (&surface->xobjects);
- if (num_resources > 0) {
- fprintf (file,
- " /XObject <<");
-
- for (i = 0; i < num_resources; i++) {
- res = _cairo_array_index (&surface->xobjects, i);
- fprintf (file,
- " /res%d %d 0 R",
- res->id, res->id);
- }
-
- fprintf (file,
- " >>\r\n");
- }
-
- fprintf (file,
- " >>\r\n"
- ">>\r\n"
- "endobj\r\n");
-
- _cairo_array_append (&document->pages, &page_id, 1);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-cairo_set_target_pdf (cairo_t *cr,
- FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch)
-{
- cairo_surface_t *surface;
-
- surface = cairo_pdf_surface_create (file,
- width_inches,
- height_inches,
- x_pixels_per_inch,
- y_pixels_per_inch);
-
- if (surface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface (cr, surface);
-
- /* cairo_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy (surface);
-}
diff --git a/src/cairo_pen.c b/src/cairo_pen.c
deleted file mode 100644
index 6ecaa00b3..000000000
--- a/src/cairo_pen.c
+++ /dev/null
@@ -1,587 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2002 University of Southern California
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#include "cairoint.h"
-
-static int
-_cairo_pen_vertices_needed (double tolerance, double radius, cairo_matrix_t *matrix);
-
-static void
-_cairo_pen_compute_slopes (cairo_pen_t *pen);
-
-static cairo_status_t
-_cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_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->vertices = 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;
- int reflect;
- double det;
-
- 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;
-
- _cairo_matrix_compute_determinant (&gstate->ctm, &det);
- if (det >= 0) {
- reflect = 0;
- } else {
- reflect = 1;
- }
-
- pen->num_vertices = _cairo_pen_vertices_needed (gstate->tolerance,
- radius,
- &gstate->ctm);
-
- pen->vertices = malloc (pen->num_vertices * sizeof (cairo_pen_vertex_t));
- if (pen->vertices == NULL) {
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- /*
- * Compute pen coordinates. To generate the right ellipse, compute points around
- * a circle in user space and transform them to device space. To get a consistent
- * orientation in device space, flip the pen if the transformation matrix
- * is reflecting
- */
- for (i=0; i < pen->num_vertices; i++) {
- double theta = 2 * M_PI * i / (double) pen->num_vertices;
- double dx = radius * cos (reflect ? -theta : theta);
- double dy = radius * sin (reflect ? -theta : theta);
- cairo_pen_vertex_t *v = &pen->vertices[i];
- cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
- v->point.x = _cairo_fixed_from_double (dx);
- v->point.y = _cairo_fixed_from_double (dy);
- }
-
- _cairo_pen_compute_slopes (pen);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_pen_fini (cairo_pen_t *pen)
-{
- free (pen->vertices);
- pen->vertices = NULL;
-
- _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->vertices = malloc (pen->num_vertices * sizeof (cairo_pen_vertex_t));
- if (pen->vertices == NULL) {
- return CAIRO_STATUS_NO_MEMORY;
- }
- memcpy (pen->vertices, other->vertices, pen->num_vertices * sizeof (cairo_pen_vertex_t));
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points)
-{
- cairo_pen_vertex_t *vertices;
- int num_vertices;
- int i;
-
- num_vertices = pen->num_vertices + num_points;
- vertices = realloc (pen->vertices, num_vertices * sizeof (cairo_pen_vertex_t));
- if (vertices == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- pen->vertices = vertices;
- pen->num_vertices = num_vertices;
-
- /* initialize new vertices */
- for (i=0; i < num_points; i++)
- pen->vertices[pen->num_vertices-num_points+i].point = point[i];
-
- _cairo_hull_compute (pen->vertices, &pen->num_vertices);
-
- _cairo_pen_compute_slopes (pen);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/*
-The circular pen in user space is transformed into an ellipse in
-device space.
-
-We construct the pen by computing points along the circumference
-using equally spaced angles.
-
-We show below that this approximation to the ellipse has
-maximum error at the major axis of the ellipse.
-So, we need to compute the length of the major axis and then
-use that to compute the number of sides needed in our pen.
-
-Thanks to Walter Brisken <wbrisken@aoc.nrao.edu> for this
-derivation:
-
-1. First some notation:
-
-All capital letters represent vectors in two dimensions. A prime '
-represents a transformed coordinate. Matrices are written in underlined
-form, ie _R_. Lowercase letters represent scalar real values.
-
-The letter t is used to represent the greek letter theta.
-
-2. The question has been posed: What is the maximum expansion factor
-achieved by the linear transformation
-
-X' = _R_ X
-
-where _R_ is a real-valued 2x2 matrix with entries:
-
-_R_ = [a b]
- [c d] .
-
-In other words, what is the maximum radius, MAX[ |X'| ], reached for any
-X on the unit circle ( |X| = 1 ) ?
-
-
-3. Some useful formulae
-
-(A) through (C) below are standard double-angle formulae. (D) is a lesser
-known result and is derived below:
-
-(A) sin^2(t) = (1 - cos(2*t))/2
-(B) cos^2(t) = (1 + cos(2*t))/2
-(C) sin(t)*cos(t) = sin(2*t)/2
-(D) MAX[a*cos(t) + b*sin(t)] = sqrt(a^2 + b^2)
-
-Proof of (D):
-
-find the maximum of the function by setting the derivative to zero:
-
- -a*sin(t)+b*cos(t) = 0
-
-From this it follows that
-
- tan(t) = b/a
-
-and hence
-
- sin(t) = b/sqrt(a^2 + b^2)
-
-and
-
- cos(t) = a/sqrt(a^2 + b^2)
-
-Thus the maximum value is
-
- MAX[a*cos(t) + b*sin(t)] = (a^2 + b^2)/sqrt(a^2 + b^2)
- = sqrt(a^2 + b^2)
-
-
-4. Derivation of maximum expansion
-
-To find MAX[ |X'| ] we search brute force method using calculus. The unit
-circle on which X is constrained is to be parameterized by t:
-
- X(t) = (cos(t), sin(t))
-
-Thus
-
- X'(t) = (a*cos(t) + b*sin(t), c*cos(t) + d*sin(t)) .
-
-Define
-
- r(t) = |X'(t)|
-
-Thus
-
- r^2(t) = (a*cos(t) + b*sin(t))^2 + (c*cos(t) + d*sin(t))^2
- = (a^2 + c^2)*cos^2(t) + (b^2 + d^2)*sin^2(t)
- + 2*(a*b + c*d)*cos(t)*sin(t)
-
-Now apply the double angle formulae (A) to (C) from above:
-
- r^2(t) = (a^2 + b^2 + c^2 + d^2)/2
- + (a^2 - b^2 + c^2 - d^2)*cos(2*t)/2
- + (a*b + c*d)*sin(2*t)
- = f + g*cos(u) + h*sin(u)
-
-Where
-
- f = (a^2 + b^2 + c^2 + d^2)/2
- g = (a^2 - b^2 + c^2 - d^2)/2
- h = (a*b + c*d)
- u = 2*t
-
-It is clear that MAX[ |X'| ] = sqrt(MAX[ r^2 ]). Here we determine MAX[ r^2 ]
-using (D) from above:
-
- MAX[ r^2 ] = f + sqrt(g^2 + h^2)
-
-And finally
-
- MAX[ |X'| ] = sqrt( f + sqrt(g^2 + h^2) )
-
-Which is the solution to this problem.
-
-
-Walter Brisken
-2004/10/08
-
-(Note that the minor axis length is at the minimum of the above solution,
-which is just sqrt (f - sqrt (g^2 + h^2)) given the symmetry of (D)).
-
-Now to compute how many sides to use for the pen formed by
-a regular polygon.
-
-Set
-
- M = major axis length (computed by above formula)
- m = minor axis length (computed by above formula)
-
-Align 'M' along the X axis and 'm' along the Y axis and draw
-an ellipse parameterized by angle 't':
-
- x = M cos t y = m sin t
-
-Perturb t by ± d and compute two new points (x+,y+), (x-,y-).
-The distance from the average of these two points to (x,y) represents
-the maximum error in approximating the ellipse with a polygon formed
-from vertices 2∆ radians apart.
-
- x+ = M cos (t+∆) y+ = m sin (t+∆)
- x- = M cos (t-∆) y- = m sin (t-∆)
-
-Now compute the approximation error, E:
-
- Ex = (x - (x+ + x-) / 2)
- Ex = (M cos(t) - (Mcos(t+∆) + Mcos(t-∆))/2)
- = M (cos(t) - (cos(t)cos(∆) + sin(t)sin(∆) +
- cos(t)cos(∆) - sin(t)sin(∆))/2)
- = M(cos(t) - cos(t)cos(∆))
- = M cos(t) (1 - cos(∆))
-
- Ey = y - (y+ - y-) / 2
- = m sin (t) - (m sin(t+∆) + m sin(t-∆)) / 2
- = m (sin(t) - (sin(t)cos(∆) + cos(t)sin(∆) +
- sin(t)cos(∆) - cos(t)sin(∆))/2)
- = m (sin(t) - sin(t)cos(∆))
- = m sin(t) (1 - cos(∆))
-
- E² = Ex² + Ey²
- = (M cos(t) (1 - cos (∆)))² + (m sin(t) (1-cos(∆)))²
- = (1 - cos(∆))² (M² cos²(t) + m² sin²(t))
- = (1 - cos(∆))² ((m² + M² - m²) cos² (t) + m² sin²(t))
- = (1 - cos(∆))² (M² - m²) cos² (t) + (1 - cos(∆))² m²
-
-Find the extremum by differentiation wrt t and setting that to zero
-
-∂(E²)/∂(t) = (1-cos(∆))² (M² - m²) (-2 cos(t) sin(t))
-
- 0 = 2 cos (t) sin (t)
- 0 = sin (2t)
- t = nπ
-
-Which is to say that the maximum and minimum errors occur on the
-axes of the ellipse at 0 and π radians:
-
- E²(0) = (1-cos(∆))² (M² - m²) + (1-cos(∆))² m²
- = (1-cos(∆))² M²
- E²(π) = (1-cos(∆))² m²
-
-maximum error = M (1-cos(∆))
-minimum error = m (1-cos(∆))
-
-We must make maximum error ≤ tolerance, so compute the ∆ needed:
-
- tolerance = M (1-cos(∆))
- tolerance / M = 1 - cos (∆)
- cos(∆) = 1 - tolerance/M
- ∆ = acos (1 - tolerance / M);
-
-Remembering that ∆ is half of our angle between vertices,
-the number of vertices is then
-
-vertices = ceil(2π/2∆).
- = ceil(π/∆).
-
-Note that this also equation works for M == m (a circle) as it
-doesn't matter where on the circle the error is computed.
-
-*/
-
-static int
-_cairo_pen_vertices_needed (double tolerance,
- double radius,
- cairo_matrix_t *matrix)
-{
- double a = matrix->m[0][0], c = matrix->m[0][1];
- double b = matrix->m[1][0], d = matrix->m[1][1];
-
- double i = a*a + c*c;
- double j = b*b + d*d;
-
- double f = 0.5 * (i + j);
- double g = 0.5 * (i - j);
- double h = a*b + c*d;
-
- /*
- * compute major and minor axes lengths for
- * a pen with the specified radius
- */
-
- double major_axis = radius * sqrt (f + sqrt (g*g+h*h));
-
- /*
- * we don't need the minor axis length, which is
- * double min = radius * sqrt (f - sqrt (g*g+h*h));
- */
-
- /*
- * compute number of vertices needed
- */
- int num_vertices;
-
- /* Where tolerance / M is > 1, we use 4 points */
- if (tolerance >= major_axis) {
- num_vertices = 4;
- } else {
- double delta = acos (1 - tolerance / major_axis);
- num_vertices = ceil (M_PI / delta);
-
- /* number of vertices must be even */
- if (num_vertices % 2)
- num_vertices++;
- }
- return num_vertices;
-}
-
-static void
-_cairo_pen_compute_slopes (cairo_pen_t *pen)
-{
- int i, i_prev;
- cairo_pen_vertex_t *prev, *v, *next;
-
- for (i=0, i_prev = pen->num_vertices - 1;
- i < pen->num_vertices;
- i_prev = i++) {
- prev = &pen->vertices[i_prev];
- v = &pen->vertices[i];
- next = &pen->vertices[(i + 1) % pen->num_vertices];
-
- _cairo_slope_init (&v->slope_cw, &prev->point, &v->point);
- _cairo_slope_init (&v->slope_ccw, &v->point, &next->point);
- }
-}
-/*
- * 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 _cairo_slope_clockwise/_cairo_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_t *slope,
- int *active)
-{
- int i;
-
- for (i=0; i < pen->num_vertices; i++) {
- if (_cairo_slope_clockwise (slope, &pen->vertices[i].slope_ccw)
- && _cairo_slope_counter_clockwise (slope, &pen->vertices[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 _cairo_slope_clockwise/_cairo_slope_counter_clockwise.
- */
-cairo_status_t
-_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
- cairo_slope_t *slope,
- int *active)
-{
- int i;
- cairo_slope_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 (_cairo_slope_counter_clockwise (&pen->vertices[i].slope_ccw, &slope_reverse)
- && _cairo_slope_clockwise (&pen->vertices[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_direction_t dir,
- cairo_polygon_t *polygon)
-{
- int i;
- cairo_status_t status;
- int start, stop, step;
- int active = 0;
- cairo_point_t hull_point;
- cairo_slope_t slope, initial_slope, final_slope;
- cairo_point_t *point = spline->points;
- int num_points = spline->num_points;
-
- if (dir == CAIRO_DIRECTION_FORWARD) {
- start = 0;
- stop = num_points;
- step = 1;
- initial_slope = spline->initial_slope;
- final_slope = spline->final_slope;
- } else {
- start = num_points - 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_point.x = point[i].x + pen->vertices[active].point.x;
- hull_point.y = point[i].y + pen->vertices[active].point.y;
- status = _cairo_polygon_line_to (polygon, &hull_point);
- if (status)
- return status;
-
- if (i + step == stop)
- slope = final_slope;
- else
- _cairo_slope_init (&slope, &point[i], &point[i+step]);
- if (_cairo_slope_counter_clockwise (&slope, &pen->vertices[active].slope_ccw)) {
- if (++active == pen->num_vertices)
- active = 0;
- } else if (_cairo_slope_clockwise (&slope, &pen->vertices[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;
-
- /* If the line width is so small that the pen is reduced to a
- single point, then we have nothing to do. */
- if (pen->num_vertices <= 1)
- return CAIRO_STATUS_SUCCESS;
-
- _cairo_polygon_init (&polygon);
-
- status = _cairo_spline_decompose (spline, tolerance);
- if (status)
- return status;
-
- status = _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_FORWARD, &polygon);
- if (status)
- return status;
-
- status = _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_REVERSE, &polygon);
- if (status)
- return status;
-
- _cairo_polygon_close (&polygon);
- _cairo_traps_tessellate_polygon (traps, &polygon, CAIRO_FILL_RULE_WINDING);
- _cairo_polygon_fini (&polygon);
-
- return CAIRO_STATUS_SUCCESS;
-}
diff --git a/src/cairo_png_surface.c b/src/cairo_png_surface.c
deleted file mode 100644
index 1ae745cb5..000000000
--- a/src/cairo_png_surface.c
+++ /dev/null
@@ -1,425 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2004 University of Southern California
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Olivier Andrieu <oliv__a@users.sourceforge.net>
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#include <png.h>
-
-#include "cairoint.h"
-#include "cairo-png.h"
-
-static const cairo_surface_backend_t cairo_png_surface_backend;
-
-static cairo_int_status_t
-_cairo_png_surface_copy_page (void *abstract_surface);
-
-void
-cairo_set_target_png (cairo_t *cr,
- FILE *file,
- cairo_format_t format,
- int width,
- int height)
-{
- cairo_surface_t *surface;
-
- surface = cairo_png_surface_create (file, format,
- width, height);
-
- if (surface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface (cr, surface);
-
- /* cairo_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy (surface);
-}
-
-typedef struct cairo_png_surface {
- cairo_surface_t base;
-
- /* PNG-specific fields */
- cairo_image_surface_t *image;
- FILE *file;
- int copied;
-
- cairo_format_t format;
-
-} cairo_png_surface_t;
-
-
-static void
-_cairo_png_surface_erase (cairo_png_surface_t *surface);
-
-cairo_surface_t *
-cairo_png_surface_create (FILE *file,
- cairo_format_t format,
- int width,
- int height)
-{
- cairo_png_surface_t *surface;
-
- surface = malloc (sizeof (cairo_png_surface_t));
- if (surface == NULL)
- return NULL;
-
- _cairo_surface_init (&surface->base, &cairo_png_surface_backend);
-
- surface->image = (cairo_image_surface_t *)
- cairo_image_surface_create (format, width, height);
-
- if (surface->image == NULL) {
- free (surface);
- return NULL;
- }
-
- _cairo_png_surface_erase (surface);
-
- surface->file = file;
- surface->copied = 0;
-
- surface->format = format;
-
- return &surface->base;
-}
-
-
-static cairo_surface_t *
-_cairo_png_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- return NULL;
-}
-
-static void
-unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
-{
- int i;
-
- for (i = 0; i < row_info->rowbytes; i += 4) {
- unsigned char *b = &data[i];
- unsigned int pixel;
- unsigned char alpha;
-
- memcpy (&pixel, b, sizeof (unsigned int));
- alpha = (pixel & 0xff000000) >> 24;
- if (alpha == 0) {
- b[0] = b[1] = b[2] = b[3] = 0;
- } else {
- b[0] = (((pixel & 0x0000ff) >> 0) * 255) / alpha;
- b[1] = (((pixel & 0x00ff00) >> 8) * 255) / alpha;
- b[2] = (((pixel & 0xff0000) >> 16) * 255) / alpha;
- b[3] = alpha;
- }
- }
-}
-
-static void
-_cairo_png_surface_destroy (void *abstract_surface)
-{
- cairo_png_surface_t *surface = abstract_surface;
-
- if (! surface->copied)
- _cairo_png_surface_copy_page (surface);
-
- cairo_surface_destroy (&surface->image->base);
-
- free (surface);
-}
-
-static void
-_cairo_png_surface_erase (cairo_png_surface_t *surface)
-{
- cairo_color_t transparent;
-
- _cairo_color_init (&transparent);
- _cairo_color_set_rgb (&transparent, 0., 0., 0.);
- _cairo_color_set_alpha (&transparent, 0.);
- _cairo_surface_fill_rectangle (&surface->image->base,
- CAIRO_OPERATOR_SRC,
- &transparent,
- 0, 0,
- surface->image->width,
- surface->image->height);
-}
-
-static double
-_cairo_png_surface_pixels_per_inch (void *abstract_surface)
-{
- return 96.0;
-}
-
-static cairo_status_t
-_cairo_png_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_png_surface_t *surface = abstract_surface;
-
- *image_out = surface->image;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_png_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_png_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect,
- void **image_extra)
-{
- cairo_png_surface_t *surface = abstract_surface;
-
- image_rect->x = 0;
- image_rect->y = 0;
- image_rect->width = surface->image->width;
- image_rect->height = surface->image->height;
-
- *image_out = surface->image;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_png_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_png_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_png_surface_composite (cairo_operator_t operator,
- cairo_pattern_t *src,
- cairo_pattern_t *mask,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_png_surface_fill_rectangles (void *abstract_surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_png_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_png_surface_copy_page (void *abstract_surface)
-{
- int i;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_png_surface_t *surface = abstract_surface;
- png_struct *png;
- png_info *info;
- png_byte **rows;
- png_color_16 white;
- int png_color_type;
- int depth;
-
- rows = malloc (surface->image->height * sizeof(png_byte*));
- if (rows == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- for (i = 0; i < surface->image->height; i++)
- rows[i] = surface->image->data + i * surface->image->stride;
-
- png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (png == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL1;
- }
-
- info = png_create_info_struct (png);
- if (info == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL2;
- }
-
- if (setjmp (png_jmpbuf (png))) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL2;
- }
-
- png_init_io (png, surface->file);
-
- switch (surface->format) {
- case CAIRO_FORMAT_ARGB32:
- depth = 8;
- png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
- break;
- case CAIRO_FORMAT_RGB24:
- depth = 8;
- png_color_type = PNG_COLOR_TYPE_RGB;
- break;
- case CAIRO_FORMAT_A8:
- depth = 8;
- png_color_type = PNG_COLOR_TYPE_GRAY;
- break;
- case CAIRO_FORMAT_A1:
- depth = 1;
- png_color_type = PNG_COLOR_TYPE_GRAY;
- break;
- default:
- status = CAIRO_STATUS_NULL_POINTER;
- goto BAIL2;
- }
-
- png_set_IHDR (png, info,
- surface->image->width,
- surface->image->height, depth,
- png_color_type,
- PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_DEFAULT,
- PNG_FILTER_TYPE_DEFAULT);
-
- white.red = 0xff;
- white.blue = 0xff;
- white.green = 0xff;
- png_set_bKGD (png, info, &white);
-
-/* XXX: Setting the time is interfereing with the image comparison
- png_convert_from_time_t (&png_time, time (NULL));
- png_set_tIME (png, info, &png_time);
-*/
-
- png_set_write_user_transform_fn (png, unpremultiply_data);
- if (surface->format == CAIRO_FORMAT_ARGB32 || surface->format == CAIRO_FORMAT_RGB24)
- png_set_bgr (png);
- if (surface->format == CAIRO_FORMAT_RGB24)
- png_set_filler (png, 0, PNG_FILLER_AFTER);
-
- png_write_info (png, info);
- png_write_image (png, rows);
- png_write_end (png, info);
-
- surface->copied = 1;
-
-BAIL2:
- png_destroy_write_struct (&png, &info);
-BAIL1:
- free (rows);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_png_surface_show_page (void *abstract_surface)
-{
- cairo_int_status_t status;
- cairo_png_surface_t *surface = abstract_surface;
-
- status = _cairo_png_surface_copy_page (surface);
- if (status)
- return status;
-
- _cairo_png_surface_erase (surface);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_png_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- cairo_png_surface_t *surface = abstract_surface;
-
- return _cairo_image_surface_set_clip_region (surface->image, region);
-}
-
-static const cairo_surface_backend_t cairo_png_surface_backend = {
- _cairo_png_surface_create_similar,
- _cairo_png_surface_destroy,
- _cairo_png_surface_pixels_per_inch,
- _cairo_png_surface_acquire_source_image,
- _cairo_png_surface_release_source_image,
- _cairo_png_surface_acquire_dest_image,
- _cairo_png_surface_release_dest_image,
- _cairo_png_surface_clone_similar,
- _cairo_png_surface_composite,
- _cairo_png_surface_fill_rectangles,
- _cairo_png_surface_composite_trapezoids,
- _cairo_png_surface_copy_page,
- _cairo_png_surface_show_page,
- _cairo_png_surface_set_clip_region,
- NULL /* show_glyphs */
-};
diff --git a/src/cairo_polygon.c b/src/cairo_polygon.c
deleted file mode 100644
index 59c615da2..000000000
--- a/src/cairo_polygon.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2002 University of Southern California
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#include <stdlib.h>
-#include "cairoint.h"
-
-/* private functions */
-
-static cairo_status_t
-_cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional);
-
-void
-_cairo_polygon_init (cairo_polygon_t *polygon)
-{
- polygon->num_edges = 0;
-
- polygon->edges_size = 0;
- polygon->edges = NULL;
-
- polygon->has_current_point = 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->has_current_point = 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;
-}
-
-cairo_status_t
-_cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_point_t *p2)
-{
- cairo_status_t status;
- cairo_edge_t *edge;
-
- /* drop horizontal edges */
- if (p1->y == p2->y) {
- goto DONE;
- }
-
- if (polygon->num_edges >= polygon->edges_size) {
- int additional = polygon->edges_size ? polygon->edges_size : 16;
- status = _cairo_polygon_grow_by (polygon, additional);
- 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 = 1;
- } else {
- edge->edge.p1 = *p2;
- edge->edge.p2 = *p1;
- edge->clockWise = 0;
- }
-
- polygon->num_edges++;
-
- DONE:
- _cairo_polygon_move_to (polygon, p2);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_polygon_move_to (cairo_polygon_t *polygon, cairo_point_t *point)
-{
- if (! polygon->has_current_point)
- polygon->first_point = *point;
- polygon->current_point = *point;
- polygon->has_current_point = 1;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_polygon_line_to (cairo_polygon_t *polygon, cairo_point_t *point)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
- if (polygon->has_current_point) {
- status = _cairo_polygon_add_edge (polygon, &polygon->current_point, point);
- } else {
- _cairo_polygon_move_to (polygon, point);
- }
-
- return status;
-}
-
-cairo_status_t
-_cairo_polygon_close (cairo_polygon_t *polygon)
-{
- cairo_status_t status;
-
- if (polygon->has_current_point) {
- status = _cairo_polygon_add_edge (polygon,
- &polygon->current_point,
- &polygon->first_point);
- if (status)
- return status;
-
- polygon->has_current_point = 0;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
diff --git a/src/cairo_ps_surface.c b/src/cairo_ps_surface.c
deleted file mode 100644
index 4a45fc679..000000000
--- a/src/cairo_ps_surface.c
+++ /dev/null
@@ -1,443 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2003 University of Southern California
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#include "cairoint.h"
-#include "cairo-ps.h"
-
-#include <time.h>
-#include <zlib.h>
-
-static const cairo_surface_backend_t cairo_ps_surface_backend;
-
-/**
- * cairo_set_target_ps:
- * @cr: a #cairo_t
- * @file: an open, writeable file
- * @width_inches: width of the output page, in inches
- * @height_inches: height of the output page, in inches
- * @x_pixels_per_inch: X resolution to use for image fallbacks;
- * not all Cairo drawing can be represented in a postscript
- * file, so Cairo will write out images for some portions
- * of the output.
- * @y_pixels_per_inch: Y resolution to use for image fallbacks.
- *
- * Directs output for a #cairo_t to a postscript file. The file must
- * be kept open until the #cairo_t is destroyed or set to have a
- * different target, and then must be closed by the application.
- **/
-void
-cairo_set_target_ps (cairo_t *cr,
- FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch)
-{
- cairo_surface_t *surface;
-
- surface = cairo_ps_surface_create (file,
- width_inches, height_inches,
- x_pixels_per_inch, y_pixels_per_inch);
- if (surface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface (cr, surface);
-
- /* cairo_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy (surface);
-}
-
-typedef struct cairo_ps_surface {
- cairo_surface_t base;
-
- /* PS-specific fields */
- FILE *file;
-
- double width_inches;
- double height_inches;
- double x_ppi;
- double y_ppi;
-
- int pages;
-
- cairo_image_surface_t *image;
-} cairo_ps_surface_t;
-
-static void
-_cairo_ps_surface_erase (cairo_ps_surface_t *surface);
-
-cairo_surface_t *
-cairo_ps_surface_create (FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch)
-{
- cairo_ps_surface_t *surface;
- int width, height;
- time_t now = time (0);
-
- surface = malloc (sizeof (cairo_ps_surface_t));
- if (surface == NULL)
- return NULL;
-
- _cairo_surface_init (&surface->base, &cairo_ps_surface_backend);
-
- surface->file = file;
-
- surface->width_inches = width_inches;
- surface->height_inches = height_inches;
- surface->x_ppi = x_pixels_per_inch;
- surface->y_ppi = x_pixels_per_inch;
-
- surface->pages = 0;
-
- width = (int) (x_pixels_per_inch * width_inches + 1.0);
- height = (int) (y_pixels_per_inch * height_inches + 1.0);
-
- surface->image = (cairo_image_surface_t *)
- cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
- if (surface->image == NULL) {
- free (surface);
- return NULL;
- }
-
- _cairo_ps_surface_erase (surface);
-
- /* Document header */
- fprintf (file,
- "%%!PS-Adobe-3.0\n"
- "%%%%Creator: Cairo (http://cairographics.org)\n");
- fprintf (file,
- "%%%%CreationDate: %s",
- ctime (&now));
- fprintf (file,
- "%%%%BoundingBox: %d %d %d %d\n",
- 0, 0, (int) (surface->width_inches * 72.0), (int) (surface->height_inches * 72.0));
- /* The "/FlateDecode filter" currently used is a feature of LanguageLevel 3 */
- fprintf (file,
- "%%%%DocumentData: Clean7Bit\n"
- "%%%%LanguageLevel: 3\n");
- fprintf (file,
- "%%%%Orientation: Portrait\n"
- "%%%%EndComments\n");
-
- return &surface->base;
-}
-
-static cairo_surface_t *
-_cairo_ps_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- return NULL;
-}
-
-static void
-_cairo_ps_surface_destroy (void *abstract_surface)
-{
- cairo_ps_surface_t *surface = abstract_surface;
-
- /* Document footer */
- fprintf (surface->file, "%%%%EOF\n");
-
- cairo_surface_destroy (&surface->image->base);
-
- free (surface);
-}
-
-static void
-_cairo_ps_surface_erase (cairo_ps_surface_t *surface)
-{
- cairo_color_t transparent;
-
- _cairo_color_init (&transparent);
- _cairo_color_set_rgb (&transparent, 0., 0., 0.);
- _cairo_color_set_alpha (&transparent, 0.);
- _cairo_surface_fill_rectangle (&surface->image->base,
- CAIRO_OPERATOR_SRC,
- &transparent,
- 0, 0,
- surface->image->width,
- surface->image->height);
-}
-
-/* XXX: We should re-work this interface to return both X/Y ppi values. */
-static double
-_cairo_ps_surface_pixels_per_inch (void *abstract_surface)
-{
- cairo_ps_surface_t *surface = abstract_surface;
-
- return surface->y_ppi;
-}
-
-static cairo_status_t
-_cairo_ps_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_ps_surface_t *surface = abstract_surface;
-
- *image_out = surface->image;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_ps_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_ps_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect,
- void **image_extra)
-{
- cairo_ps_surface_t *surface = abstract_surface;
-
- image_rect->x = 0;
- image_rect->y = 0;
- image_rect->width = surface->image->width;
- image_rect->height = surface->image->height;
-
- *image_out = surface->image;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_ps_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_ps_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_composite (cairo_operator_t operator,
- cairo_pattern_t *src,
- cairo_pattern_t *mask,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_fill_rectangles (void *abstract_surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *generic_src,
- void *abstract_dst,
- int x_src,
- int y_src,
- int x_dst,
- int y_dst,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_copy_page (void *abstract_surface)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_ps_surface_t *surface = abstract_surface;
- int width = surface->image->width;
- int height = surface->image->height;
- FILE *file = surface->file;
-
- int i, x, y;
-
- cairo_solid_pattern_t white_pattern;
- char *rgb, *compressed;
- long rgb_size, compressed_size;
-
- rgb_size = 3 * width * height;
- rgb = malloc (rgb_size);
- if (rgb == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL0;
- }
-
- compressed_size = (int) (1.0 + 1.1 * rgb_size);
- compressed = malloc (compressed_size);
- if (compressed == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL1;
- }
-
- /* PostScript can not represent the alpha channel, so we blend the
- current image over a white RGB surface to eliminate it. */
-
- _cairo_pattern_init_solid (&white_pattern, 1.0, 1.0, 1.0);
-
- _cairo_surface_composite (CAIRO_OPERATOR_OVER_REVERSE,
- &white_pattern.base,
- NULL,
- &surface->image->base,
- 0, 0,
- 0, 0,
- 0, 0,
- width, height);
-
- _cairo_pattern_fini (&white_pattern.base);
-
- i = 0;
- for (y = 0; y < height; y++) {
- pixman_bits_t *pixel = (pixman_bits_t *) (surface->image->data + y * surface->image->stride);
- for (x = 0; x < width; x++, pixel++) {
- rgb[i++] = (*pixel & 0x00ff0000) >> 16;
- rgb[i++] = (*pixel & 0x0000ff00) >> 8;
- rgb[i++] = (*pixel & 0x000000ff) >> 0;
- }
- }
-
- compress (compressed, &compressed_size, rgb, rgb_size);
-
- /* Page header */
- fprintf (file, "%%%%Page: %d\n", ++surface->pages);
-
- fprintf (file, "gsave\n");
-
- /* Image header goop */
- fprintf (file, "%g %g translate\n", 0.0, surface->height_inches * 72.0);
- fprintf (file, "%g %g scale\n", 72.0 / surface->x_ppi, 72.0 / surface->y_ppi);
- fprintf (file, "/DeviceRGB setcolorspace\n");
- fprintf (file, "<<\n");
- fprintf (file, " /ImageType 1\n");
- fprintf (file, " /Width %d\n", width);
- fprintf (file, " /Height %d\n", height);
- fprintf (file, " /BitsPerComponent 8\n");
- fprintf (file, " /Decode [ 0 1 0 1 0 1 ]\n");
- fprintf (file, " /DataSource currentfile /FlateDecode filter\n");
- fprintf (file, " /ImageMatrix [ 1 0 0 -1 0 1 ]\n");
- fprintf (file, ">>\n");
- fprintf (file, "image\n");
-
- /* Compressed image data */
- fwrite (compressed, 1, compressed_size, file);
-
- fprintf (file, "showpage\n");
-
- fprintf (file, "grestore\n");
-
- /* Page footer */
- fprintf (file, "%%%%EndPage\n");
-
- free (compressed);
- BAIL1:
- free (rgb);
- BAIL0:
- return status;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_show_page (void *abstract_surface)
-{
- cairo_int_status_t status;
- cairo_ps_surface_t *surface = abstract_surface;
-
- status = _cairo_ps_surface_copy_page (surface);
- if (status)
- return status;
-
- _cairo_ps_surface_erase (surface);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- cairo_ps_surface_t *surface = abstract_surface;
-
- return _cairo_image_surface_set_clip_region (surface->image, region);
-}
-
-static const cairo_surface_backend_t cairo_ps_surface_backend = {
- _cairo_ps_surface_create_similar,
- _cairo_ps_surface_destroy,
- _cairo_ps_surface_pixels_per_inch,
- _cairo_ps_surface_acquire_source_image,
- _cairo_ps_surface_release_source_image,
- _cairo_ps_surface_acquire_dest_image,
- _cairo_ps_surface_release_dest_image,
- _cairo_ps_surface_clone_similar,
- _cairo_ps_surface_composite,
- _cairo_ps_surface_fill_rectangles,
- _cairo_ps_surface_composite_trapezoids,
- _cairo_ps_surface_copy_page,
- _cairo_ps_surface_show_page,
- _cairo_ps_surface_set_clip_region,
- NULL /* show_glyphs */
-};
diff --git a/src/cairo_quartz_surface.c b/src/cairo_quartz_surface.c
deleted file mode 100644
index 01b345cdc..000000000
--- a/src/cairo_quartz_surface.c
+++ /dev/null
@@ -1,392 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2004 Calum Robinson
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is Calum Robinson
- *
- * Contributor(s):
- * Calum Robinson <calumr@mac.com>
- */
-
-#include "cairoint.h"
-#include "cairo-quartz.h"
-
-#pragma mark Types
-
-typedef struct cairo_quartz_surface {
- cairo_surface_t base;
-
- CGContextRef context;
-
- int width;
- int height;
-
- cairo_image_surface_t *image;
-
- CGImageRef cgImage;
-} cairo_quartz_surface_t;
-
-
-
-
-
-#pragma mark Private functions
-
-
-
-
-void ImageDataReleaseFunc(void *info, const void *data, size_t size)
-{
- if (data != NULL)
- {
- free((void *)data);
- }
-}
-
-
-
-
-#pragma mark Public functions
-
-
-
-
-
-void
-cairo_set_target_quartz_context( cairo_t *cr,
- CGContextRef context,
- int width,
- int height)
-{
- cairo_surface_t *surface;
-
-
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
-
- surface = cairo_quartz_surface_create(context, width, height);
- if (surface == NULL)
- {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface(cr, surface);
-
- /* cairo_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy(surface);
-}
-
-
-static cairo_surface_t *
-_cairo_quartz_surface_create_similar( void *abstract_src,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- return NULL;
-}
-
-
-static void
-_cairo_quartz_surface_destroy(void *abstract_surface)
-{
- cairo_quartz_surface_t *surface = abstract_surface;
-
-
- if (surface->cgImage)
- {
- CGImageRelease(surface->cgImage);
- }
-
-
- free(surface);
-}
-
-
-static double
-_cairo_quartz_surface_pixels_per_inch(void *abstract_surface)
-{
-
-
- // TODO - get this from CGDirectDisplay somehow?
- return 96.0;
-}
-
-
-static cairo_image_surface_t *
-_cairo_quartz_surface_get_image(void *abstract_surface)
-{
- cairo_quartz_surface_t *surface = abstract_surface;
- CGColorSpaceRef colorSpace;
- void *imageData;
- UInt32 imageDataSize, rowBytes;
- CGDataProviderRef dataProvider;
-
-
- // We keep a cached (cairo_image_surface_t *) in the cairo_quartz_surface_t
- // struct. If the window is ever drawn to without going through Cairo, then
- // we would need to refetch the pixel data from the window into the cached
- // image surface.
- if (surface->image)
- {
- cairo_surface_reference(&surface->image->base);
-
- return surface->image;
- }
-
- colorSpace = CGColorSpaceCreateDeviceRGB();
-
-
- rowBytes = surface->width * 4;
- imageDataSize = rowBytes * surface->height;
- imageData = malloc(imageDataSize);
-
- dataProvider = CGDataProviderCreateWithData(NULL, imageData, imageDataSize, ImageDataReleaseFunc);
-
- surface->cgImage = CGImageCreate( surface->width,
- surface->height,
- 8,
- 32,
- rowBytes,
- colorSpace,
- kCGImageAlphaPremultipliedFirst,
- dataProvider,
- NULL,
- false,
- kCGRenderingIntentDefault);
-
-
- CGColorSpaceRelease(colorSpace);
- CGDataProviderRelease(dataProvider);
-
-
- surface->image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data( imageData,
- CAIRO_FORMAT_ARGB32,
- surface->width,
- surface->height,
- rowBytes);
-
-
- // Set the image surface Cairo state to match our own.
- _cairo_image_surface_set_repeat(surface->image, surface->base.repeat);
- _cairo_image_surface_set_matrix(surface->image, &(surface->base.matrix));
-
-
- return surface->image;
-}
-
-
-static cairo_status_t
-_cairo_quartz_surface_set_image( void *abstract_surface,
- cairo_image_surface_t *image)
-{
- cairo_quartz_surface_t *surface = abstract_surface;
- cairo_status_t status;
-
-
- if (surface->image == image)
- {
- CGRect rect;
-
-
- rect = CGRectMake(0, 0, surface->width, surface->height);
-
- CGContextDrawImage(surface->context, rect, surface->cgImage);
-
-
- status = CAIRO_STATUS_SUCCESS;
- }
- else
- {
- // TODO - set_image from something other than what we returned from get_image
- status = CAIRO_STATUS_NO_TARGET_SURFACE;
- }
-
-
- return status;
-}
-
-
-static cairo_status_t
-_cairo_quartz_surface_set_matrix(void *abstract_surface, cairo_matrix_t *matrix)
-{
- cairo_quartz_surface_t *surface = abstract_surface;
-
- return _cairo_image_surface_set_matrix(surface->image, matrix);
-}
-
-
-static cairo_status_t
-_cairo_quartz_surface_set_filter(void *abstract_surface, cairo_filter_t filter)
-{
- cairo_quartz_surface_t *surface = abstract_surface;
-
- return _cairo_image_surface_set_filter(surface->image, filter);
-}
-
-
-static cairo_status_t
-_cairo_quartz_surface_set_repeat(void *abstract_surface, int repeat)
-{
- cairo_quartz_surface_t *surface = abstract_surface;
-
- return _cairo_image_surface_set_repeat(surface->image, repeat);
-}
-
-
-static cairo_int_status_t
-_cairo_quartz_surface_composite( cairo_operator_t operator,
- cairo_surface_t *generic_src,
- cairo_surface_t *generic_mask,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-
-static cairo_int_status_t
-_cairo_quartz_surface_fill_rectangles( void *abstract_surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-
-static cairo_int_status_t
-_cairo_quartz_surface_composite_trapezoids( cairo_operator_t operator,
- cairo_surface_t *generic_src,
- void *abstract_dst,
- int xSrc,
- int ySrc,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-
-static cairo_int_status_t
-_cairo_quartz_surface_copy_page(void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-
-static cairo_int_status_t
-_cairo_quartz_surface_show_page(void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-
-static cairo_int_status_t
-_cairo_quartz_surface_set_clip_region( void *abstract_surface,
- pixman_region16_t *region)
-{
- cairo_quartz_surface_t *surface = abstract_surface;
-
- return _cairo_image_surface_set_clip_region(surface->image, region);
-}
-
-
-static cairo_int_status_t
-_cairo_quartz_surface_create_pattern( void *abstract_surface,
- cairo_pattern_t *pattern,
- cairo_box_t *extents)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-
-static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
- _cairo_quartz_surface_create_similar,
- _cairo_quartz_surface_destroy,
- _cairo_quartz_surface_pixels_per_inch,
- _cairo_quartz_surface_get_image,
- _cairo_quartz_surface_set_image,
- _cairo_quartz_surface_set_matrix,
- _cairo_quartz_surface_set_filter,
- _cairo_quartz_surface_set_repeat,
- _cairo_quartz_surface_composite,
- _cairo_quartz_surface_fill_rectangles,
- _cairo_quartz_surface_composite_trapezoids,
- _cairo_quartz_surface_copy_page,
- _cairo_quartz_surface_show_page,
- _cairo_quartz_surface_set_clip_region,
- _cairo_quartz_surface_create_pattern
-};
-
-
-cairo_surface_t *
-cairo_quartz_surface_create( CGContextRef context,
- int width,
- int height)
-{
- cairo_quartz_surface_t *surface;
-
-
- surface = malloc(sizeof(cairo_quartz_surface_t));
- if (surface == NULL)
- return NULL;
-
- _cairo_surface_init(&surface->base, &cairo_quartz_surface_backend);
-
-
- surface->context = context;
-
- surface->width = width;
- surface->height = height;
-
- surface->image = NULL;
-
- surface->cgImage = NULL;
-
-
- // Set up the image surface which Cairo draws into and we blit to & from.
- surface->image = _cairo_quartz_surface_get_image(surface);
-
-
- return (cairo_surface_t *)surface;
-}
-
-
-DEPRECATE (cairo_surface_create_for_drawable, cairo_quartz_surface_create);
diff --git a/src/cairo_slope.c b/src/cairo_slope.c
deleted file mode 100644
index a2edec038..000000000
--- a/src/cairo_slope.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2002 University of Southern California
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#include "cairoint.h"
-
-void
-_cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b)
-{
- slope->dx = b->x - a->x;
- slope->dy = b->y - a->y;
-}
-
-/* Compare two slopes. Slope angles begin at 0 in the direction of the
- positive X axis and increase in the direction of the positive Y
- axis.
-
- WARNING: This function only gives correct results if the angular
- difference between a and b is less than PI.
-
- < 0 => a less positive than b
- == 0 => a equal to be
- > 0 => a more positive than b
-*/
-int
-_cairo_slope_compare (cairo_slope_t *a, cairo_slope_t *b)
-{
- cairo_fixed_48_16_t diff;
-
- diff = ((cairo_fixed_48_16_t) a->dy * (cairo_fixed_48_16_t) b->dx
- - (cairo_fixed_48_16_t) b->dy * (cairo_fixed_48_16_t) a->dx);
-
- if (diff > 0)
- return 1;
- if (diff < 0)
- return -1;
-
- if (a->dx == 0 && a->dy == 0)
- return 1;
- if (b->dx == 0 && b->dy ==0)
- return -1;
-
- return 0;
-}
-
-/* XXX: It might be cleaner to move away from usage of
- _cairo_slope_clockwise/_cairo_slope_counter_clockwise in favor of
- directly using _cairo_slope_compare.
-*/
-
-/* 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).
- */
-int
-_cairo_slope_clockwise (cairo_slope_t *a, cairo_slope_t *b)
-{
- return _cairo_slope_compare (a, b) < 0;
-}
-
-int
-_cairo_slope_counter_clockwise (cairo_slope_t *a, cairo_slope_t *b)
-{
- return ! _cairo_slope_clockwise (a, b);
-}
-
-
-
-
diff --git a/src/cairo_spline.c b/src/cairo_spline.c
deleted file mode 100644
index 5119a8e2b..000000000
--- a/src/cairo_spline.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2002 University of Southern California
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#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, cairo_point_t *point);
-
-static void
-_lerp_half (cairo_point_t *a, cairo_point_t *b, cairo_point_t *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);
-
-cairo_int_status_t
-_cairo_spline_init (cairo_spline_t *spline,
- cairo_point_t *a, cairo_point_t *b,
- cairo_point_t *c, cairo_point_t *d)
-{
- spline->a = *a;
- spline->b = *b;
- spline->c = *c;
- spline->d = *d;
-
- if (a->x != b->x || a->y != b->y) {
- _cairo_slope_init (&spline->initial_slope, &spline->a, &spline->b);
- } else if (a->x != c->x || a->y != c->y) {
- _cairo_slope_init (&spline->initial_slope, &spline->a, &spline->c);
- } else if (a->x != d->x || a->y != d->y) {
- _cairo_slope_init (&spline->initial_slope, &spline->a, &spline->d);
- } else {
- return CAIRO_INT_STATUS_DEGENERATE;
- }
-
- if (c->x != d->x || c->y != d->y) {
- _cairo_slope_init (&spline->final_slope, &spline->c, &spline->d);
- } else if (b->x != d->x || b->y != d->y) {
- _cairo_slope_init (&spline->final_slope, &spline->b, &spline->d);
- } else {
- _cairo_slope_init (&spline->final_slope, &spline->a, &spline->d);
- }
-
- spline->num_points = 0;
- spline->points_size = 0;
- spline->points = NULL;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_spline_fini (cairo_spline_t *spline)
-{
- spline->num_points = 0;
- spline->points_size = 0;
- free (spline->points);
- spline->points = NULL;
-}
-
-static cairo_status_t
-_cairo_spline_grow_by (cairo_spline_t *spline, int additional)
-{
- cairo_point_t *new_points;
- int old_size = spline->points_size;
- int new_size = spline->num_points + additional;
-
- if (new_size <= spline->points_size)
- return CAIRO_STATUS_SUCCESS;
-
- spline->points_size = new_size;
- new_points = realloc (spline->points, spline->points_size * sizeof (cairo_point_t));
-
- if (new_points == NULL) {
- spline->points_size = old_size;
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- spline->points = new_points;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_spline_add_point (cairo_spline_t *spline, cairo_point_t *point)
-{
- cairo_status_t status;
- cairo_point_t *prev;
-
- if (spline->num_points) {
- prev = &spline->points[spline->num_points - 1];
- if (prev->x == point->x && prev->y == point->y)
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (spline->num_points >= spline->points_size) {
- int additional = spline->points_size ? spline->points_size : 32;
- status = _cairo_spline_grow_by (spline, additional);
- if (status)
- return status;
- }
-
- spline->points[spline->num_points] = *point;
- spline->num_points++;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_lerp_half (cairo_point_t *a, cairo_point_t *b, cairo_point_t *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)
-{
- cairo_point_t ab, bc, cd;
- cairo_point_t abbc, bccd;
- cairo_point_t 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 (cairo_point_t *a, cairo_point_t *b)
-{
- double dx = _cairo_fixed_to_double (b->x - a->x);
- double dy = _cairo_fixed_to_double (b->y - a->y);
-
- return dx*dx + dy*dy;
-}
-
-static double
-_PointDistanceSquaredToSegment (cairo_point_t *p, cairo_point_t *p1, cairo_point_t *p2)
-{
- double u;
- double dx, dy;
- double pdx, pdy;
- cairo_point_t px;
-
- /* intersection point (px):
-
- px = p1 + u(p2 - p1)
- (p - px) . (p2 - p1) = 0
-
- Thus:
-
- u = ((p - p1) . (p2 - p1)) / (||(p2 - p1)|| ^ 2);
- */
-
- dx = _cairo_fixed_to_double (p2->x - p1->x);
- dy = _cairo_fixed_to_double (p2->y - p1->y);
-
- if (dx == 0 && dy == 0)
- return _PointDistanceSquaredToPoint (p, p1);
-
- pdx = _cairo_fixed_to_double (p->x - p1->x);
- pdy = _cairo_fixed_to_double (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->points_size) {
- _cairo_spline_fini (spline);
- }
-
- status = _cairo_spline_decompose_into (spline, tolerance * tolerance, spline);
- if (status)
- return status;
-
- status = _cairo_spline_add_point (spline, &spline->d);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
diff --git a/src/cairo_surface.c b/src/cairo_surface.c
deleted file mode 100644
index 330d58b1e..000000000
--- a/src/cairo_surface.c
+++ /dev/null
@@ -1,708 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2002 University of Southern California
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#include <stdlib.h>
-
-#include "cairoint.h"
-
-void
-_cairo_surface_init (cairo_surface_t *surface,
- const cairo_surface_backend_t *backend)
-{
- surface->backend = backend;
-
- surface->ref_count = 1;
-
- _cairo_matrix_init (&surface->matrix);
- surface->filter = CAIRO_FILTER_NEAREST;
- surface->repeat = 0;
-}
-
-cairo_surface_t *
-cairo_surface_create_for_image (char *data,
- cairo_format_t format,
- int width,
- int height,
- int stride)
-{
- return cairo_image_surface_create_for_data (data, format, width, height, stride);
-}
-slim_hidden_def(cairo_surface_create_for_image);
-
-cairo_surface_t *
-_cairo_surface_create_similar_scratch (cairo_surface_t *other,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- if (other == NULL)
- return NULL;
-
- return other->backend->create_similar (other, format, drawable,
- width, height);
-}
-
-cairo_surface_t *
-cairo_surface_create_similar (cairo_surface_t *other,
- cairo_format_t format,
- int width,
- int height)
-{
- cairo_color_t empty;
-
- if (other == NULL)
- return NULL;
-
- _cairo_color_init (&empty);
- _cairo_color_set_rgb (&empty, 0., 0., 0.);
- _cairo_color_set_alpha (&empty, 0.);
-
- return _cairo_surface_create_similar_solid (other, format, width, height, &empty);
-}
-
-cairo_surface_t *
-_cairo_surface_create_similar_solid (cairo_surface_t *other,
- cairo_format_t format,
- int width,
- int height,
- cairo_color_t *color)
-{
- cairo_status_t status;
- cairo_surface_t *surface;
-
- surface = _cairo_surface_create_similar_scratch (other, format, 1,
- width, height);
-
- if (surface == NULL)
- surface = cairo_image_surface_create (format, width, height);
-
- status = _cairo_surface_fill_rectangle (surface,
- CAIRO_OPERATOR_SRC, color,
- 0, 0, width, height);
- if (status) {
- cairo_surface_destroy (surface);
- return NULL;
- }
-
- 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;
-
- if (surface->backend->destroy)
- surface->backend->destroy (surface);
-}
-slim_hidden_def(cairo_surface_destroy);
-
-double
-_cairo_surface_pixels_per_inch (cairo_surface_t *surface)
-{
- return surface->backend->pixels_per_inch (surface);
-}
-
-/**
- * _cairo_surface_acquire_source_image:
- * @surface: a #cairo_surface_t
- * @image_out: location to store a pointer to an image surface that includes at least
- * the intersection of @interest_rect with the visible area of @surface.
- * This surface could be @surface itself, a surface held internal to @surface,
- * or it could be a new surface with a copy of the relevant portion of @surface.
- * @image_extra: location to store image specific backend data
- *
- * Gets an image surface to use when drawing as a fallback when drawing with
- * @surface as a source. _cairo_surface_release_source_image() must be called
- * when finished.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if a an image was stored in @image_out.
- * %CAIRO_INT_STATUS_UNSUPPORTED if an image cannot be retrieved for the specified
- * surface. Or %CAIRO_STATUS_NO_MEMORY.
- **/
-cairo_private cairo_status_t
-_cairo_surface_acquire_source_image (cairo_surface_t *surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- return surface->backend->acquire_source_image (surface, image_out, image_extra);
-}
-
-/**
- * _cairo_surface_release_source_image:
- * @surface: a #cairo_surface_t
- * @image_extra: same as return from the matching _cairo_surface_acquire_dest_image()
- *
- * Releases any resources obtained with _cairo_surface_acquire_source_image()
- **/
-cairo_private void
-_cairo_surface_release_source_image (cairo_surface_t *surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
- surface->backend->release_source_image (surface, image, image_extra);
-}
-
-/**
- * _cairo_surface_acquire_dest_image:
- * @surface: a #cairo_surface_t
- * @interest_rect: area of @surface for which fallback drawing is being done.
- * A value of %NULL indicates that the entire surface is desired.
- * @image_out: location to store a pointer to an image surface that includes at least
- * the intersection of @interest_rect with the visible area of @surface.
- * This surface could be @surface itself, a surface held internal to @surface,
- * or it could be a new surface with a copy of the relevant portion of @surface.
- * @image_rect: location to store area of the original surface occupied
- * by the surface stored in @image.
- * @image_extra: location to store image specific backend data
- *
- * Retrieves a local image for a surface for implementing a fallback drawing
- * operation. After calling this function, the implementation of the fallback
- * drawing operation draws the primitive to the surface stored in @image_out
- * then calls _cairo_surface_release_dest_fallback(),
- * which, if a temporary surface was created, copies the bits back to the
- * main surface and frees the temporary surface.
- *
- * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY.
- * %CAIRO_INT_STATUS_UNSUPPORTED can be returned but this will mean that
- * the backend can't draw with fallbacks. It's possible for the routine
- * to store NULL in @local_out and return %CAIRO_STATUS_SUCCESS;
- * that indicates that no part of @interest_rect is visible, so no drawing
- * is necessary. _cairo_surface_release_dest_fallback() should not be called in that
- * case.
- **/
-cairo_status_t
-_cairo_surface_acquire_dest_image (cairo_surface_t *surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect,
- void **image_extra)
-{
- return surface->backend->acquire_dest_image (surface, interest_rect,
- image_out, image_rect, image_extra);
-}
-
-/**
- * _cairo_surface_end_fallback:
- * @surface: a #cairo_surface_t
- * @interest_rect: same as passed to the matching _cairo_surface_acquire_dest_image()
- * @image: same as returned from the matching _cairo_surface_acquire_dest_image()
- * @image_rect: same as returned from the matching _cairo_surface_acquire_dest_image()
- * @image_extra: same as return from the matching _cairo_surface_acquire_dest_image()
- *
- * Finishes the operation started with _cairo_surface_acquire_dest_image(), by, if
- * necessary, copying the image from @image back to @surface and freeing any
- * resources that were allocated.
- **/
-void
-_cairo_surface_release_dest_image (cairo_surface_t *surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
- surface->backend->release_dest_image (surface, interest_rect,
- image, image_rect, image_extra);
-}
-
-/**
- * _cairo_surface_clone_similar:
- * @surface: a #cairo_surface_t
- * @src: the source image
- * @clone_out: location to store a surface compatible with @surface
- * and with contents identical to @src. The caller must call
- * cairo_surface_destroy() on the result.
- *
- * Creates a surface with contents identical to @src but that
- * can be used efficiently with @surface. If @surface and @src are
- * already compatible then it may return a new reference to @src.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if a surface was created and stored
- * in @clone_out. Otherwise %CAIRO_INT_STATUS_UNSUPPORTED or another
- * error like %CAIRO_STATUS_NO_MEMORY.
- **/
-cairo_status_t
-_cairo_surface_clone_similar (cairo_surface_t *surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- cairo_status_t status;
- cairo_image_surface_t *image;
- void *image_extra;
-
- status = surface->backend->clone_similar (surface, src, clone_out);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
-
- status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
- if (status != CAIRO_STATUS_SUCCESS)
- return status;
-
- status = surface->backend->clone_similar (surface, &image->base, clone_out);
-
- /* If the above failed point, we could implement a full fallback
- * using acquire_dest_image, but that's going to be very
- * inefficient compared to a backend-specific implementation of
- * clone_similar() with an image source. So we don't bother
- */
-
- _cairo_surface_release_source_image (src, image, image_extra);
- return status;
-}
-
-cairo_status_t
-cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
-{
- if (surface == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- return cairo_matrix_copy (&surface->matrix, matrix);
-}
-slim_hidden_def(cairo_surface_set_matrix);
-
-cairo_status_t
-cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
-{
- if (surface == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- return cairo_matrix_copy (matrix, &surface->matrix);
-}
-slim_hidden_def(cairo_surface_get_matrix);
-
-cairo_status_t
-cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter)
-{
- if (surface == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- surface->filter = filter;
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_filter_t
-cairo_surface_get_filter (cairo_surface_t *surface)
-{
- return surface->filter;
-}
-
-/* XXX: NYI
-cairo_status_t
-cairo_surface_clip_rectangle (cairo_surface_t *surface,
- int x, int y,
- int width, int height)
-{
-
-}
-*/
-
-/* XXX: NYI
-cairo_status_t
-cairo_surface_clip_restore (cairo_surface_t *surface);
-*/
-
-cairo_status_t
-cairo_surface_set_repeat (cairo_surface_t *surface, int repeat)
-{
- if (surface == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- surface->repeat = repeat;
-
- return CAIRO_STATUS_SUCCESS;
-}
-slim_hidden_def(cairo_surface_set_repeat);
-
-typedef struct {
- cairo_surface_t *dst;
- cairo_rectangle_t extents;
- cairo_image_surface_t *image;
- cairo_rectangle_t image_rect;
- void *image_extra;
-} fallback_state_t;
-
-static cairo_status_t
-_fallback_init (fallback_state_t *state,
- cairo_surface_t *dst,
- int x,
- int y,
- int width,
- int height)
-{
- state->extents.x = x;
- state->extents.y = y;
- state->extents.width = width;
- state->extents.height = height;
-
- state->dst = dst;
-
- return _cairo_surface_acquire_dest_image (dst, &state->extents,
- &state->image, &state->image_rect, &state->image_extra);
-}
-
-static void
-_fallback_cleanup (fallback_state_t *state)
-{
- _cairo_surface_release_dest_image (state->dst, &state->extents,
- state->image, &state->image_rect, state->image_extra);
-}
-
-static cairo_status_t
-_fallback_composite (cairo_operator_t operator,
- cairo_pattern_t *src,
- cairo_pattern_t *mask,
- cairo_surface_t *dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- fallback_state_t state;
- cairo_status_t status;
-
- status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
- if (!CAIRO_OK (status) || !state.image)
- return status;
-
- state.image->base.backend->composite (operator, src, mask,
- &state.image->base,
- src_x, src_y, mask_x, mask_y,
- dst_x - state.image_rect.x,
- dst_y - state.image_rect.y,
- width, height);
-
- _fallback_cleanup (&state);
-
- return status;
-}
-
-cairo_status_t
-_cairo_surface_composite (cairo_operator_t operator,
- cairo_pattern_t *src,
- cairo_pattern_t *mask,
- cairo_surface_t *dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- cairo_int_status_t status;
-
- status = dst->backend->composite (operator,
- src, mask, dst,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
-
- return _fallback_composite (operator,
- src, mask, dst,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
-}
-
-cairo_status_t
-_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_rectangle_t rect;
-
- rect.x = x;
- rect.y = y;
- rect.width = width;
- rect.height = height;
-
- return _cairo_surface_fill_rectangles (surface, operator, color, &rect, 1);
-}
-
-static cairo_status_t
-_fallback_fill_rectangles (cairo_surface_t *surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- fallback_state_t state;
- cairo_rectangle_t *offset_rects = NULL;
- cairo_status_t status;
- int x1, y1, x2, y2;
- int i;
-
- if (num_rects <= 0)
- return CAIRO_STATUS_SUCCESS;
-
- /* Compute the bounds of the rectangles, so that we know what area of the
- * destination surface to fetch
- */
- x1 = rects[0].x;
- y1 = rects[0].y;
- x2 = rects[0].x + rects[0].width;
- y2 = rects[0].y + rects[0].height;
-
- for (i = 1; i < num_rects; i++) {
- if (rects[0].x < x1)
- x1 = rects[0].x;
- if (rects[0].y < y1)
- y1 = rects[0].y;
-
- if (rects[0].x + rects[0].width > x2)
- x2 = rects[0].x + rects[0].width;
- if (rects[0].y + rects[0].height > y2)
- y2 = rects[0].y + rects[0].height;
- }
-
- status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
- if (!CAIRO_OK (status) || !state.image)
- return status;
-
- /* If the fetched image isn't at 0,0, we need to offset the rectangles */
-
- if (state.image_rect.x != 0 || state.image_rect.y != 0) {
- offset_rects = malloc (sizeof (cairo_rectangle_t) * num_rects);
- if (!offset_rects) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
-
- for (i = 0; i < num_rects; i++) {
- offset_rects[i].x = rects[i].x - state.image_rect.x;
- offset_rects[i].y = rects[i].y - state.image_rect.y;
- offset_rects[i].width = rects[i].width;
- offset_rects[i].height = rects[i].height;
- }
-
- rects = offset_rects;
- }
-
- state.image->base.backend->fill_rectangles (&state.image->base, operator, color,
- rects, num_rects);
-
- if (offset_rects)
- free (offset_rects);
-
- FAIL:
- _fallback_cleanup (&state);
-
- return status;
-}
-
-cairo_status_t
-_cairo_surface_fill_rectangles (cairo_surface_t *surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- cairo_int_status_t status;
-
- if (num_rects == 0)
- return CAIRO_STATUS_SUCCESS;
-
- status = surface->backend->fill_rectangles (surface,
- operator,
- color,
- rects, num_rects);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
-
- return _fallback_fill_rectangles (surface, operator, color, rects, num_rects);
-}
-
-static cairo_status_t
-_fallback_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- fallback_state_t state;
- cairo_trapezoid_t *offset_traps = NULL;
- cairo_status_t status;
- int i;
-
- status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
- if (!CAIRO_OK (status) || !state.image)
- return status;
-
- /* If the destination image isn't at 0,0, we need to offset the trapezoids */
-
- if (state.image_rect.x != 0 || state.image_rect.y != 0) {
-
- cairo_fixed_t xoff = _cairo_fixed_from_int (state.image_rect.x);
- cairo_fixed_t yoff = _cairo_fixed_from_int (state.image_rect.y);
-
- offset_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps);
- if (!offset_traps) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
-
- for (i = 0; i < num_traps; i++) {
- offset_traps[i].top = traps[i].top - yoff;
- offset_traps[i].bottom = traps[i].bottom - yoff;
- offset_traps[i].left.p1.x = traps[i].left.p1.x - xoff;
- offset_traps[i].left.p1.y = traps[i].left.p1.y - yoff;
- offset_traps[i].left.p2.x = traps[i].left.p2.x - xoff;
- offset_traps[i].left.p2.y = traps[i].left.p2.y - yoff;
- offset_traps[i].right.p1.x = traps[i].right.p1.x - xoff;
- offset_traps[i].right.p1.y = traps[i].right.p1.y - yoff;
- offset_traps[i].right.p2.x = traps[i].right.p2.x - xoff;
- offset_traps[i].right.p2.y = traps[i].right.p2.y - yoff;
- }
-
- traps = offset_traps;
- }
-
- state.image->base.backend->composite_trapezoids (operator, pattern,
- &state.image->base,
- src_x, src_y,
- dst_x - state.image_rect.x,
- dst_y - state.image_rect.y,
- width, height, traps, num_traps);
- if (offset_traps)
- free (offset_traps);
-
- FAIL:
- _fallback_cleanup (&state);
-
- return status;
-}
-
-
-cairo_status_t
-_cairo_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- cairo_int_status_t status;
-
- status = dst->backend->composite_trapezoids (operator,
- pattern, dst,
- src_x, src_y,
- dst_x, dst_y,
- width, height,
- traps, num_traps);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
-
- return _fallback_composite_trapezoids (operator, pattern, dst,
- src_x, src_y,
- dst_x, dst_y,
- width, height,
- traps, num_traps);
-}
-
-cairo_status_t
-_cairo_surface_copy_page (cairo_surface_t *surface)
-{
- cairo_int_status_t status;
-
- status = surface->backend->copy_page (surface);
- /* It's fine if some backends just don't support this. */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
- return CAIRO_STATUS_SUCCESS;
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_surface_show_page (cairo_surface_t *surface)
-{
- cairo_int_status_t status;
-
- status = surface->backend->show_page (surface);
- /* It's fine if some backends just don't support this. */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
- return CAIRO_STATUS_SUCCESS;
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region)
-{
- return surface->backend->set_clip_region (surface, region);
-}
diff --git a/src/cairo_traps.c b/src/cairo_traps.c
deleted file mode 100644
index 79c7e16b6..000000000
--- a/src/cairo_traps.c
+++ /dev/null
@@ -1,740 +0,0 @@
-/*
- * Copyright © 2002 Keith Packard
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is Keith Packard
- *
- * Contributor(s):
- * Keith R. Packard <keithp@keithp.com>
- * Carl D. Worth <cworth@cworth.org>
- *
- * 2002-07-15: Converted from XRenderCompositeDoublePoly to cairo_trap. Carl D. Worth
- */
-
-#include "cairoint.h"
-
-/* private functions */
-
-static cairo_status_t
-_cairo_traps_grow_by (cairo_traps_t *traps, int additional);
-
-static cairo_status_t
-_cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom,
- cairo_line_t *left, cairo_line_t *right);
-
-static cairo_status_t
-_cairo_traps_add_trap_from_points (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom,
- cairo_point_t left_p1, cairo_point_t left_p2,
- cairo_point_t right_p1, cairo_point_t 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 int
-_compare_cairo_edge_by_slope (const void *av, const void *bv);
-
-static cairo_fixed_16_16_t
-_compute_x (cairo_line_t *line, cairo_fixed_t y);
-
-static int
-_line_segs_intersect_ceil (cairo_line_t *left, cairo_line_t *right, cairo_fixed_t *y_ret);
-
-void
-_cairo_traps_init (cairo_traps_t *traps)
-{
- traps->num_traps = 0;
-
- traps->traps_size = 0;
- traps->traps = NULL;
- traps->extents.p1.x = traps->extents.p1.y = CAIRO_MAXSHORT << 16;
- traps->extents.p2.x = traps->extents.p2.y = CAIRO_MINSHORT << 16;
-}
-
-void
-_cairo_traps_fini (cairo_traps_t *traps)
-{
- if (traps->traps_size) {
- free (traps->traps);
- traps->traps = NULL;
- traps->traps_size = 0;
- traps->num_traps = 0;
- }
-}
-
-static cairo_status_t
-_cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom,
- cairo_line_t *left, cairo_line_t *right)
-{
- cairo_status_t status;
- cairo_trapezoid_t *trap;
-
- if (top == bottom) {
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (traps->num_traps >= traps->traps_size) {
- int inc = traps->traps_size ? traps->traps_size : 32;
- status = _cairo_traps_grow_by (traps, inc);
- if (status)
- return status;
- }
-
- trap = &traps->traps[traps->num_traps];
- trap->top = top;
- trap->bottom = bottom;
- trap->left = *left;
- trap->right = *right;
-
- if (top < traps->extents.p1.y)
- traps->extents.p1.y = top;
- if (bottom > traps->extents.p2.y)
- traps->extents.p2.y = bottom;
- /*
- * This isn't generally accurate, but it is close enough for
- * this purpose. Assuming that the left and right segments always
- * contain the trapezoid vertical extents, these compares will
- * yield a containing box. Assuming that the points all come from
- * the same figure which will eventually be completely drawn, then
- * the compares will yield the correct overall extents
- */
- if (left->p1.x < traps->extents.p1.x)
- traps->extents.p1.x = left->p1.x;
- if (left->p2.x < traps->extents.p1.x)
- traps->extents.p1.x = left->p2.x;
-
- if (right->p1.x > traps->extents.p2.x)
- traps->extents.p2.x = right->p1.x;
- if (right->p2.x > traps->extents.p2.x)
- traps->extents.p2.x = right->p2.x;
-
- traps->num_traps++;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_traps_add_trap_from_points (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom,
- cairo_point_t left_p1, cairo_point_t left_p2,
- cairo_point_t right_p1, cairo_point_t right_p2)
-{
- cairo_line_t left;
- cairo_line_t 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)
-{
- cairo_trapezoid_t *new_traps;
- int old_size = traps->traps_size;
- int new_size = traps->num_traps + additional;
-
- if (new_size <= traps->traps_size) {
- return CAIRO_STATUS_SUCCESS;
- }
-
- traps->traps_size = new_size;
- new_traps = realloc (traps->traps, traps->traps_size * sizeof (cairo_trapezoid_t));
-
- if (new_traps == NULL) {
- traps->traps_size = old_size;
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- traps->traps = new_traps;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static int
-_compare_point_fixed_by_y (const void *av, const void *bv)
-{
- const cairo_point_t *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, cairo_point_t t[3])
-{
- cairo_status_t status;
- cairo_line_t line;
- cairo_fixed_16_16_t intersect;
- cairo_point_t tsort[3];
-
- memcpy (tsort, t, 3 * sizeof (cairo_point_t));
- qsort (tsort, 3, sizeof (cairo_point_t), _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, cairo_point_t q[4])
-{
- cairo_status_t status;
-
- qsort (q, 4, sizeof (cairo_point_t), _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;
-
- return a->edge.p1.y - b->edge.p1.y;
-}
-
-/* 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;
- cairo_fixed_32_32_t d;
-
- cairo_fixed_48_16_t a_dx = a->edge.p2.x - a->edge.p1.x;
- cairo_fixed_48_16_t a_dy = a->edge.p2.y - a->edge.p1.y;
- cairo_fixed_48_16_t b_dx = b->edge.p2.x - b->edge.p1.x;
- cairo_fixed_48_16_t b_dy = b->edge.p2.y - b->edge.p1.y;
-
- d = b_dy * a_dx - a_dy * b_dx;
-
- if (d > 0)
- return 1;
- else if (d == 0)
- return 0;
- else
- return -1;
-}
-
-static int
-_compare_cairo_edge_by_current_x_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).
- */
-
-/* XXX: Keith's new intersection code is much cleaner, and uses
- * sufficient precision for correctly sorting intersections according
- * to the analysis in Hobby's paper.
- *
- * But, when we enable this code, some things are failing, (eg. the
- * stars in test/fill_rule get filled wrong). This could indicate a
- * bug in one of tree places:
- *
- * 1) The new intersection code in this file
- *
- * 2) cairo_wideint.c (which is only exercised here)
- *
- * 3) In the current tessellator, (where the old intersection
- * code, with its mystic increments could be masking the bug).
- *
- * It will likely be easier to revisit this when the new tessellation
- * code is in place. So, for now, we'll simply disable the new
- * intersection code.
- */
-
-#define CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE 0
-
-#if CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE
-static const cairo_fixed_32_32_t
-_det16_32 (cairo_fixed_16_16_t a,
- cairo_fixed_16_16_t b,
- cairo_fixed_16_16_t c,
- cairo_fixed_16_16_t d)
-{
- return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d),
- _cairo_int32x32_64_mul (b, c));
-}
-
-static const cairo_fixed_64_64_t
-_det32_64 (cairo_fixed_32_32_t a,
- cairo_fixed_32_32_t b,
- cairo_fixed_32_32_t c,
- cairo_fixed_32_32_t d)
-{
- return _cairo_int128_sub (_cairo_int64x64_128_mul (a, d),
- _cairo_int64x64_128_mul (b, c));
-}
-
-static const cairo_fixed_32_32_t
-_fixed_16_16_to_fixed_32_32 (cairo_fixed_16_16_t a)
-{
- return _cairo_int64_lsl (_cairo_int32_to_int64 (a), 16);
-}
-
-static int
-_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection)
-{
- cairo_fixed_16_16_t dx1, dx2, dy1, dy2;
- cairo_fixed_32_32_t den_det;
- cairo_fixed_32_32_t l1_det, l2_det;
- cairo_fixed_64_64_t num_det;
- cairo_fixed_32_32_t intersect_32_32;
- cairo_fixed_48_16_t intersect_48_16;
- cairo_fixed_16_16_t intersect_16_16;
- cairo_quorem128_t qr;
-
- dx1 = l1->p1.x - l1->p2.x;
- dy1 = l1->p1.y - l1->p2.y;
- dx2 = l2->p1.x - l2->p2.x;
- dy2 = l2->p1.y - l2->p2.y;
- den_det = _det16_32 (dx1, dy1,
- dx2, dy2);
-
- if (_cairo_int64_eq (den_det, _cairo_int32_to_int64(0)))
- return 0;
-
- l1_det = _det16_32 (l1->p1.x, l1->p1.y,
- l1->p2.x, l1->p2.y);
- l2_det = _det16_32 (l2->p1.x, l2->p1.y,
- l2->p2.x, l2->p2.y);
-
-
- num_det = _det32_64 (l1_det, _fixed_16_16_to_fixed_32_32 (dy1),
- l2_det, _fixed_16_16_to_fixed_32_32 (dy2));
-
- /*
- * Ok, this one is a bit tricky in fixed point, the denominator
- * needs to be left with 32-bits of fraction so that the
- * result of the divide ends up with 32-bits of fraction (64 - 32 = 32)
- */
- qr = _cairo_int128_divrem (num_det, _cairo_int64_to_int128 (den_det));
-
- intersect_32_32 = _cairo_int128_to_int64 (qr.quo);
-
- /*
- * Find the ceiling of the quotient -- divrem returns
- * the quotient truncated towards zero, so if the
- * quotient should be positive (num_den and den_det have same sign)
- * bump the quotient up by one.
- */
-
- if (_cairo_int128_ne (qr.rem, _cairo_int32_to_int128 (0)) &&
- (_cairo_int128_ge (num_det, _cairo_int32_to_int128 (0)) ==
- _cairo_int64_ge (den_det, _cairo_int32_to_int64 (0))))
- {
- intersect_32_32 = _cairo_int64_add (intersect_32_32,
- _cairo_int32_to_int64 (1));
- }
-
- /*
- * Now convert from 32.32 to 48.16 and take the ceiling;
- * this requires adding in 15 1 bits and shifting the result
- */
-
- intersect_32_32 = _cairo_int64_add (intersect_32_32,
- _cairo_int32_to_int64 ((1 << 16) - 1));
- intersect_48_16 = _cairo_int64_rsa (intersect_32_32, 16);
-
- /*
- * And drop the top bits
- */
- intersect_16_16 = _cairo_int64_to_int32 (intersect_48_16);
-
- *y_intersection = intersect_16_16;
-
- return 1;
-}
-#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */
-
-static cairo_fixed_16_16_t
-_compute_x (cairo_line_t *line, cairo_fixed_t y)
-{
- cairo_fixed_16_16_t dx = line->p2.x - line->p1.x;
- cairo_fixed_32_32_t ex = (cairo_fixed_48_16_t) (y - line->p1.y) * (cairo_fixed_48_16_t) dx;
- cairo_fixed_16_16_t dy = line->p2.y - line->p1.y;
-
- return line->p1.x + (ex / dy);
-}
-
-#if ! CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE
-static double
-_compute_inverse_slope (cairo_line_t *l)
-{
- return (_cairo_fixed_to_double (l->p2.x - l->p1.x) /
- _cairo_fixed_to_double (l->p2.y - l->p1.y));
-}
-
-static double
-_compute_x_intercept (cairo_line_t *l, double inverse_slope)
-{
- return _cairo_fixed_to_double (l->p1.x) - inverse_slope * _cairo_fixed_to_double (l->p1.y);
-}
-
-static int
-_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_ret)
-{
- /*
- * x = m1y + b1
- * x = m2y + b2
- * m1y + b1 = m2y + b2
- * y * (m1 - m2) = b2 - b1
- * y = (b2 - b1) / (m1 - m2)
- */
- cairo_fixed_16_16_t y_intersect;
- 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_intersect = _cairo_fixed_from_double ((b2 - b1) / (m1 - m2));
-
- if (m1 < m2) {
- cairo_line_t *t;
- t = l1;
- l1 = l2;
- l2 = t;
- }
-
- /* Assuming 56 bits of floating point precision, the intersection
- is accurate within one sub-pixel coordinate. We must ensure
- that we return a value that is at or after the intersection. At
- most, we must increment once. */
- if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))
- y_intersect++;
- /* XXX: Hmm... Keith's error calculations said we'd at most be off
- by one sub-pixel. But, I found that the paint-fill-BE-01.svg
- test from the W3C SVG conformance suite definitely requires two
- increments.
-
- It could be that we need one to overcome the error, and another
- to round up.
-
- It would be nice to be sure this code is correct, (but we can't
- do the while loop as it will work for way to long on
- exceedingly distant intersections with large errors that we
- really don't care about anyway as they will be ignored by the
- calling function.
- */
- if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))
- y_intersect++;
- /* XXX: hmm... now I found "intersection_killer" inside xrspline.c
- that requires 3 increments. Clearly, we haven't characterized
- this completely yet. */
- if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))
- y_intersect++;
- /* I think I've found the answer to our problems. The insight is
- that everytime we round we are changing the slopes of the
- relevant lines, so we may be introducing new intersections that
- we miss, so everything breaks apart. John Hobby wrote a paper
- on how to fix this:
-
- [Hobby93c] John D. Hobby, Practical Segment Intersection with
- Finite Precision Output, Computation Geometry Theory and
- Applications, 13(4), 1999.
-
- Available online (2003-08017):
-
- http://cm.bell-labs.com/cm/cs/doc/93/2-27.ps.gz
-
- Now we just need to go off and implement that.
- */
-
- *y_ret = y_intersect;
-
- return 1;
-}
-#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */
-
-/* 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 obliterates 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 i, active, inactive;
- cairo_fixed_t y, y_next, 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 < num_edges) {
- while (inactive < num_edges && edges[inactive].edge.p1.y <= y)
- inactive++;
-
- for (i = active; i < inactive; i++)
- edges[i].current_x = _compute_x (&edges[i].edge, y);
-
- qsort (&edges[active], inactive - active,
- sizeof (cairo_edge_t), _compare_cairo_edge_by_current_x_slope);
-
- /* find next inflection point */
- y_next = edges[active].edge.p2.y;
-
- for (i = active; i < inactive; i++) {
- if (edges[i].edge.p2.y < y_next)
- y_next = edges[i].edge.p2.y;
- /* check intersect */
- if (i != inactive - 1 && edges[i].current_x != edges[i+1].current_x)
- if (_line_segs_intersect_ceil (&edges[i].edge, &edges[i+1].edge,
- &intersect))
- if (intersect > y && intersect < y_next)
- y_next = intersect;
- }
- /* check next inactive point */
- if (inactive < num_edges && edges[inactive].edge.p1.y < y_next)
- y_next = edges[inactive].edge.p1.y;
-
- /* walk the active edges generating trapezoids */
- in_out = 0;
- for (i = active; i < inactive - 1; i++) {
- if (fill_rule == CAIRO_FILL_RULE_WINDING) {
- if (edges[i].clockWise)
- in_out++;
- else
- in_out--;
- if (in_out == 0)
- continue;
- } else {
- in_out++;
- if ((in_out & 1) == 0)
- continue;
- }
- status = _cairo_traps_add_trap (traps, y, y_next, &edges[i].edge, &edges[i+1].edge);
- if (status)
- return status;
- }
-
- /* delete inactive edges */
- for (i = active; i < inactive; i++) {
- if (edges[i].edge.p2.y <= y_next) {
- memmove (&edges[active+1], &edges[active], (i - active) * sizeof (cairo_edge_t));
- active++;
- }
- }
-
- y = y_next;
- }
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_bool_t
-_cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
-{
- cairo_slope_t slope_left, slope_pt, slope_right;
-
- if (t->top > pt->y)
- return FALSE;
- if (t->bottom < pt->y)
- return FALSE;
-
- _cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2);
- _cairo_slope_init (&slope_pt, &t->left.p1, pt);
-
- if (_cairo_slope_compare (&slope_left, &slope_pt) < 0)
- return FALSE;
-
- _cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2);
- _cairo_slope_init (&slope_pt, &t->right.p1, pt);
-
- if (_cairo_slope_compare (&slope_pt, &slope_right) < 0)
- return FALSE;
-
- return TRUE;
-}
-
-cairo_bool_t
-_cairo_traps_contain (cairo_traps_t *traps, double x, double y)
-{
- int i;
- cairo_point_t point;
-
- point.x = _cairo_fixed_from_double (x);
- point.y = _cairo_fixed_from_double (y);
-
- for (i = 0; i < traps->num_traps; i++) {
- if (_cairo_trap_contains (&traps->traps[i], &point))
- return TRUE;
- }
-
- return FALSE;
-}
-
-void
-_cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents)
-{
- *extents = traps->extents;
-}
diff --git a/src/cairo_unicode.c b/src/cairo_unicode.c
deleted file mode 100644
index 92201391a..000000000
--- a/src/cairo_unicode.c
+++ /dev/null
@@ -1,340 +0,0 @@
-/* cairo_unicode.c: Unicode conversion routines
- *
- * The code in this file is derived from GLib's gutf8.c and
- * ultimately from libunicode. It is relicensed under the
- * dual LGPL/MPL with permission of the original authors.
- *
- * Copyright © 1999 Tom Tromey
- * Copyright © 2005 Red Hat, Inc
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is cairo_unicode.c as distributed with the
- * cairo graphics library.
- *
- * The Initial Developer of the Original Code is Tom Tromey.
- * and Red Hat, Inc.
- *
- * Contributor(s):
- * Owen Taylor <otaylor@redhat.com>
- */
-
-#include <limits.h>
-
-#include <cairoint.h>
-
-#define UTF8_COMPUTE(Char, Mask, Len) \
- if (Char < 128) \
- { \
- Len = 1; \
- Mask = 0x7f; \
- } \
- else if ((Char & 0xe0) == 0xc0) \
- { \
- Len = 2; \
- Mask = 0x1f; \
- } \
- else if ((Char & 0xf0) == 0xe0) \
- { \
- Len = 3; \
- Mask = 0x0f; \
- } \
- else if ((Char & 0xf8) == 0xf0) \
- { \
- Len = 4; \
- Mask = 0x07; \
- } \
- else if ((Char & 0xfc) == 0xf8) \
- { \
- Len = 5; \
- Mask = 0x03; \
- } \
- else if ((Char & 0xfe) == 0xfc) \
- { \
- Len = 6; \
- Mask = 0x01; \
- } \
- else \
- Len = -1;
-
-#define UTF8_LENGTH(Char) \
- ((Char) < 0x80 ? 1 : \
- ((Char) < 0x800 ? 2 : \
- ((Char) < 0x10000 ? 3 : \
- ((Char) < 0x200000 ? 4 : \
- ((Char) < 0x4000000 ? 5 : 6)))))
-
-
-#define UTF8_GET(Result, Chars, Count, Mask, Len) \
- (Result) = (Chars)[0] & (Mask); \
- for ((Count) = 1; (Count) < (Len); ++(Count)) \
- { \
- if (((Chars)[(Count)] & 0xc0) != 0x80) \
- { \
- (Result) = -1; \
- break; \
- } \
- (Result) <<= 6; \
- (Result) |= ((Chars)[(Count)] & 0x3f); \
- }
-
-#define UNICODE_VALID(Char) \
- ((Char) < 0x110000 && \
- (((Char) & 0xFFFFF800) != 0xD800) && \
- ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \
- ((Char) & 0xFFFE) != 0xFFFE)
-
-
-static const char utf8_skip_data[256] = {
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
-};
-
-#define UTF8_NEXT_CHAR(p) (char *)((p) + utf8_skip_data[*(unsigned char *)(p)])
-
-/* Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
- * If @p does not point to a valid UTF-8 encoded character, results are
- * undefined.
- **/
-static uint32_t
-_utf8_get_char (const char *p)
-{
- int i, mask = 0, len;
- uint32_t result;
- unsigned char c = (unsigned char) *p;
-
- UTF8_COMPUTE (c, mask, len);
- if (len == -1)
- return (uint32_t)-1;
- UTF8_GET (result, p, i, mask, len);
-
- return result;
-}
-
-/* Like _utf8_get_char, but take a maximum length
- * and return (uint32_t)-2 on incomplete trailing character
- */
-static uint32_t
-_utf8_get_char_extended (const char *p,
- long max_len)
-{
- int i, len;
- uint32_t wc = (unsigned char) *p;
-
- if (wc < 0x80) {
- return wc;
- } else if (wc < 0xc0) {
- return (uint32_t)-1;
- } else if (wc < 0xe0) {
- len = 2;
- wc &= 0x1f;
- } else if (wc < 0xf0) {
- len = 3;
- wc &= 0x0f;
- } else if (wc < 0xf8) {
- len = 4;
- wc &= 0x07;
- } else if (wc < 0xfc) {
- len = 5;
- wc &= 0x03;
- } else if (wc < 0xfe) {
- len = 6;
- wc &= 0x01;
- } else {
- return (uint32_t)-1;
- }
-
- if (max_len >= 0 && len > max_len) {
- for (i = 1; i < max_len; i++) {
- if ((((unsigned char *)p)[i] & 0xc0) != 0x80)
- return (uint32_t)-1;
- }
- return (uint32_t)-2;
- }
-
- for (i = 1; i < len; ++i) {
- uint32_t ch = ((unsigned char *)p)[i];
-
- if ((ch & 0xc0) != 0x80) {
- if (ch)
- return (uint32_t)-1;
- else
- return (uint32_t)-2;
- }
-
- wc <<= 6;
- wc |= (ch & 0x3f);
- }
-
- if (UTF8_LENGTH(wc) != len)
- return (uint32_t)-1;
-
- return wc;
-}
-
-/**
- * _cairo_utf8_to_utf32:
- * @str: an UTF-8 string
- * @len: length of @str in bytes, or -1 if it is nul-terminated.
- * If @len is supplied and the string has an embedded nul
- * byte, only the portion before the nul byte is converted.
- * @result: location to store a pointer to a newly allocated UTF-32
- * string (always native endian). Free with free(). A 0
- * word will be written after the last character.
- * @items_written: location to store number of 32-bit words
- * written. (Not including the trailing 0)
- *
- * Converts a UTF-8 string to UCS-4. UCS-4 is an encoding of Unicode
- * with 1 32-bit word per character. The string is validated to
- * consist entirely of valid Unicode characters.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if the entire string was
- * succesfully converted. %CAIRO_STATUS_INVALID_STRING if an
- * an invalid sequence was found.
- **/
-cairo_status_t
-_cairo_utf8_to_ucs4 (const char *str,
- int len,
- uint32_t **result,
- int *items_written)
-{
- uint32_t *str32 = NULL;
- int n_chars, i;
- const char *in;
-
- in = str;
- n_chars = 0;
- while ((len < 0 || str + len - in > 0) && *in)
- {
- uint32_t wc = _utf8_get_char_extended (in, str + len - in);
- if (wc & 0x80000000 || !UNICODE_VALID (wc))
- return CAIRO_STATUS_INVALID_STRING;
-
- n_chars++;
- if (n_chars == INT_MAX)
- return CAIRO_STATUS_INVALID_STRING;
-
- in = UTF8_NEXT_CHAR (in);
- }
-
- str32 = malloc (sizeof (uint32_t) * (n_chars + 1));
- if (!str32)
- return CAIRO_STATUS_NO_MEMORY;
-
- in = str;
- for (i=0; i < n_chars; i++) {
- str32[i] = _utf8_get_char (in);
- in = UTF8_NEXT_CHAR (in);
- }
- str32[i] = 0;
-
- *result = str32;
- if (items_written)
- *items_written = n_chars;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/**
- * _cairo_utf8_to_utf16:
- * @str: an UTF-8 string
- * @len: length of @str in bytes, or -1 if it is nul-terminated.
- * If @len is supplied and the string has an embedded nul
- * byte, only the portion before the nul byte is converted.
- * @result: location to store a pointer to a newly allocated UTF-16
- * string (always native endian). Free with free(). A 0
- * word will be written after the last character.
- * @items_written: location to store number of 16-bit words
- * written. (Not including the trailing 0)
- *
- * Converts a UTF-8 string to UTF-16. UTF-16 is an encoding of Unicode
- * where characters are represented either as a single 16-bit word, or
- * as a pair of 16-bit "surrogates". The string is validated to
- * consist entirely of valid Unicode characters.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if the entire string was
- * succesfully converted. %CAIRO_STATUS_INVALID_STRING if an
- * an invalid sequence was found.
- **/
-cairo_status_t
-_cairo_utf8_to_utf16 (const char *str,
- int len,
- uint16_t **result,
- int *items_written)
-{
- uint16_t *str16 = NULL;
- int n16, i;
- const char *in;
-
- in = str;
- n16 = 0;
- while ((len < 0 || str + len - in > 0) && *in) {
- uint32_t wc = _utf8_get_char_extended (in, str + len - in);
- if (wc & 0x80000000 || !UNICODE_VALID (wc))
- return CAIRO_STATUS_INVALID_STRING;
-
- if (wc < 0x10000)
- n16 += 1;
- else
- n16 += 2;
-
- if (n16 == INT_MAX - 1 || n16 == INT_MAX)
- return CAIRO_STATUS_INVALID_STRING;
-
- in = UTF8_NEXT_CHAR (in);
- }
-
-
- str16 = malloc (sizeof (uint16_t) * (n16 + 1));
- if (!str16)
- return CAIRO_STATUS_NO_MEMORY;
-
- in = str;
- for (i = 0; i < n16;) {
- uint32_t wc = _utf8_get_char (in);
-
- if (wc < 0x10000) {
- str16[i++] = wc;
- } else {
- str16[i++] = (wc - 0x10000) / 0x400 + 0xd800;
- str16[i++] = (wc - 0x10000) % 0x400 + 0xdc00;
- }
-
- in = UTF8_NEXT_CHAR (in);
- }
-
- str16[i] = 0;
-
- *result = str16;
- if (items_written)
- *items_written = n16;
-
- return CAIRO_STATUS_SUCCESS;
-}
diff --git a/src/cairo_wideint.c b/src/cairo_wideint.c
deleted file mode 100644
index b636dface..000000000
--- a/src/cairo_wideint.c
+++ /dev/null
@@ -1,1024 +0,0 @@
-/*
- * $Id: cairo_wideint.c,v 1.4 2005-01-19 15:07:00 cworth Exp $
- *
- * Copyright © 2004 Keith Packard
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is Keith Packard
- *
- * Contributor(s):
- * Keith R. Packard <keithp@keithp.com>
- */
-
-#include "cairoint.h"
-
-#if !HAVE_UINT64_T || !HAVE_UINT128_T
-
-static const unsigned char top_bit[256] =
-{
- 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
- 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
-};
-
-#endif
-
-#if HAVE_UINT64_T
-
-#define _cairo_uint32s_to_uint64(h,l) ((uint64_t) (h) << 32 | (l))
-
-cairo_uquorem64_t
-_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
-{
- cairo_uquorem64_t qr;
-
- qr.quo = num / den;
- qr.rem = num % den;
- return qr;
-}
-
-#else
-
-cairo_uint64_t
-_cairo_uint32_to_uint64 (uint32_t i)
-{
- cairo_uint64_t q;
-
- q.lo = i;
- q.hi = 0;
- return q;
-}
-
-cairo_int64_t
-_cairo_int32_to_int64 (int32_t i)
-{
- cairo_uint64_t q;
-
- q.lo = i;
- q.hi = i < 0 ? -1 : 0;
- return q;
-}
-
-static const cairo_uint64_t
-_cairo_uint32s_to_uint64 (uint32_t h, uint32_t l)
-{
- cairo_uint64_t q;
-
- q.lo = l;
- q.hi = h;
- return q;
-}
-
-cairo_uint64_t
-_cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b)
-{
- cairo_uint64_t s;
-
- s.hi = a.hi + b.hi;
- s.lo = a.lo + b.lo;
- if (s.lo < a.lo)
- s.hi++;
- return s;
-}
-
-cairo_uint64_t
-_cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b)
-{
- cairo_uint64_t s;
-
- s.hi = a.hi - b.hi;
- s.lo = a.lo - b.lo;
- if (s.lo > a.lo)
- s.hi--;
- return s;
-}
-
-#define uint32_lo(i) ((i) & 0xffff)
-#define uint32_hi(i) ((i) >> 16)
-#define uint32_carry16 ((1) << 16)
-
-cairo_uint64_t
-_cairo_uint32x32_64_mul (uint32_t a, uint32_t b)
-{
- cairo_uint64_t s;
-
- uint16_t ah, al, bh, bl;
- uint32_t r0, r1, r2, r3;
-
- al = uint32_lo (a);
- ah = uint32_hi (a);
- bl = uint32_lo (b);
- bh = uint32_hi (b);
-
- r0 = (uint32_t) al * bl;
- r1 = (uint32_t) al * bh;
- r2 = (uint32_t) ah * bl;
- r3 = (uint32_t) ah * bh;
-
- r1 += uint32_hi(r0); /* no carry possible */
- r1 += r2; /* but this can carry */
- if (r1 < r2) /* check */
- r3 += uint32_carry16;
-
- s.hi = r3 + uint32_hi(r1);
- s.lo = (uint32_lo (r1) << 16) + uint32_lo (r0);
- return s;
-}
-
-cairo_int64_t
-_cairo_int32x32_64_mul (int32_t a, int32_t b)
-{
- s = _cairo_uint32x32_64_mul ((uint32_t) a, (uint32_t b));
- if (a < 0)
- s.hi -= b;
- if (b < 0)
- s.hi -= a;
- return s;
-}
-
-cairo_uint64_t
-_cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b)
-{
- cairo_uint64_t s;
-
- s = _cairo_uint32x32_64_mul (a.lo, b.lo);
- s.hi += a.lo * b.hi + a.hi * b.lo;
- return s;
-}
-
-cairo_uint64_t
-_cairo_uint64_lsl (cairo_uint64_t a, int shift)
-{
- if (shift >= 32)
- {
- a.hi = a.lo;
- a.lo = 0;
- shift -= 32;
- }
- if (shift)
- {
- a.hi = a.hi << shift | a.lo >> (32 - shift);
- a.lo = a.lo << shift;
- }
- return a;
-}
-
-cairo_uint64_t
-_cairo_uint64_rsl (cairo_uint64_t a, int shift)
-{
- if (shift >= 32)
- {
- a.lo = a.hi;
- a.hi = 0;
- shift -= 32;
- }
- if (shift)
- {
- a.lo = a.lo >> shift | a.hi << (32 - shift);
- a.hi = a.hi >> shift;
- }
- return a;
-}
-
-#define _cairo_uint32_rsa(a,n) ((uint32_t) (((int32_t) (a)) >> (n)))
-
-cairo_int64_t
-_cairo_uint64_rsa (cairo_int64_t a, int shift)
-{
- if (shift >= 32)
- {
- a.lo = a.hi;
- a.hi = _cairo_uint32_rsa (a.hi, 31);
- shift -= 32;
- }
- if (shift)
- {
- a.lo = a.lo >> shift | a.hi << (32 - shift);
- a.hi = _cairo_uint32_rsa (a.hi, shift);
- }
- return a;
-}
-
-int
-_cairo_uint64_lt (cairo_uint64_t a, cairo_uint64_t b)
-{
- return (a.hi < b.hi ||
- (a.hi == b.hi && a.lo < b.lo));
-}
-
-int
-_cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b)
-{
- return a.hi == b.hi && a.lo == b.lo;
-}
-
-int
-_cairo_int64_lt (cairo_int64_t a, cairo_int64_t b)
-{
- if (_cairo_int64_negative (a) && !_cairo_int64_negative (b))
- return 1;
- if (!_cairo_int64_negative (a) && _cairo_int64_negative (b))
- return 0;
- return _cairo_uint64_lt (a, b);
-}
-
-cairo_uint64_t
-_cairo_uint64_not (cairo_uint64_t a)
-{
- a.lo = ~a.lo;
- a.hi = ~a.hi;
- return a;
-}
-
-cairo_uint64_t
-_cairo_uint64_negate (cairo_uint64_t a)
-{
- a.lo = ~a.lo;
- a.hi = ~a.hi;
- if (++a.lo == 0)
- ++a.hi;
- return a;
-}
-
-/*
- * The design of this algorithm comes from GCC,
- * but the actual implementation is new
- */
-
-static const int
-_cairo_leading_zeros32 (uint32_t i)
-{
- int top;
-
- if (i < 0x100)
- top = 0;
- else if (i < 0x10000)
- top = 8;
- else if (i < 0x1000000)
- top = 16;
- else
- top = 24;
- top = top + top_bit [i >> top];
- return 32 - top;
-}
-
-typedef struct _cairo_uquorem32_t {
- uint32_t quo;
- uint32_t rem;
-} cairo_uquorem32_t;
-
-/*
- * den >= num.hi
- */
-static const cairo_uquorem32_t
-_cairo_uint64x32_normalized_divrem (cairo_uint64_t num, uint32_t den)
-{
- cairo_uquorem32_t qr;
- uint32_t q0, q1, r0, r1;
- uint16_t d0, d1;
- uint32_t t;
-
- d0 = den & 0xffff;
- d1 = den >> 16;
-
- q1 = num.hi / d1;
- r1 = num.hi % d1;
-
- t = q1 * d0;
- r1 = (r1 << 16) | (num.lo >> 16);
- if (r1 < t)
- {
- q1--;
- r1 += den;
- if (r1 >= den && r1 < t)
- {
- q1--;
- r1 += den;
- }
- }
-
- r1 -= t;
-
- q0 = r1 / d1;
- r0 = r1 % d1;
- t = q0 * d0;
- r0 = (r0 << 16) | (num.lo & 0xffff);
- if (r0 < t)
- {
- q0--;
- r0 += den;
- if (r0 >= den && r0 < t)
- {
- q0--;
- r0 += den;
- }
- }
- r0 -= t;
- qr.quo = (q1 << 16) | q0;
- qr.rem = r0;
- return qr;
-}
-
-cairo_uquorem64_t
-_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
-{
- cairo_uquorem32_t qr32;
- cairo_uquorem64_t qr;
- int norm;
- uint32_t q1, q0, r1, r0;
-
- if (den.hi == 0)
- {
- if (den.lo > num.hi)
- {
- /* 0q = nn / 0d */
-
- norm = _cairo_leading_zeros32 (den.lo);
- if (norm)
- {
- den.lo <<= norm;
- num = _cairo_uint64_lsl (num, norm);
- }
- q1 = 0;
- }
- else
- {
- /* qq = NN / 0d */
-
- if (den.lo == 0)
- den.lo = 1 / den.lo;
-
- norm = _cairo_leading_zeros32 (den.lo);
- if (norm)
- {
- cairo_uint64_t num1;
- den.lo <<= norm;
- num1 = _cairo_uint64_rsl (num, 32 - norm);
- qr32 = _cairo_uint64x32_normalized_divrem (num1, den.lo);
- q1 = qr32.quo;
- num.hi = qr32.rem;
- num.lo <<= norm;
- }
- else
- {
- num.hi -= den.lo;
- q1 = 1;
- }
- }
- qr32 = _cairo_uint64x32_normalized_divrem (num, den.lo);
- q0 = qr32.quo;
- r1 = 0;
- r0 = qr32.rem >> norm;
- }
- else
- {
- if (den.hi > num.hi)
- {
- /* 00 = nn / DD */
- q0 = q1 = 0;
- r0 = num.lo;
- r1 = num.hi;
- }
- else
- {
- /* 0q = NN / dd */
-
- norm = _cairo_leading_zeros32 (den.hi);
- if (norm == 0)
- {
- if (num.hi > den.hi || num.lo >= den.lo)
- {
- q0 = 1;
- num = _cairo_uint64_sub (num, den);
- }
- else
- q0 = 0;
-
- q1 = 0;
- r0 = num.lo;
- r1 = num.hi;
- }
- else
- {
- cairo_uint64_t num1;
- cairo_uint64_t part;
-
- num1 = _cairo_uint64_rsl (num, 32 - norm);
- den = _cairo_uint64_lsl (den, norm);
-
- qr32 = _cairo_uint64x32_normalized_divrem (num1, den.hi);
- part = _cairo_uint32x32_64_mul (qr32.quo, den.lo);
-
- q0 = qr32.quo;
-
- num.lo <<= norm;
- num.hi = qr32.rem;
-
- if (_cairo_uint64_gt (part, num))
- {
- q0--;
- part = _cairo_uint64_sub (part, den);
- }
-
- q1 = 0;
-
- num = _cairo_uint64_sub (num, part);
- num = _cairo_uint64_rsl (num, norm);
- r0 = num.lo;
- r1 = num.hi;
- }
- }
- }
- qr.quo.lo = q0;
- qr.quo.hi = q1;
- qr.rem.lo = r0;
- qr.rem.hi = r1;
- return qr;
-}
-
-#endif /* !HAVE_UINT64_T */
-
-cairo_quorem64_t
-_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den)
-{
- int num_neg = _cairo_int64_negative (num);
- int den_neg = _cairo_int64_negative (den);
- cairo_uquorem64_t uqr;
- cairo_quorem64_t qr;
-
- if (num_neg)
- num = _cairo_int64_negate (num);
- if (den_neg)
- den = _cairo_int64_negate (den);
- uqr = _cairo_uint64_divrem (num, den);
- if (num_neg)
- qr.rem = _cairo_int64_negate (uqr.rem);
- else
- qr.rem = uqr.rem;
- if (num_neg != den_neg)
- qr.quo = (cairo_int64_t) _cairo_int64_negate (uqr.quo);
- else
- qr.quo = (cairo_int64_t) uqr.quo;
- return qr;
-}
-
-#if HAVE_UINT128_T
-
-cairo_uquorem128_t
-_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
-{
- cairo_uquorem128_t qr;
-
- qr.quo = num / den;
- qr.rem = num % den;
- return qr;
-}
-
-#else
-
-cairo_uint128_t
-_cairo_uint32_to_uint128 (uint32_t i)
-{
- cairo_uint128_t q;
-
- q.lo = _cairo_uint32_to_uint64 (i);
- q.hi = _cairo_uint32_to_uint64 (0);
- return q;
-}
-
-cairo_int128_t
-_cairo_int32_to_int128 (int32_t i)
-{
- cairo_int128_t q;
-
- q.lo = _cairo_int32_to_int64 (i);
- q.hi = _cairo_int32_to_int64 (i < 0 ? -1 : 0);
- return q;
-}
-
-cairo_uint128_t
-_cairo_uint64_to_uint128 (cairo_uint64_t i)
-{
- cairo_uint128_t q;
-
- q.lo = i;
- q.hi = _cairo_uint32_to_uint64 (0);
- return q;
-}
-
-cairo_int128_t
-_cairo_int64_to_int128 (cairo_int64_t i)
-{
- cairo_int128_t q;
-
- q.lo = i;
- q.hi = _cairo_int32_to_int64 (_cairo_int64_negative(i) ? -1 : 0);
- return q;
-}
-
-cairo_uint128_t
-_cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b)
-{
- cairo_uint128_t s;
-
- s.hi = _cairo_uint64_add (a.hi, b.hi);
- s.lo = _cairo_uint64_add (a.lo, b.lo);
- if (_cairo_uint64_lt (s.lo, a.lo))
- s.hi = _cairo_uint64_add (s.hi, _cairo_uint32_to_uint64 (1));
- return s;
-}
-
-cairo_uint128_t
-_cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b)
-{
- cairo_uint128_t s;
-
- s.hi = _cairo_uint64_sub (a.hi, b.hi);
- s.lo = _cairo_uint64_sub (a.lo, b.lo);
- if (_cairo_uint64_gt (s.lo, a.lo))
- s.hi = _cairo_uint64_sub (s.hi, _cairo_uint32_to_uint64(1));
- return s;
-}
-
-#if HAVE_UINT64_T
-
-#define uint64_lo32(i) ((i) & 0xffffffff)
-#define uint64_hi32(i) ((i) >> 32)
-#define uint64_lo(i) ((i) & 0xffffffff)
-#define uint64_hi(i) ((i) >> 32)
-#define uint64_shift32(i) ((i) << 32)
-#define uint64_carry32 (((uint64_t) 1) << 32)
-
-#else
-
-#define uint64_lo32(i) ((i).lo)
-#define uint64_hi32(i) ((i).hi)
-
-static const cairo_uint64_t
-uint64_lo (cairo_uint64_t i)
-{
- cairo_uint64_t s;
-
- s.lo = i.lo;
- s.hi = 0;
- return s;
-}
-
-static const cairo_uint64_t
-uint64_hi (cairo_uint64_t i)
-{
- cairo_uint64_t s;
-
- s.lo = i.hi;
- s.hi = 0;
- return s;
-}
-
-static const cairo_uint64_t
-uint64_shift32 (cairo_uint64_t i)
-{
- cairo_uint64_t s;
-
- s.lo = 0;
- s.hi = i.lo;
- return s;
-}
-
-static const cairo_uint64_t uint64_carry32 = { 0, 1 };
-
-#endif
-
-cairo_uint128_t
-_cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b)
-{
- cairo_uint128_t s;
- uint32_t ah, al, bh, bl;
- cairo_uint64_t r0, r1, r2, r3;
-
- al = uint64_lo32 (a);
- ah = uint64_hi32 (a);
- bl = uint64_lo32 (b);
- bh = uint64_hi32 (b);
-
- r0 = _cairo_uint32x32_64_mul (al, bl);
- r1 = _cairo_uint32x32_64_mul (al, bh);
- r2 = _cairo_uint32x32_64_mul (ah, bl);
- r3 = _cairo_uint32x32_64_mul (ah, bh);
-
- r1 = _cairo_uint64_add (r1, uint64_hi (r0)); /* no carry possible */
- r1 = _cairo_uint64_add (r1, r2); /* but this can carry */
- if (_cairo_uint64_lt (r1, r2)) /* check */
- r3 = _cairo_uint64_add (r3, uint64_carry32);
-
- s.hi = _cairo_uint64_add (r3, uint64_hi(r1));
- s.lo = _cairo_uint64_add (uint64_shift32 (r1),
- uint64_lo (r0));
- return s;
-}
-
-cairo_int128_t
-_cairo_int64x64_128_mul (cairo_int64_t a, cairo_int64_t b)
-{
- cairo_int128_t s;
- s = _cairo_uint64x64_128_mul (_cairo_int64_to_uint64(a),
- _cairo_int64_to_uint64(b));
- if (_cairo_int64_negative (a))
- s.hi = _cairo_uint64_sub (s.hi,
- _cairo_int64_to_uint64 (b));
- if (_cairo_int64_negative (b))
- s.hi = _cairo_uint64_sub (s.hi,
- _cairo_int64_to_uint64 (a));
- return s;
-}
-
-cairo_uint128_t
-_cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b)
-{
- cairo_uint128_t s;
-
- s = _cairo_uint64x64_128_mul (a.lo, b.lo);
- s.hi = _cairo_uint64_add (s.hi,
- _cairo_uint64_mul (a.lo, b.hi));
- s.hi = _cairo_uint64_add (s.hi,
- _cairo_uint64_mul (a.hi, b.lo));
- return s;
-}
-
-cairo_uint128_t
-_cairo_uint128_lsl (cairo_uint128_t a, int shift)
-{
- if (shift >= 64)
- {
- a.hi = a.lo;
- a.lo = _cairo_uint32_to_uint64 (0);
- shift -= 64;
- }
- if (shift)
- {
- a.hi = _cairo_uint64_add (_cairo_uint64_lsl (a.hi, shift),
- _cairo_uint64_rsl (a.lo, (64 - shift)));
- a.lo = _cairo_uint64_lsl (a.lo, shift);
- }
- return a;
-}
-
-cairo_uint128_t
-_cairo_uint128_rsl (cairo_uint128_t a, int shift)
-{
- if (shift >= 64)
- {
- a.lo = a.hi;
- a.hi = _cairo_uint32_to_uint64 (0);
- shift -= 64;
- }
- if (shift)
- {
- a.lo = _cairo_uint64_add (_cairo_uint64_rsl (a.lo, shift),
- _cairo_uint64_lsl (a.hi, (64 - shift)));
- a.hi = _cairo_uint64_rsl (a.hi, shift);
- }
- return a;
-}
-
-cairo_uint128_t
-_cairo_uint128_rsa (cairo_int128_t a, int shift)
-{
- if (shift >= 64)
- {
- a.lo = a.hi;
- a.hi = _cairo_uint64_rsa (a.hi, 64-1);
- shift -= 64;
- }
- if (shift)
- {
- a.lo = _cairo_uint64_add (_cairo_uint64_rsl (a.lo, shift),
- _cairo_uint64_lsl (a.hi, (64 - shift)));
- a.hi = _cairo_uint64_rsa (a.hi, shift);
- }
- return a;
-}
-
-int
-_cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b)
-{
- return (_cairo_uint64_lt (a.hi, b.hi) ||
- (_cairo_uint64_eq (a.hi, b.hi) &&
- _cairo_uint64_lt (a.lo, b.lo)));
-}
-
-int
-_cairo_int128_lt (cairo_int128_t a, cairo_int128_t b)
-{
- if (_cairo_int128_negative (a) && !_cairo_int128_negative (b))
- return 1;
- if (!_cairo_int128_negative (a) && _cairo_int128_negative (b))
- return 0;
- return _cairo_uint128_lt (a, b);
-}
-
-int
-_cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b)
-{
- return (_cairo_uint64_eq (a.hi, b.hi) &&
- _cairo_uint64_eq (a.lo, b.lo));
-}
-
-/*
- * The design of this algorithm comes from GCC,
- * but the actual implementation is new
- */
-
-/*
- * den >= num.hi
- */
-static cairo_uquorem64_t
-_cairo_uint128x64_normalized_divrem (cairo_uint128_t num, cairo_uint64_t den)
-{
- cairo_uquorem64_t qr64;
- cairo_uquorem64_t qr;
- uint32_t q0, q1;
- cairo_uint64_t r0, r1;
- uint32_t d0, d1;
- cairo_uint64_t t;
-
- d0 = uint64_lo32 (den);
- d1 = uint64_hi32 (den);
-
- qr64 = _cairo_uint64_divrem (num.hi, _cairo_uint32_to_uint64 (d1));
- q1 = _cairo_uint64_to_uint32 (qr64.quo);
- r1 = qr64.rem;
-
- t = _cairo_uint32x32_64_mul (q1, d0);
-
- r1 = _cairo_uint64_add (_cairo_uint64_lsl (r1, 32),
- _cairo_uint64_rsl (num.lo, 32));
-
- if (_cairo_uint64_lt (r1, t))
- {
- q1--;
- r1 = _cairo_uint64_add (r1, den);
- if (_cairo_uint64_ge (r1, den) && _cairo_uint64_lt (r1, t))
- {
- q1--;
- r1 = _cairo_uint64_add (r1, den);
- }
- }
-
- r1 = _cairo_uint64_sub (r1, t);
-
- qr64 = _cairo_uint64_divrem (r1, _cairo_uint32_to_uint64 (d1));
-
- q0 = _cairo_uint64_to_uint32 (qr64.quo);
- r0 = qr64.rem;
-
- t = _cairo_uint32x32_64_mul (q0, d0);
-
- r0 = _cairo_uint64_add (_cairo_uint64_lsl (r0, 32),
- _cairo_uint32_to_uint64 (_cairo_uint64_to_uint32 (num.lo)));
- if (_cairo_uint64_lt (r0, t))
- {
- q0--;
- r0 = _cairo_uint64_add (r0, den);
- if (_cairo_uint64_ge (r0, den) && _cairo_uint64_lt (r0, t))
- {
- q0--;
- r0 = _cairo_uint64_add (r0, den);
- }
- }
-
- r0 = _cairo_uint64_sub (r0, t);
-
- qr.quo = _cairo_uint32s_to_uint64 (q1, q0);
- qr.rem = r0;
- return qr;
-}
-
-#if HAVE_UINT64_T
-
-static int
-_cairo_leading_zeros64 (cairo_uint64_t q)
-{
- int top = 0;
-
- if (q >= (uint64_t) 0x10000 << 16)
- {
- top += 32;
- q >>= 32;
- }
- if (q >= (uint64_t) 0x10000)
- {
- top += 16;
- q >>= 16;
- }
- if (q >= (uint64_t) 0x100)
- {
- top += 8;
- q >>= 8;
- }
- top += top_bit [q];
- return 64 - top;
-}
-
-#else
-
-static const int
-_cairo_leading_zeros64 (cairo_uint64_t d)
-{
- if (d.hi)
- return _cairo_leading_zeros32 (d.hi);
- else
- return 32 + _cairo_leading_zeros32 (d.lo);
-}
-
-#endif
-
-cairo_uquorem128_t
-_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
-{
- cairo_uquorem64_t qr64;
- cairo_uquorem128_t qr;
- int norm;
- cairo_uint64_t q1, q0, r1, r0;
-
- if (_cairo_uint64_eq (den.hi, _cairo_uint32_to_uint64 (0)))
- {
- if (_cairo_uint64_gt (den.lo, num.hi))
- {
- /* 0q = nn / 0d */
-
- norm = _cairo_leading_zeros64 (den.lo);
- if (norm)
- {
- den.lo = _cairo_uint64_lsl (den.lo, norm);
- num = _cairo_uint128_lsl (num, norm);
- }
- q1 = _cairo_uint32_to_uint64 (0);
- }
- else
- {
- /* qq = NN / 0d */
-
- if (_cairo_uint64_eq (den.lo, _cairo_uint32_to_uint64 (0)))
- den.lo = _cairo_uint64_divrem (_cairo_uint32_to_uint64 (1),
- den.lo).quo;
-
- norm = _cairo_leading_zeros64 (den.lo);
- if (norm)
- {
- cairo_uint128_t num1;
-
- den.lo = _cairo_uint64_lsl (den.lo, norm);
- num1 = _cairo_uint128_rsl (num, 64 - norm);
- qr64 = _cairo_uint128x64_normalized_divrem (num1, den.lo);
- q1 = qr64.quo;
- num.hi = qr64.rem;
- num.lo = _cairo_uint64_lsl (num.lo, norm);
- }
- else
- {
- num.hi = _cairo_uint64_sub (num.hi, den.lo);
- q1 = _cairo_uint32_to_uint64 (1);
- }
- }
- qr64 = _cairo_uint128x64_normalized_divrem (num, den.lo);
- q0 = qr64.quo;
- r1 = _cairo_uint32_to_uint64 (0);
- r0 = _cairo_uint64_rsl (qr64.rem, norm);
- }
- else
- {
- if (_cairo_uint64_gt (den.hi, num.hi))
- {
- /* 00 = nn / DD */
- q0 = q1 = _cairo_uint32_to_uint64 (0);
- r0 = num.lo;
- r1 = num.hi;
- }
- else
- {
- /* 0q = NN / dd */
-
- norm = _cairo_leading_zeros64 (den.hi);
- if (norm == 0)
- {
- if (_cairo_uint64_gt (num.hi, den.hi) ||
- _cairo_uint64_ge (num.lo, den.lo))
- {
- q0 = _cairo_uint32_to_uint64 (1);
- num = _cairo_uint128_sub (num, den);
- }
- else
- q0 = _cairo_uint32_to_uint64 (0);
-
- q1 = _cairo_uint32_to_uint64 (0);
- r0 = num.lo;
- r1 = num.hi;
- }
- else
- {
- cairo_uint128_t num1;
- cairo_uint128_t part;
-
- num1 = _cairo_uint128_rsl (num, 64 - norm);
- den = _cairo_uint128_lsl (den, norm);
-
- qr64 = _cairo_uint128x64_normalized_divrem (num1, den.hi);
- part = _cairo_uint64x64_128_mul (qr64.quo, den.lo);
-
- q0 = qr64.quo;
-
- num.lo = _cairo_uint64_lsl (num.lo, norm);
- num.hi = qr64.rem;
-
- if (_cairo_uint128_gt (part, num))
- {
- q0 = _cairo_uint64_sub (q0, _cairo_uint32_to_uint64 (1));
- part = _cairo_uint128_sub (part, den);
- }
-
- q1 = _cairo_uint32_to_uint64 (0);
-
- num = _cairo_uint128_sub (num, part);
- num = _cairo_uint128_rsl (num, norm);
- r0 = num.lo;
- r1 = num.hi;
- }
- }
- }
- qr.quo.lo = q0;
- qr.quo.hi = q1;
- qr.rem.lo = r0;
- qr.rem.hi = r1;
- return qr;
-}
-
-cairo_int128_t
-_cairo_int128_negate (cairo_int128_t a)
-{
- a.lo = _cairo_uint64_not (a.lo);
- a.hi = _cairo_uint64_not (a.hi);
- return _cairo_uint128_add (a, _cairo_uint32_to_uint128 (1));
-}
-
-cairo_int128_t
-_cairo_int128_not (cairo_int128_t a)
-{
- a.lo = _cairo_uint64_not (a.lo);
- a.hi = _cairo_uint64_not (a.hi);
- return a;
-}
-
-#endif /* !HAVE_UINT128_T */
-
-cairo_quorem128_t
-_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den)
-{
- int num_neg = _cairo_int128_negative (num);
- int den_neg = _cairo_int128_negative (den);
- cairo_uquorem128_t uqr;
- cairo_quorem128_t qr;
-
- if (num_neg)
- num = _cairo_int128_negate (num);
- if (den_neg)
- den = _cairo_int128_negate (den);
- uqr = _cairo_uint128_divrem (num, den);
- if (num_neg)
- qr.rem = _cairo_int128_negate (uqr.rem);
- else
- qr.rem = uqr.rem;
- if (num_neg != den_neg)
- qr.quo = _cairo_int128_negate (uqr.quo);
- else
- qr.quo = uqr.quo;
- return qr;
-}
diff --git a/src/cairo_win32_font.c b/src/cairo_win32_font.c
deleted file mode 100644
index 02f0cffd6..000000000
--- a/src/cairo_win32_font.c
+++ /dev/null
@@ -1,1252 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2005 Red Hat, Inc
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is Red Hat, Inc.
- *
- * Contributor(s):
- */
-
-#include <string.h>
-#include <stdio.h>
-
-#include "cairo-win32-private.h"
-
-#ifndef SPI_GETFONTSMOOTHINGTYPE
-#define SPI_GETFONTSMOOTHINGTYPE 0x200a
-#endif
-#ifndef FE_FONTSMOOTHINGCLEARTYPE
-#define FE_FONTSMOOTHINGCLEARTYPE 2
-#endif
-#ifndef CLEARTYPE_QUALITY
-#define CLEARTYPE_QUALITY 5
-#endif
-
-const cairo_font_backend_t cairo_win32_font_backend;
-
-#define LOGICAL_SCALE 32
-
-typedef struct {
- cairo_font_t base;
-
- LOGFONTW logfont;
-
- BYTE quality;
-
- /* We do drawing and metrics computation in a "logical space" which
- * is similar to font space, except that it is scaled by a factor
- * of the (desired font size) * (LOGICAL_SCALE). The multiplication
- * by LOGICAL_SCALE allows for sub-pixel precision.
- */
- double logical_scale;
-
- /* The size we should actually request the font at from Windows; differs
- * from the logical_scale because it is quantized for orthogonal
- * transformations
- */
- double logical_size;
-
- /* Transformations from device <=> logical space
- */
- cairo_matrix_t logical_to_device;
- cairo_matrix_t device_to_logical;
-
- /* We special case combinations of 90-degree-rotations, scales and
- * flips ... that is transformations that take the axes to the
- * axes. If preserve_axes is true, then swap_axes/swap_x/swap_y
- * encode the 8 possibilities for orientation (4 rotation angles with
- * and without a flip), and scale_x, scale_y the scale components.
- */
- cairo_bool_t preserve_axes;
- cairo_bool_t swap_axes;
- cairo_bool_t swap_x;
- cairo_bool_t swap_y;
- double x_scale;
- double y_scale;
-
- /* The size of the design unit of the font
- */
- int em_square;
-
- HFONT scaled_font;
- HFONT unscaled_font;
-
-} cairo_win32_font_t;
-
-#define NEARLY_ZERO(d) (fabs(d) < (1. / 65536.))
-
-static void
-_compute_transform (cairo_win32_font_t *font,
- cairo_font_scale_t *sc)
-{
- if (NEARLY_ZERO (sc->matrix[0][1]) && NEARLY_ZERO (sc->matrix[1][0])) {
- font->preserve_axes = TRUE;
- font->x_scale = sc->matrix[0][0];
- font->swap_x = (sc->matrix[0][0] < 0);
- font->y_scale = sc->matrix[1][1];
- font->swap_y = (sc->matrix[1][1] < 0);
- font->swap_axes = FALSE;
-
- } else if (NEARLY_ZERO (sc->matrix[0][0]) && NEARLY_ZERO (sc->matrix[1][1])) {
- font->preserve_axes = TRUE;
- font->x_scale = sc->matrix[0][1];
- font->swap_x = (sc->matrix[0][1] < 0);
- font->y_scale = sc->matrix[1][0];
- font->swap_y = (sc->matrix[1][0] < 0);
- font->swap_axes = TRUE;
-
- } else {
- font->preserve_axes = FALSE;
- font->swap_x = font->swap_y = font->swap_axes = FALSE;
- }
-
- if (font->preserve_axes) {
- if (font->swap_x)
- font->x_scale = - font->x_scale;
- if (font->swap_y)
- font->y_scale = - font->y_scale;
-
- font->logical_scale = LOGICAL_SCALE * font->y_scale;
- font->logical_size = LOGICAL_SCALE * floor (font->y_scale + 0.5);
- }
-
- /* The font matrix has x and y "scale" components which we extract and
- * use as character scale values.
- */
- cairo_matrix_set_affine (&font->logical_to_device,
- sc->matrix[0][0],
- sc->matrix[0][1],
- sc->matrix[1][0],
- sc->matrix[1][1],
- 0, 0);
-
- if (!font->preserve_axes) {
- _cairo_matrix_compute_scale_factors (&font->logical_to_device,
- &font->x_scale, &font->y_scale,
- TRUE); /* XXX: Handle vertical text */
-
- font->logical_size = floor (LOGICAL_SCALE * font->y_scale + 0.5);
- font->logical_scale = LOGICAL_SCALE * font->y_scale;
- }
-
- cairo_matrix_scale (&font->logical_to_device,
- 1.0 / font->logical_scale, 1.0 / font->logical_scale);
-
- font->device_to_logical = font->logical_to_device;
- if (!CAIRO_OK (cairo_matrix_invert (&font->device_to_logical)))
- cairo_matrix_set_identity (&font->device_to_logical);
-}
-
-static BYTE
-_get_system_quality (void)
-{
- BOOL font_smoothing;
-
- if (!SystemParametersInfo (SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) {
- _cairo_win32_print_gdi_error ("_get_system_quality");
- return FALSE;
- }
-
- if (font_smoothing) {
- OSVERSIONINFO version_info;
-
- version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
-
- if (!GetVersionEx (&version_info)) {
- _cairo_win32_print_gdi_error ("_get_system_quality");
- return FALSE;
- }
-
- if (version_info.dwMajorVersion > 5 ||
- (version_info.dwMajorVersion == 5 &&
- version_info.dwMinorVersion >= 1)) { /* XP or newer */
- UINT smoothing_type;
-
- if (!SystemParametersInfo (SPI_GETFONTSMOOTHINGTYPE,
- 0, &smoothing_type, 0)) {
- _cairo_win32_print_gdi_error ("_get_system_quality");
- return FALSE;
- }
-
- if (smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
- return CLEARTYPE_QUALITY;
- }
-
- return ANTIALIASED_QUALITY;
- } else
- return DEFAULT_QUALITY;
-}
-
-static cairo_font_t *
-_win32_font_create (LOGFONTW *logfont,
- cairo_font_scale_t *scale)
-{
- cairo_win32_font_t *f;
-
- f = malloc (sizeof(cairo_win32_font_t));
- if (f == NULL)
- return NULL;
-
- f->logfont = *logfont;
- f->quality = _get_system_quality ();
- f->em_square = 0;
- f->scaled_font = NULL;
- f->unscaled_font = NULL;
-
- _compute_transform (f, scale);
-
- _cairo_font_init ((cairo_font_t *)f, scale, &cairo_win32_font_backend);
-
- return (cairo_font_t *)f;
-}
-
-static cairo_status_t
-_win32_font_set_world_transform (cairo_win32_font_t *font,
- HDC hdc)
-{
- XFORM xform;
-
- xform.eM11 = font->logical_to_device.m[0][0];
- xform.eM21 = font->logical_to_device.m[1][0];
- xform.eM12 = font->logical_to_device.m[0][1];
- xform.eM22 = font->logical_to_device.m[1][1];
- xform.eDx = font->logical_to_device.m[2][0];
- xform.eDy = font->logical_to_device.m[2][1];
-
- if (!SetWorldTransform (hdc, &xform))
- return _cairo_win32_print_gdi_error ("_win32_font_set_world_transform");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_win32_font_set_identity_transform (HDC hdc)
-{
- if (!ModifyWorldTransform (hdc, NULL, MWT_IDENTITY))
- return _cairo_win32_print_gdi_error ("_win32_font_set_identity_transform");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static HDC
-_get_global_font_dc (void)
-{
- static HDC hdc;
-
- if (!hdc) {
- hdc = CreateCompatibleDC (NULL);
- if (!hdc) {
- _cairo_win32_print_gdi_error ("_get_global_font_dc");
- return NULL;
- }
-
- if (!SetGraphicsMode (hdc, GM_ADVANCED)) {
- _cairo_win32_print_gdi_error ("_get_global_font_dc");
- DeleteDC (hdc);
- return NULL;
- }
- }
-
- return hdc;
-}
-
-static HFONT
-_win32_font_get_scaled_font (cairo_win32_font_t *font)
-{
- if (!font->scaled_font) {
- LOGFONTW logfont = font->logfont;
- logfont.lfHeight = font->logical_size;
- logfont.lfWidth = 0;
- logfont.lfEscapement = 0;
- logfont.lfOrientation = 0;
- logfont.lfQuality = font->quality;
-
- font->scaled_font = CreateFontIndirectW (&logfont);
- if (!font->scaled_font) {
- _cairo_win32_print_gdi_error ("_win32_font_get_scaled_font");
- return NULL;
- }
- }
-
- return font->scaled_font;
-}
-
-static HFONT
-_win32_font_get_unscaled_font (cairo_win32_font_t *font,
- HDC hdc)
-{
- if (!font->unscaled_font) {
- OUTLINETEXTMETRIC *otm;
- unsigned int otm_size;
- HFONT scaled_font;
- LOGFONTW logfont;
-
- scaled_font = _win32_font_get_scaled_font (font);
- if (!scaled_font)
- return NULL;
-
- if (!SelectObject (hdc, scaled_font)) {
- _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:SelectObject");
- return NULL;
- }
-
- otm_size = GetOutlineTextMetrics (hdc, 0, NULL);
- if (!otm_size) {
- _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:GetOutlineTextMetrics");
- return NULL;
- }
-
- otm = malloc (otm_size);
- if (!otm)
- return NULL;
-
- if (!GetOutlineTextMetrics (hdc, otm_size, otm)) {
- _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:GetOutlineTextMetrics");
- free (otm);
- return NULL;
- }
-
- font->em_square = otm->otmEMSquare;
- free (otm);
-
- logfont = font->logfont;
- logfont.lfHeight = font->em_square;
- logfont.lfWidth = 0;
- logfont.lfEscapement = 0;
- logfont.lfOrientation = 0;
- logfont.lfQuality = font->quality;
-
- font->unscaled_font = CreateFontIndirectW (&logfont);
- if (!font->unscaled_font) {
- _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:CreateIndirect");
- return NULL;
- }
- }
-
- return font->unscaled_font;
-}
-
-static cairo_status_t
-_cairo_win32_font_select_unscaled_font (cairo_font_t *font,
- HDC hdc)
-{
- cairo_status_t status;
- HFONT hfont;
- HFONT old_hfont = NULL;
-
- hfont = _win32_font_get_unscaled_font ((cairo_win32_font_t *)font, hdc);
- if (!hfont)
- return CAIRO_STATUS_NO_MEMORY;
-
- old_hfont = SelectObject (hdc, hfont);
- if (!old_hfont)
- return _cairo_win32_print_gdi_error ("_cairo_win32_font_select_unscaled_font");
-
- status = _win32_font_set_identity_transform (hdc);
- if (!CAIRO_OK (status)) {
- SelectObject (hdc, old_hfont);
- return status;
- }
-
- SetMapMode (hdc, MM_TEXT);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_win32_font_done_unscaled_font (cairo_font_t *font)
-{
-}
-
-/* implement the font backend interface */
-
-static cairo_status_t
-_cairo_win32_font_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight,
- cairo_font_scale_t *scale,
- cairo_font_t **font_out)
-{
- LOGFONTW logfont;
- cairo_font_t *font;
- uint16_t *face_name;
- int face_name_len;
- cairo_status_t status;
-
- status = _cairo_utf8_to_utf16 (family, -1, &face_name, &face_name_len);
- if (!CAIRO_OK (status))
- return status;
-
- if (face_name_len > LF_FACESIZE - 1) {
- free (face_name);
- return CAIRO_STATUS_INVALID_STRING;
- }
-
- memcpy (logfont.lfFaceName, face_name, sizeof (uint16_t) * (face_name_len + 1));
- free (face_name);
-
- logfont.lfHeight = 0; /* filled in later */
- logfont.lfWidth = 0; /* filled in later */
- logfont.lfEscapement = 0; /* filled in later */
- logfont.lfOrientation = 0; /* filled in later */
-
- switch (weight) {
- case CAIRO_FONT_WEIGHT_NORMAL:
- default:
- logfont.lfWeight = FW_NORMAL;
- break;
- case CAIRO_FONT_WEIGHT_BOLD:
- logfont.lfWeight = FW_BOLD;
- break;
- }
-
- switch (slant) {
- case CAIRO_FONT_SLANT_NORMAL:
- default:
- logfont.lfItalic = FALSE;
- break;
- case CAIRO_FONT_SLANT_ITALIC:
- case CAIRO_FONT_SLANT_OBLIQUE:
- logfont.lfItalic = TRUE;
- break;
- }
-
- logfont.lfUnderline = FALSE;
- logfont.lfStrikeOut = FALSE;
- /* The docs for LOGFONT discourage using this, since the
- * interpretation is locale-specific, but it's not clear what
- * would be a better alternative.
- */
- logfont.lfCharSet = DEFAULT_CHARSET;
- logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
- logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
- logfont.lfQuality = DEFAULT_QUALITY; /* filled in later */
- logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
-
- if (!logfont.lfFaceName)
- return CAIRO_STATUS_NO_MEMORY;
-
- font = _win32_font_create (&logfont, scale);
- if (!font)
- return CAIRO_STATUS_NO_MEMORY;
-
- *font_out = font;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_win32_font_destroy_font (void *abstract_font)
-{
- cairo_win32_font_t *font = abstract_font;
-
- if (font->scaled_font)
- DeleteObject (font->scaled_font);
-
- if (font->unscaled_font)
- DeleteObject (font->unscaled_font);
-
- free (font);
-}
-
-static void
-_cairo_win32_font_destroy_unscaled_font (void *abstract_font)
-{
-}
-
-static void
-_cairo_win32_font_get_glyph_cache_key (void *abstract_font,
- cairo_glyph_cache_key_t *key)
-{
-}
-
-static cairo_status_t
-_cairo_win32_font_text_to_glyphs (void *abstract_font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs)
-{
- cairo_win32_font_t *font = abstract_font;
- uint16_t *utf16;
- int n16;
- GCP_RESULTSW gcp_results;
- unsigned int buffer_size, i;
- WCHAR *glyph_indices = NULL;
- int *dx = NULL;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- double x_pos;
- HDC hdc = NULL;
-
- status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &n16);
- if (!CAIRO_OK (status))
- return status;
-
- gcp_results.lStructSize = sizeof (GCP_RESULTS);
- gcp_results.lpOutString = NULL;
- gcp_results.lpOrder = NULL;
- gcp_results.lpCaretPos = NULL;
- gcp_results.lpClass = NULL;
-
- buffer_size = MAX (n16 * 1.2, 16); /* Initially guess number of chars plus a few */
- if (buffer_size > INT_MAX) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL1;
- }
-
- hdc = _get_global_font_dc ();
- if (!hdc) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL1;
- }
-
- status = cairo_win32_font_select_font (&font->base, hdc);
- if (!CAIRO_OK (status))
- goto FAIL1;
-
- while (TRUE) {
- if (glyph_indices) {
- free (glyph_indices);
- glyph_indices = NULL;
- }
- if (dx) {
- free (dx);
- dx = NULL;
- }
-
- glyph_indices = malloc (sizeof (WCHAR) * buffer_size);
- dx = malloc (sizeof (int) * buffer_size);
- if (!glyph_indices || !dx) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL2;
- }
-
- gcp_results.nGlyphs = buffer_size;
- gcp_results.lpDx = dx;
- gcp_results.lpGlyphs = glyph_indices;
-
- if (!GetCharacterPlacementW (hdc, utf16, n16,
- 0,
- &gcp_results,
- GCP_DIACRITIC | GCP_LIGATE | GCP_GLYPHSHAPE | GCP_REORDER)) {
- status = _cairo_win32_print_gdi_error ("_cairo_win32_font_text_to_glyphs");
- goto FAIL2;
- }
-
- if (gcp_results.lpDx && gcp_results.lpGlyphs)
- break;
-
- /* Too small a buffer, try again */
-
- buffer_size *= 1.5;
- if (buffer_size > INT_MAX) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL2;
- }
- }
-
- *num_glyphs = gcp_results.nGlyphs;
- *glyphs = malloc (sizeof (cairo_glyph_t) * gcp_results.nGlyphs);
- if (!*glyphs) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL2;
- }
-
- x_pos = 0;
- for (i = 0; i < gcp_results.nGlyphs; i++) {
- (*glyphs)[i].index = glyph_indices[i];
- (*glyphs)[i].x = x_pos ;
- (*glyphs)[i].y = 0;
-
- x_pos += dx[i] / font->logical_scale;
- }
-
- FAIL2:
- if (glyph_indices)
- free (glyph_indices);
- if (dx)
- free (dx);
-
- cairo_win32_font_done_font (&font->base);
-
- FAIL1:
- free (utf16);
-
- return status;
-}
-
-static cairo_status_t
-_cairo_win32_font_font_extents (void *abstract_font,
- cairo_font_extents_t *extents)
-{
- cairo_win32_font_t *font = abstract_font;
- cairo_status_t status;
- TEXTMETRIC metrics;
- HDC hdc;
-
- hdc = _get_global_font_dc ();
- if (!hdc)
- return CAIRO_STATUS_NO_MEMORY;
-
- if (font->preserve_axes) {
- /* For 90-degree rotations (including 0), we get the metrics
- * from the GDI in logical space, then convert back to font space
- */
- status = cairo_win32_font_select_font (&font->base, hdc);
- if (!CAIRO_OK (status))
- return status;
- GetTextMetrics (hdc, &metrics);
- cairo_win32_font_done_font (&font->base);
-
- extents->ascent = metrics.tmAscent / font->logical_scale;
- extents->descent = metrics.tmDescent / font->logical_scale;
-
- extents->height = (metrics.tmHeight + metrics.tmExternalLeading) / font->logical_scale;
- extents->max_x_advance = metrics.tmMaxCharWidth / font->logical_scale;
- extents->max_y_advance = 0;
-
- } else {
- /* For all other transformations, we use the design metrics
- * of the font. The GDI results from GetTextMetrics() on a
- * transformed font are inexplicably large and we want to
- * avoid them.
- */
- status = _cairo_win32_font_select_unscaled_font (&font->base, hdc);
- if (!CAIRO_OK (status))
- return status;
- GetTextMetrics (hdc, &metrics);
- _cairo_win32_font_done_unscaled_font (&font->base);
-
- extents->ascent = (double)metrics.tmAscent / font->em_square;
- extents->descent = metrics.tmDescent * font->em_square;
- extents->height = (double)(metrics.tmHeight + metrics.tmExternalLeading) / font->em_square;
- extents->max_x_advance = (double)(metrics.tmMaxCharWidth) / font->em_square;
- extents->max_y_advance = 0;
-
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_win32_font_glyph_extents (void *abstract_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
-{
- cairo_win32_font_t *font = abstract_font;
- static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
- GLYPHMETRICS metrics;
- cairo_status_t status;
- HDC hdc;
-
- hdc = _get_global_font_dc ();
- if (!hdc)
- return CAIRO_STATUS_NO_MEMORY;
-
- /* We handle only the case num_glyphs == 1, glyphs[i].x == glyphs[0].y == 0.
- * This is all that the calling code triggers, and the backend interface
- * will eventually be changed to match
- */
- assert (num_glyphs == 1);
-
- if (font->preserve_axes) {
- /* If we aren't rotating / skewing the axes, then we get the metrics
- * from the GDI in device space and convert to font space.
- */
- status = cairo_win32_font_select_font (&font->base, hdc);
- if (!CAIRO_OK (status))
- return status;
- GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX,
- &metrics, 0, NULL, &matrix);
- cairo_win32_font_done_font (&font->base);
-
- if (font->swap_axes) {
- extents->x_bearing = - metrics.gmptGlyphOrigin.y / font->y_scale;
- extents->y_bearing = metrics.gmptGlyphOrigin.x / font->x_scale;
- extents->width = metrics.gmBlackBoxY / font->y_scale;
- extents->height = metrics.gmBlackBoxX / font->x_scale;
- extents->x_advance = metrics.gmCellIncY / font->x_scale;
- extents->y_advance = metrics.gmCellIncX / font->y_scale;
- } else {
- extents->x_bearing = metrics.gmptGlyphOrigin.x / font->x_scale;
- extents->y_bearing = - metrics.gmptGlyphOrigin.y / font->y_scale;
- extents->width = metrics.gmBlackBoxX / font->x_scale;
- extents->height = metrics.gmBlackBoxY / font->y_scale;
- extents->x_advance = metrics.gmCellIncX / font->x_scale;
- extents->y_advance = metrics.gmCellIncY / font->y_scale;
- }
-
- if (font->swap_x) {
- extents->x_bearing = (- extents->x_bearing - extents->width);
- extents->x_advance = - extents->x_advance;
- }
-
- if (font->swap_y) {
- extents->y_bearing = (- extents->y_bearing - extents->height);
- extents->y_advance = - extents->y_advance;
- }
-
- } else {
- /* For all other transformations, we use the design metrics
- * of the font.
- */
- status = _cairo_win32_font_select_unscaled_font (&font->base, hdc);
- GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX,
- &metrics, 0, NULL, &matrix);
- _cairo_win32_font_done_unscaled_font (&font->base);
-
- extents->x_bearing = (double)metrics.gmptGlyphOrigin.x / font->em_square;
- extents->y_bearing = (double)metrics.gmptGlyphOrigin.y / font->em_square;
- extents->width = (double)metrics.gmBlackBoxX / font->em_square;
- extents->height = (double)metrics.gmBlackBoxY / font->em_square;
- extents->x_advance = (double)metrics.gmCellIncX / font->em_square;
- extents->y_advance = (double)metrics.gmCellIncY / font->em_square;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-static cairo_status_t
-_cairo_win32_font_glyph_bbox (void *abstract_font,
- const cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox)
-{
- static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
- cairo_win32_font_t *font = abstract_font;
- int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
-
- if (num_glyphs > 0) {
- HDC hdc = _get_global_font_dc ();
- GLYPHMETRICS metrics;
- cairo_status_t status;
- int i;
-
- if (!hdc)
- return CAIRO_STATUS_NO_MEMORY;
-
- status = cairo_win32_font_select_font (&font->base, hdc);
- if (!CAIRO_OK (status))
- return status;
-
- for (i = 0; i < num_glyphs; i++) {
- int x = floor (0.5 + glyphs[i].x);
- int y = floor (0.5 + glyphs[i].y);
-
- GetGlyphOutlineW (hdc, glyphs[i].index, GGO_METRICS | GGO_GLYPH_INDEX,
- &metrics, 0, NULL, &matrix);
-
- if (i == 0 || x1 > x + metrics.gmptGlyphOrigin.x)
- x1 = x + metrics.gmptGlyphOrigin.x;
- if (i == 0 || y1 > y - metrics.gmptGlyphOrigin.y)
- y1 = y - metrics.gmptGlyphOrigin.y;
- if (i == 0 || x2 < x + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxX)
- x2 = x + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxX;
- if (i == 0 || y2 < y - metrics.gmptGlyphOrigin.y + metrics.gmBlackBoxY)
- y2 = y - metrics.gmptGlyphOrigin.y + metrics.gmBlackBoxY;
- }
-
- cairo_win32_font_done_font (&font->base);
- }
-
- bbox->p1.x = _cairo_fixed_from_int (x1);
- bbox->p1.y = _cairo_fixed_from_int (y1);
- bbox->p2.x = _cairo_fixed_from_int (x2);
- bbox->p2.y = _cairo_fixed_from_int (y2);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-typedef struct {
- cairo_win32_font_t *font;
- HDC hdc;
-
- cairo_array_t glyphs;
- cairo_array_t dx;
-
- int start_x;
- int last_x;
- int last_y;
-} cairo_glyph_state_t;
-
-static void
-_start_glyphs (cairo_glyph_state_t *state,
- cairo_win32_font_t *font,
- HDC hdc)
-{
- state->hdc = hdc;
- state->font = font;
-
- _cairo_array_init (&state->glyphs, sizeof (WCHAR));
- _cairo_array_init (&state->dx, sizeof (int));
-}
-
-static cairo_status_t
-_flush_glyphs (cairo_glyph_state_t *state)
-{
- int dx = 0;
- if (!_cairo_array_append (&state->dx, &dx, 1))
- return CAIRO_STATUS_NO_MEMORY;
-
- if (!ExtTextOutW (state->hdc,
- state->start_x, state->last_y,
- ETO_GLYPH_INDEX,
- NULL,
- (WCHAR *)state->glyphs.elements,
- state->glyphs.num_elements,
- (int *)state->dx.elements)) {
- return _cairo_win32_print_gdi_error ("_flush_glyphs");
- }
-
- _cairo_array_truncate (&state->glyphs, 0);
- _cairo_array_truncate (&state->dx, 0);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_add_glyph (cairo_glyph_state_t *state,
- unsigned long index,
- double device_x,
- double device_y)
-{
- double user_x = device_x;
- double user_y = device_y;
- WCHAR glyph_index = index;
- int logical_x, logical_y;
-
- cairo_matrix_transform_point (&state->font->device_to_logical, &user_x, &user_y);
-
- logical_x = floor (user_x + 0.5);
- logical_y = floor (user_y + 0.5);
-
- if (state->glyphs.num_elements > 0) {
- int dx;
-
- if (logical_y != state->last_y) {
- cairo_status_t status = _flush_glyphs (state);
- if (!CAIRO_OK (status))
- return status;
- state->start_x = logical_x;
- }
-
- dx = logical_x - state->last_x;
- if (!_cairo_array_append (&state->dx, &dx, 1))
- return CAIRO_STATUS_NO_MEMORY;
- } else {
- state->start_x = logical_x;
- }
-
- state->last_x = logical_x;
- state->last_y = logical_y;
-
- _cairo_array_append (&state->glyphs, &glyph_index, 1);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_finish_glyphs (cairo_glyph_state_t *state)
-{
- _flush_glyphs (state);
-
- _cairo_array_fini (&state->glyphs);
- _cairo_array_fini (&state->dx);
-}
-
-static cairo_status_t
-_draw_glyphs_on_surface (cairo_win32_surface_t *surface,
- cairo_win32_font_t *font,
- COLORREF color,
- int x_offset,
- int y_offset,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_glyph_state_t state;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- int i;
-
- if (!SaveDC (surface->dc))
- return _cairo_win32_print_gdi_error ("_draw_glyphs_on_surface:SaveDC");
-
- status = cairo_win32_font_select_font (&font->base, surface->dc);
- if (!CAIRO_OK (status))
- goto FAIL1;
-
- SetTextColor (surface->dc, color);
- SetTextAlign (surface->dc, TA_BASELINE | TA_LEFT);
- SetBkMode (surface->dc, TRANSPARENT);
-
- _start_glyphs (&state, font, surface->dc);
-
- for (i = 0; i < num_glyphs; i++) {
- status = _add_glyph (&state, glyphs[i].index,
- glyphs[i].x - x_offset, glyphs[i].y - y_offset);
- if (!CAIRO_OK (status))
- goto FAIL2;
- }
-
- FAIL2:
- _finish_glyphs (&state);
- cairo_win32_font_done_font (&font->base);
- FAIL1:
- RestoreDC (surface->dc, 1);
-
- return status;
-}
-
-/* Duplicate the green channel of a 4-channel mask in the alpha channel, then
- * invert the whole mask.
- */
-static void
-_compute_argb32_mask_alpha (cairo_win32_surface_t *mask_surface)
-{
- cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->image;
- int i, j;
-
- for (i = 0; i < image->height; i++) {
- uint32_t *p = (uint32_t *) (image->data + i * image->stride);
- for (j = 0; j < image->width; j++) {
- *p = 0xffffffff ^ (*p | ((*p & 0x0000ff00) << 16));
- p++;
- }
- }
-}
-
-/* Invert a mask
- */
-static void
-_invert_argb32_mask (cairo_win32_surface_t *mask_surface)
-{
- cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->image;
- int i, j;
-
- for (i = 0; i < image->height; i++) {
- uint32_t *p = (uint32_t *) (image->data + i * image->stride);
- for (j = 0; j < image->width; j++) {
- *p = 0xffffffff ^ *p;
- p++;
- }
- }
-}
-
-/* Compute an alpha-mask from a monochrome RGB24 image
- */
-static cairo_surface_t *
-_compute_a8_mask (cairo_win32_surface_t *mask_surface)
-{
- cairo_image_surface_t *image24 = (cairo_image_surface_t *)mask_surface->image;
- cairo_image_surface_t *image8;
- int i, j;
-
- image8 = (cairo_image_surface_t *)cairo_image_surface_create (CAIRO_FORMAT_A8,
- image24->width, image24->height);
- if (!image8)
- return NULL;
-
- for (i = 0; i < image24->height; i++) {
- uint32_t *p = (uint32_t *) (image24->data + i * image24->stride);
- unsigned char *q = (unsigned char *) (image8->data + i * image8->stride);
-
- for (j = 0; j < image24->width; j++) {
- *q = 255 - ((*p & 0x0000ff00) >> 8);
- p++;
- q++;
- }
- }
-
- return &image8->base;
-}
-
-static cairo_status_t
-_cairo_win32_font_show_glyphs (void *abstract_font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *generic_surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_win32_font_t *font = abstract_font;
- cairo_win32_surface_t *surface = (cairo_win32_surface_t *)generic_surface;
- cairo_status_t status;
-
- if (width == 0 || height == 0)
- return CAIRO_STATUS_SUCCESS;
-
- if (_cairo_surface_is_win32 (generic_surface) &&
- surface->format == CAIRO_FORMAT_RGB24 &&
- operator == CAIRO_OPERATOR_OVER &&
- pattern->type == CAIRO_PATTERN_SOLID &&
- _cairo_pattern_is_opaque (pattern)) {
-
- cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)pattern;
-
- /* When compositing OVER on a GDI-understood surface, with a
- * solid opaque color, we can just call ExtTextOut directly.
- */
- COLORREF new_color;
-
- new_color = RGB (((int)(0xffff * solid_pattern->red)) >> 8,
- ((int)(0xffff * solid_pattern->green)) >> 8,
- ((int)(0xffff * solid_pattern->blue)) >> 8);
-
- status = _draw_glyphs_on_surface (surface, font, new_color,
- 0, 0,
- glyphs, num_glyphs);
-
- return status;
- } else {
- /* Otherwise, we need to draw using software fallbacks. We create a mask
- * surface by drawing the the glyphs onto a DIB, black-on-white then
- * inverting. GDI outputs gamma-corrected images so inverted black-on-white
- * is very different from white-on-black. We favor the more common
- * case where the final output is dark-on-light.
- */
- cairo_win32_surface_t *tmp_surface;
- cairo_surface_t *mask_surface;
- cairo_surface_pattern_t mask;
- RECT r;
-
- tmp_surface = (cairo_win32_surface_t *)_cairo_win32_surface_create_dib (CAIRO_FORMAT_ARGB32, width, height);
- if (!tmp_surface)
- return CAIRO_STATUS_NO_MEMORY;
-
- r.left = 0;
- r.top = 0;
- r.right = width;
- r.bottom = height;
- FillRect (tmp_surface->dc, &r, GetStockObject (WHITE_BRUSH));
-
- _draw_glyphs_on_surface (tmp_surface, font, RGB (0, 0, 0),
- dest_x, dest_y,
- glyphs, num_glyphs);
-
- if (font->quality == CLEARTYPE_QUALITY) {
- /* For ClearType, we need a 4-channel mask. If we are compositing on
- * a surface with alpha, we need to compute the alpha channel of
- * the mask (we just copy the green channel). But for a destination
- * surface without alpha the alpha channel of the mask is ignored
- */
-
- if (surface->format != CAIRO_FORMAT_RGB24)
- _compute_argb32_mask_alpha (tmp_surface);
- else
- _invert_argb32_mask (tmp_surface);
-
- mask_surface = &tmp_surface->base;
-
- /* XXX: Hacky, should expose this in cairo_image_surface */
- pixman_image_set_component_alpha (((cairo_image_surface_t *)tmp_surface->image)->pixman_image, TRUE);
-
- } else {
- mask_surface = _compute_a8_mask (tmp_surface);
- cairo_surface_destroy (&tmp_surface->base);
- if (!mask_surface)
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- /* For operator == OVER, no-cleartype, a possible optimization here is to
- * draw onto an intermediate ARGB32 surface and alpha-blend that with the
- * destination
- */
- _cairo_pattern_init_for_surface (&mask, mask_surface);
-
- status = _cairo_surface_composite (operator, pattern,
- &mask.base,
- &surface->base,
- source_x, source_y,
- 0, 0,
- dest_x, dest_y,
- width, height);
-
- _cairo_pattern_fini (&mask.base);
-
- cairo_surface_destroy (mask_surface);
-
- return status;
- }
-}
-
-static cairo_status_t
-_cairo_win32_font_glyph_path (void *abstract_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path)
-{
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_win32_font_create_glyph (cairo_image_glyph_cache_entry_t *val)
-{
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-const cairo_font_backend_t cairo_win32_font_backend = {
- _cairo_win32_font_create,
- _cairo_win32_font_destroy_font,
- _cairo_win32_font_destroy_unscaled_font,
- _cairo_win32_font_font_extents,
- _cairo_win32_font_text_to_glyphs,
- _cairo_win32_font_glyph_extents,
- _cairo_win32_font_glyph_bbox,
- _cairo_win32_font_show_glyphs,
- _cairo_win32_font_glyph_path,
- _cairo_win32_font_get_glyph_cache_key,
- _cairo_win32_font_create_glyph
-};
-
-/* implement the platform-specific interface */
-
-/**
- * cairo_win32_font_create_for_logfontw:
- * @logfont: A #LOGFONTW structure specifying the font to use.
- * The lfHeight, lfWidth, lfOrientation and lfEscapement
- * fields of this structure are ignored; information from
- * @scale will be used instead.
- * @scale: The scale at which this font will be used. The
- * scale is given by multiplying the font matrix (see
- * cairo_transform_font()) by the current transformation matrix.
- * The translation elements of the resulting matrix are ignored.
- *
- * Creates a new font for the Win32 font backend based on a
- * #LOGFONT. This font can then be used with
- * cairo_set_font(), cairo_font_glyph_extents(), or FreeType backend
- * specific functions like cairo_win32_font_select_font().
- *
- * Return value: a newly created #cairo_font_t. Free with
- * cairo_font_destroy() when you are done using it.
- **/
-cairo_font_t *
-cairo_win32_font_create_for_logfontw (LOGFONTW *logfont,
- cairo_matrix_t *scale)
-{
- cairo_font_scale_t sc;
-
- cairo_matrix_get_affine (scale,
- &sc.matrix[0][0], &sc.matrix[0][1],
- &sc.matrix[1][0], &sc.matrix[1][1],
- NULL, NULL);
-
- return _win32_font_create (logfont, &sc);
-}
-
-/**
- * cairo_win32_font_select_font:
- * @font: A #cairo_font_t from the Win32 font backend. Such an
- * object can be created with cairo_win32_font_create_for_logfontw().
- * @hdc: a device context
- *
- * Selects the font into the given device context and changes the
- * map mode and world transformation of the device context to match
- * that of the font. This function is intended for use when using
- * layout APIs such as Uniscribe to do text layout with the
- * Cairo font. After finishing using the device context, you must call
- * cairo_win32_font_done_font() to release any resources allocated
- * by this function.
- *
- * See cairo_win32_font_get_scale_factor() for converting logical
- * coordinates from the device context to font space.
- *
- * Normally, calls to SaveDC() and RestoreDC() would be made around
- * the use of this function to preserve the original graphics state.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if the operation succeeded.
- * otherwise an error such as %CAIRO_STATUS_NO_MEMORY and
- * the device context is unchanged.
- **/
-cairo_status_t
-cairo_win32_font_select_font (cairo_font_t *font,
- HDC hdc)
-{
- cairo_status_t status;
- HFONT hfont;
- HFONT old_hfont = NULL;
- int old_mode;
-
- hfont = _win32_font_get_scaled_font ((cairo_win32_font_t *)font);
- if (!hfont)
- return CAIRO_STATUS_NO_MEMORY;
-
- old_hfont = SelectObject (hdc, hfont);
- if (!old_hfont)
- return _cairo_win32_print_gdi_error ("cairo_win32_font_select_font");
-
- old_mode = SetGraphicsMode (hdc, GM_ADVANCED);
- if (!old_mode) {
- status = _cairo_win32_print_gdi_error ("cairo_win32_font_select_font");
- SelectObject (hdc, old_hfont);
- return status;
- }
-
- status = _win32_font_set_world_transform ((cairo_win32_font_t *)font, hdc);
- if (!CAIRO_OK (status)) {
- SetGraphicsMode (hdc, old_mode);
- SelectObject (hdc, old_hfont);
- return status;
- }
-
- SetMapMode (hdc, MM_TEXT);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/**
- * cairo_win32_font_done_font:
- * @font: A #cairo_font_t from the Win32 font backend.
- *
- * Releases any resources allocated by cairo_win32_font_select_font()
- **/
-void
-cairo_win32_font_done_font (cairo_font_t *font)
-{
-}
-
-/**
- * cairo_win32_font_get_scale_factor:
- * @font: a #cairo_font_t from the Win32 font backend
- *
- * Gets a scale factor between logical coordinates in the coordinate
- * space used by cairo_win32_font_select_font() and font space coordinates.
- *
- * Return value: factor to multiply logical units by to get font space
- * coordinates.
- **/
-double
-cairo_win32_font_get_scale_factor (cairo_font_t *font)
-{
- return 1. / ((cairo_win32_font_t *)font)->logical_scale;
-}
diff --git a/src/cairo_win32_surface.c b/src/cairo_win32_surface.c
deleted file mode 100644
index dcfe6d044..000000000
--- a/src/cairo_win32_surface.c
+++ /dev/null
@@ -1,931 +0,0 @@
-/* Cairo - a vector graphics library with display and print output
- *
- * Copyright © 2005 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is Red Hat, Inc.
- *
- * Contributor(s):
- * Owen Taylor <otaylor@redhat.com>
- */
-
-#include <stdio.h>
-
-#include "cairo-win32-private.h"
-
-static const cairo_surface_backend_t cairo_win32_surface_backend;
-
-/**
- * _cairo_win32_print_gdi_error:
- * @context: context string to display along with the error
- *
- * Helper function to dump out a human readable form of the
- * current error code.
- *
- * Return value: A Cairo status code for the error code
- **/
-cairo_status_t
-_cairo_win32_print_gdi_error (const char *context)
-{
- void *lpMsgBuf;
- DWORD last_error = GetLastError ();
-
- if (!FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- last_error,
- MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &lpMsgBuf,
- 0, NULL)) {
- fprintf (stderr, "%s: Unknown GDI error", context);
- } else {
- fprintf (stderr, "%s: %s", context, (char *)lpMsgBuf);
-
- LocalFree (lpMsgBuf);
- }
-
- /* We should switch off of last_status, but we'd either return
- * CAIRO_STATUS_NO_MEMORY or CAIRO_STATUS_UNKNOWN_ERROR and there
- * is no CAIRO_STATUS_UNKNOWN_ERROR.
- */
-
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-void
-cairo_set_target_win32 (cairo_t *cr,
- HDC hdc)
-{
- cairo_surface_t *surface;
-
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
-
- surface = cairo_win32_surface_create (hdc);
- if (surface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface (cr, surface);
-
- /* cairo_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy (surface);
-}
-
-static cairo_status_t
-_create_dc_and_bitmap (cairo_win32_surface_t *surface,
- HDC original_dc,
- cairo_format_t format,
- int width,
- int height,
- char **bits_out,
- int *rowstride_out)
-{
- cairo_status_t status;
-
- BITMAPINFO *bitmap_info = NULL;
- struct {
- BITMAPINFOHEADER bmiHeader;
- RGBQUAD bmiColors[2];
- } bmi_stack;
- void *bits;
-
- int num_palette = 0; /* Quiet GCC */
- int i;
-
- surface->dc = NULL;
- surface->bitmap = NULL;
-
- switch (format) {
- case CAIRO_FORMAT_ARGB32:
- case CAIRO_FORMAT_RGB24:
- num_palette = 0;
- break;
-
- case CAIRO_FORMAT_A8:
- num_palette = 256;
- break;
-
- case CAIRO_FORMAT_A1:
- num_palette = 2;
- break;
- }
-
- if (num_palette > 2) {
- bitmap_info = malloc (sizeof (BITMAPINFOHEADER) + num_palette * sizeof (RGBQUAD));
- if (!bitmap_info)
- return CAIRO_STATUS_NO_MEMORY;
- } else {
- bitmap_info = (BITMAPINFO *)&bmi_stack;
- }
-
- bitmap_info->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
- bitmap_info->bmiHeader.biWidth = width;
- bitmap_info->bmiHeader.biHeight = - height; /* top-down */
- bitmap_info->bmiHeader.biSizeImage = 0;
- bitmap_info->bmiHeader.biXPelsPerMeter = 72. / 0.0254; /* unused here */
- bitmap_info->bmiHeader.biYPelsPerMeter = 72. / 0.0254; /* unused here */
- bitmap_info->bmiHeader.biPlanes = 1;
-
- switch (format) {
- case CAIRO_FORMAT_ARGB32:
- case CAIRO_FORMAT_RGB24:
- bitmap_info->bmiHeader.biBitCount = 32;
- bitmap_info->bmiHeader.biCompression = BI_RGB;
- bitmap_info->bmiHeader.biClrUsed = 0; /* unused */
- bitmap_info->bmiHeader.biClrImportant = 0;
- break;
-
- case CAIRO_FORMAT_A8:
- bitmap_info->bmiHeader.biBitCount = 8;
- bitmap_info->bmiHeader.biCompression = BI_RGB;
- bitmap_info->bmiHeader.biClrUsed = 256;
- bitmap_info->bmiHeader.biClrImportant = 0;
-
- for (i = 0; i < 256; i++) {
- bitmap_info->bmiColors[i].rgbBlue = i;
- bitmap_info->bmiColors[i].rgbGreen = i;
- bitmap_info->bmiColors[i].rgbRed = i;
- bitmap_info->bmiColors[i].rgbReserved = 0;
- }
-
- break;
-
- case CAIRO_FORMAT_A1:
- bitmap_info->bmiHeader.biBitCount = 1;
- bitmap_info->bmiHeader.biCompression = BI_RGB;
- bitmap_info->bmiHeader.biClrUsed = 2;
- bitmap_info->bmiHeader.biClrImportant = 0;
-
- for (i = 0; i < 2; i++) {
- bitmap_info->bmiColors[i].rgbBlue = i * 255;
- bitmap_info->bmiColors[i].rgbGreen = i * 255;
- bitmap_info->bmiColors[i].rgbRed = i * 255;
- bitmap_info->bmiColors[i].rgbReserved = 0;
- break;
- }
- }
-
- surface->dc = CreateCompatibleDC (original_dc);
- if (!surface->dc)
- goto FAIL;
-
- surface->bitmap = CreateDIBSection (surface->dc,
- bitmap_info,
- DIB_RGB_COLORS,
- &bits,
- NULL, 0);
- if (!surface->bitmap)
- goto FAIL;
-
- surface->saved_dc_bitmap = SelectObject (surface->dc,
- surface->bitmap);
- if (!surface->saved_dc_bitmap)
- goto FAIL;
-
- if (bitmap_info && num_palette > 2)
- free (bitmap_info);
-
- if (bits_out)
- *bits_out = bits;
-
- if (rowstride_out) {
- /* Windows bitmaps are padded to 16-bit (word) boundaries */
- switch (format) {
- case CAIRO_FORMAT_ARGB32:
- case CAIRO_FORMAT_RGB24:
- *rowstride_out = 4 * width;
- break;
-
- case CAIRO_FORMAT_A8:
- *rowstride_out = (width + 1) & -2;
- break;
-
- case CAIRO_FORMAT_A1:
- *rowstride_out = ((width + 15) & -16) / 8;
- break;
- }
- }
-
- return CAIRO_STATUS_SUCCESS;
-
- FAIL:
- status = _cairo_win32_print_gdi_error ("_create_dc_and_bitmap");
-
- if (bitmap_info && num_palette > 2)
- free (bitmap_info);
-
- if (surface->saved_dc_bitmap) {
- SelectObject (surface->dc, surface->saved_dc_bitmap);
- surface->saved_dc_bitmap = NULL;
- }
-
- if (surface->bitmap) {
- DeleteObject (surface->bitmap);
- surface->bitmap = NULL;
- }
-
- if (surface->dc) {
- DeleteDC (surface->dc);
- surface->dc = NULL;
- }
-
- return status;
-}
-
-static cairo_surface_t *
-_cairo_win32_surface_create_for_dc (HDC original_dc,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- cairo_win32_surface_t *surface;
- char *bits;
- int rowstride;
-
- surface = malloc (sizeof (cairo_win32_surface_t));
- if (!surface)
- return NULL;
-
- if (_create_dc_and_bitmap (surface, original_dc, format,
- width, height,
- &bits, &rowstride) != CAIRO_STATUS_SUCCESS)
- goto FAIL;
-
- surface->image = cairo_image_surface_create_for_data (bits, format,
- width, height, rowstride);
- if (!surface->image)
- goto FAIL;
-
- surface->format = format;
-
- surface->clip_rect.x = 0;
- surface->clip_rect.y = 0;
- surface->clip_rect.width = width;
- surface->clip_rect.height = height;
-
- surface->set_clip = 0;
- surface->saved_clip = NULL;
-
- _cairo_surface_init (&surface->base, &cairo_win32_surface_backend);
-
- return (cairo_surface_t *)surface;
-
- FAIL:
- if (surface->bitmap) {
- SelectObject (surface->dc, surface->saved_dc_bitmap);
- DeleteObject (surface->bitmap);
- DeleteDC (surface->dc);
- }
- if (surface)
- free (surface);
-
- return NULL;
-
-}
-
-static cairo_surface_t *
-_cairo_win32_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- cairo_win32_surface_t *src = abstract_src;
-
- return _cairo_win32_surface_create_for_dc (src->dc, format, drawable,
- width, height);
-}
-
-/**
- * _cairo_win32_surface_create_dib:
- * @format: format of pixels in the surface to create
- * @width: width of the surface, in pixels
- * @height: height of the surface, in pixels
- *
- * Creates a device-independent-bitmap surface not associated with
- * any particular existing surface or device context. The created
- * bitmap will be unititialized.
- *
- * Return value: the newly created surface, or %NULL if it couldn't
- * be created (probably because of lack of memory)
- **/
-cairo_surface_t *
-_cairo_win32_surface_create_dib (cairo_format_t format,
- int width,
- int height)
-{
- return _cairo_win32_surface_create_for_dc (NULL, format, TRUE,
- width, height);
-}
-
-static void
-_cairo_win32_surface_destroy (void *abstract_surface)
-{
- cairo_win32_surface_t *surface = abstract_surface;
-
- if (surface->image)
- cairo_surface_destroy (surface->image);
-
- if (surface->saved_clip)
- DeleteObject (surface->saved_clip);
-
- /* If we created the Bitmap and DC, destroy them */
- if (surface->bitmap) {
- SelectObject (surface->dc, surface->saved_dc_bitmap);
- DeleteObject (surface->bitmap);
- DeleteDC (surface->dc);
- }
-
- free (surface);
-}
-
-static double
-_cairo_win32_surface_pixels_per_inch (void *abstract_surface)
-{
- /* XXX: We should really get this value from somewhere */
- return 96.0;
-}
-
-static cairo_status_t
-_cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface,
- int x,
- int y,
- int width,
- int height,
- cairo_win32_surface_t **local_out)
-{
- cairo_win32_surface_t *local;
- cairo_status_t status;
-
- local =
- (cairo_win32_surface_t *) _cairo_win32_surface_create_similar (surface,
- surface->format,
- 0,
- width, height);
- if (!local)
- return CAIRO_STATUS_NO_MEMORY;
-
- if (!BitBlt (local->dc,
- 0, 0,
- width, height,
- surface->dc,
- x, y,
- SRCCOPY))
- goto FAIL;
-
- *local_out = local;
-
- return CAIRO_STATUS_SUCCESS;
-
- FAIL:
- status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_get_subimage");
-
- if (local)
- cairo_surface_destroy (&local->base);
-
- return status;
-}
-
-static cairo_status_t
-_cairo_win32_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_win32_surface_t *surface = abstract_surface;
- cairo_win32_surface_t *local = NULL;
- cairo_status_t status;
-
- if (surface->image) {
- *image_out = (cairo_image_surface_t *)surface->image;
- *image_extra = NULL;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- status = _cairo_win32_surface_get_subimage (abstract_surface, 0, 0,
- surface->clip_rect.width,
- surface->clip_rect.height, &local);
- if (CAIRO_OK (status)) {
- cairo_surface_set_filter (&local->base, surface->base.filter);
- cairo_surface_set_matrix (&local->base, &surface->base.matrix);
- cairo_surface_set_repeat (&local->base, surface->base.repeat);
-
- *image_out = (cairo_image_surface_t *)local->image;
- *image_extra = local;
- }
-
- return status;
-}
-
-static void
-_cairo_win32_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
- cairo_win32_surface_t *local = image_extra;
-
- if (local)
- cairo_surface_destroy ((cairo_surface_t *)local);
-}
-
-static cairo_status_t
-_cairo_win32_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect,
- void **image_extra)
-{
- cairo_win32_surface_t *surface = abstract_surface;
- cairo_win32_surface_t *local = NULL;
- cairo_status_t status;
- RECT clip_box;
- int x1, y1, x2, y2;
-
- if (surface->image) {
- image_rect->x = 0;
- image_rect->y = 0;
- image_rect->width = surface->clip_rect.width;
- image_rect->height = surface->clip_rect.height;
-
- *image_out = (cairo_image_surface_t *)surface->image;
- *image_extra = NULL;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (GetClipBox (surface->dc, &clip_box) == ERROR)
- return _cairo_win32_print_gdi_error ("_cairo_win3_surface_acquire_dest_image");
-
- x1 = clip_box.left;
- x2 = clip_box.right;
- y1 = clip_box.top;
- y2 = clip_box.bottom;
-
- if (interest_rect->x > x1)
- x1 = interest_rect->x;
- if (interest_rect->y > y1)
- y1 = interest_rect->y;
- if (interest_rect->x + interest_rect->width < x2)
- x2 = interest_rect->x + interest_rect->width;
- if (interest_rect->y + interest_rect->height < y2)
- y2 = interest_rect->y + interest_rect->height;
-
- if (x1 >= x2 || y1 >= y2) {
- *image_out = NULL;
- *image_extra = NULL;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- status = _cairo_win32_surface_get_subimage (abstract_surface,
- x1, y1, x2 - x1, y2 - y1,
- &local);
- if (CAIRO_OK (status)) {
- *image_out = (cairo_image_surface_t *)local->image;
- *image_extra = local;
-
- image_rect->x = x1;
- image_rect->y = y1;
- image_rect->width = x2 - x1;
- image_rect->height = y2 - y1;
- }
-
- return status;
-}
-
-static void
-_cairo_win32_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
- cairo_win32_surface_t *surface = abstract_surface;
- cairo_win32_surface_t *local = image_extra;
-
- if (!local)
- return;
-
- if (!BitBlt (surface->dc,
- image_rect->x, image_rect->y,
- image_rect->width, image_rect->height,
- local->dc,
- 0, 0,
- SRCCOPY))
- _cairo_win32_print_gdi_error ("_cairo_win32_surface_release_dest_image");
-
- cairo_surface_destroy ((cairo_surface_t *)local);
-}
-
-static cairo_status_t
-_cairo_win32_surface_clone_similar (void *surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_composite (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_pattern_t *mask_pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- cairo_win32_surface_t *dst = abstract_dst;
- cairo_win32_surface_t *src;
- cairo_surface_pattern_t *src_surface_pattern;
- int alpha;
- int integer_transform;
- int itx, ity;
-
- if (pattern->type != CAIRO_PATTERN_SURFACE ||
- pattern->extend != CAIRO_EXTEND_NONE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (mask_pattern) {
- /* FIXME: When we fully support RENDER style 4-channel
- * masks we need to check r/g/b != 1.0.
- */
- if (mask_pattern->type != CAIRO_PATTERN_SOLID)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- alpha = (int)(0xffff * pattern->alpha * mask_pattern->alpha) >> 8;
- } else {
- alpha = (int)(0xffff * pattern->alpha) >> 8;
- }
-
- src_surface_pattern = (cairo_surface_pattern_t *)pattern;
- src = (cairo_win32_surface_t *)src_surface_pattern->surface;
-
- if (src->base.backend != dst->base.backend)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- integer_transform = _cairo_matrix_is_integer_translation (&pattern->matrix, &itx, &ity);
- if (!integer_transform)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (alpha == 255 &&
- src->format == dst->format &&
- (operator == CAIRO_OPERATOR_SRC ||
- (src->format == CAIRO_FORMAT_RGB24 && operator == CAIRO_OPERATOR_OVER))) {
-
- if (!BitBlt (dst->dc,
- dst_x, dst_y,
- width, height,
- src->dc,
- src_x + itx, src_y + ity,
- SRCCOPY))
- return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite");
-
- return CAIRO_STATUS_SUCCESS;
-
- } else if (integer_transform &&
- (src->format == CAIRO_FORMAT_RGB24 || src->format == CAIRO_FORMAT_ARGB32) &&
- dst->format == CAIRO_FORMAT_RGB24 &&
- !src->base.repeat &&
- operator == CAIRO_OPERATOR_OVER) {
-
- BLENDFUNCTION blend_function;
-
- blend_function.BlendOp = AC_SRC_OVER;
- blend_function.BlendFlags = 0;
- blend_function.SourceConstantAlpha = alpha;
- blend_function.AlphaFormat = src->format == CAIRO_FORMAT_ARGB32 ? AC_SRC_ALPHA : 0;
-
- if (!AlphaBlend (dst->dc,
- dst_x, dst_y,
- width, height,
- src->dc,
- src_x + itx, src_y + ity,
- width, height,
- blend_function))
- return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite");
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_fill_rectangles (void *abstract_surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- cairo_win32_surface_t *surface = abstract_surface;
- cairo_status_t status;
- COLORREF new_color;
- HBRUSH new_brush;
- int i;
-
- /* If we have a local image, use the fallback code; it will be as fast
- * as calling out to GDI.
- */
- if (surface->image)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* We could support possibly support more operators for color->alpha = 0xffff.
- * for CAIRO_OPERATOR_SRC, alpha doesn't matter since we know the destination
- * image doesn't have alpha. (surface->pixman_image is non-NULL for all
- * surfaces with alpha.)
- */
- if (operator != CAIRO_OPERATOR_SRC)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8);
-
- new_brush = CreateSolidBrush (new_color);
- if (!new_brush)
- return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
-
- for (i = 0; i < num_rects; i++) {
- RECT rect;
-
- rect.left = rects[i].x;
- rect.top = rects[i].y;
- rect.right = rects[i].x + rects[i].width;
- rect.bottom = rects[i].y + rects[i].height;
-
- if (!FillRect (surface->dc, &rect, new_brush))
- goto FAIL;
- }
-
- DeleteObject (new_brush);
-
- return CAIRO_STATUS_SUCCESS;
-
- FAIL:
- status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
-
- DeleteObject (new_brush);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_copy_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- cairo_win32_surface_t *surface = abstract_surface;
- cairo_status_t status;
-
- /* If we are in-memory, then we set the clip on the image surface
- * as well as on the underlying GDI surface.
- */
- if (surface->image)
- _cairo_surface_set_clip_region (surface->image, region);
-
- /* The semantics we want is that any clip set by Cairo combines
- * is intersected with the clip on device context that the
- * surface was created for. To implement this, we need to
- * save the original clip when first setting a clip on surface.
- */
-
- if (region == NULL) {
- /* Clear any clip set by Cairo, return to the original */
-
- if (surface->set_clip) {
- if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR)
- return _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
-
- if (surface->saved_clip) {
- DeleteObject (surface->saved_clip);
- surface->saved_clip = NULL;
- }
-
- surface->set_clip = 0;
- }
-
-
- return CAIRO_STATUS_SUCCESS;
-
- } else {
- pixman_box16_t *boxes = pixman_region_rects (region);
- int num_boxes = pixman_region_num_rects (region);
- pixman_box16_t *extents = pixman_region_extents (region);
- RGNDATA *data;
- size_t data_size;
- RECT *rects;
- int i;
- HRGN gdi_region;
-
- /* Create a GDI region for the cairo region */
-
- data_size = sizeof (RGNDATAHEADER) + num_boxes * sizeof (RECT);
- data = malloc (data_size);
- if (!data)
- return CAIRO_STATUS_NO_MEMORY;
- rects = (RECT *)data->Buffer;
-
- data->rdh.dwSize = sizeof (RGNDATAHEADER);
- data->rdh.iType = RDH_RECTANGLES;
- data->rdh.nCount = num_boxes;
- data->rdh.nRgnSize = num_boxes * sizeof (RECT);
- data->rdh.rcBound.left = extents->x1;
- data->rdh.rcBound.top = extents->y1;
- data->rdh.rcBound.right = extents->x2;
- data->rdh.rcBound.bottom = extents->y2;
-
- for (i = 0; i < num_boxes; i++) {
- rects[i].left = boxes[i].x1;
- rects[i].top = boxes[i].y1;
- rects[i].right = boxes[i].x2;
- rects[i].bottom = boxes[i].y2;
- }
-
- gdi_region = ExtCreateRegion (NULL, data_size, data);
- free (data);
-
- if (!gdi_region)
- return CAIRO_STATUS_NO_MEMORY;
-
- if (surface->set_clip) {
- /* Combine the new region with the original clip */
-
- if (surface->saved_clip) {
- if (CombineRgn (gdi_region, gdi_region, surface->saved_clip, RGN_AND) == ERROR)
- goto FAIL;
- }
-
- if (SelectClipRgn (surface->dc, gdi_region) == ERROR)
- goto FAIL;
-
- } else {
- /* Save the the current region */
-
- surface->saved_clip = CreateRectRgn (0, 0, 0, 0);
- if (!surface->saved_clip) {
- goto FAIL; }
-
- /* This function has no error return! */
- if (GetClipRgn (surface->dc, surface->saved_clip) == 0) { /* No clip */
- DeleteObject (surface->saved_clip);
- surface->saved_clip = NULL;
- }
-
- if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR)
- goto FAIL;
-
- surface->set_clip = 1;
- }
-
- DeleteObject (gdi_region);
- return CAIRO_STATUS_SUCCESS;
-
- FAIL:
- status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
- DeleteObject (gdi_region);
- return status;
- }
-}
-
-static cairo_status_t
-_cairo_win32_surface_show_glyphs (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-cairo_surface_t *
-cairo_win32_surface_create (HDC hdc)
-{
- cairo_win32_surface_t *surface;
- RECT rect;
-
- /* Try to figure out the drawing bounds for the Device context
- */
- if (GetClipBox (hdc, &rect) == ERROR) {
- _cairo_win32_print_gdi_error ("cairo_win32_surface_create");
- return NULL;
- }
-
- surface = malloc (sizeof (cairo_win32_surface_t));
- if (!surface)
- return NULL;
-
- surface->image = NULL;
- surface->format = CAIRO_FORMAT_RGB24;
-
- surface->dc = hdc;
- surface->bitmap = NULL;
-
- surface->clip_rect.x = rect.left;
- surface->clip_rect.y = rect.top;
- surface->clip_rect.width = rect.right - rect.left;
- surface->clip_rect.height = rect.bottom - rect.top;
-
- surface->set_clip = 0;
- surface->saved_clip = NULL;
-
- _cairo_surface_init (&surface->base, &cairo_win32_surface_backend);
-
- return (cairo_surface_t *)surface;
-}
-
-/**
- * _cairo_surface_is_win32:
- * @surface: a #cairo_surface_t
- *
- * Checks if a surface is an #cairo_win32_surface_t
- *
- * Return value: True if the surface is an win32 surface
- **/
-int
-_cairo_surface_is_win32 (cairo_surface_t *surface)
-{
- return surface->backend == &cairo_win32_surface_backend;
-}
-
-static const cairo_surface_backend_t cairo_win32_surface_backend = {
- _cairo_win32_surface_create_similar,
- _cairo_win32_surface_destroy,
- _cairo_win32_surface_pixels_per_inch,
- _cairo_win32_surface_acquire_source_image,
- _cairo_win32_surface_release_source_image,
- _cairo_win32_surface_acquire_dest_image,
- _cairo_win32_surface_release_dest_image,
- _cairo_win32_surface_clone_similar,
- _cairo_win32_surface_composite,
- _cairo_win32_surface_fill_rectangles,
- _cairo_win32_surface_composite_trapezoids,
- _cairo_win32_surface_copy_page,
- _cairo_win32_surface_show_page,
- _cairo_win32_surface_set_clip_region,
- _cairo_win32_surface_show_glyphs
-};
diff --git a/src/cairo_xcb_surface.c b/src/cairo_xcb_surface.c
deleted file mode 100644
index 0694b77a2..000000000
--- a/src/cairo_xcb_surface.c
+++ /dev/null
@@ -1,978 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2002 University of Southern California
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#include "cairoint.h"
-#include "cairo-xcb.h"
-
-cairo_surface_t *
-cairo_xcb_surface_create (XCBConnection *dpy,
- XCBDRAWABLE drawable,
- XCBVISUALTYPE *visual,
- cairo_format_t format);
-
-#define AllPlanes ((unsigned long)~0L)
-
-static XCBRenderPICTFORMAT
-format_from_visual(XCBConnection *c, XCBVISUALID visual)
-{
- static const XCBRenderPICTFORMAT nil = { 0 };
- XCBRenderQueryPictFormatsRep *r;
- XCBRenderPICTSCREENIter si;
- XCBRenderPICTDEPTHIter di;
- XCBRenderPICTVISUALIter vi;
-
- r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0);
- if(!r)
- return nil;
-
- for(si = XCBRenderQueryPictFormatsScreensIter(r); si.rem; XCBRenderPICTSCREENNext(&si))
- for(di = XCBRenderPICTSCREENDepthsIter(si.data); di.rem; XCBRenderPICTDEPTHNext(&di))
- for(vi = XCBRenderPICTDEPTHVisualsIter(di.data); vi.rem; XCBRenderPICTVISUALNext(&vi))
- if(vi.data->visual.id == visual.id)
- {
- XCBRenderPICTFORMAT ret = vi.data->format;
- free(r);
- return ret;
- }
-
- return nil;
-}
-
-static XCBRenderPICTFORMAT
-format_from_cairo(XCBConnection *c, cairo_format_t fmt)
-{
- XCBRenderPICTFORMAT ret = { 0 };
- struct tmpl_t {
- XCBRenderDIRECTFORMAT direct;
- CARD8 depth;
- };
- static const struct tmpl_t templates[] = {
- /* CAIRO_FORMAT_ARGB32 */
- {
- {
- 16, 0xff,
- 8, 0xff,
- 0, 0xff,
- 24, 0xff
- },
- 32
- },
- /* CAIRO_FORMAT_RGB24 */
- {
- {
- 16, 0xff,
- 8, 0xff,
- 0, 0xff,
- 0, 0x00
- },
- 24
- },
- /* CAIRO_FORMAT_A8 */
- {
- {
- 0, 0x00,
- 0, 0x00,
- 0, 0x00,
- 0, 0xff
- },
- 8
- },
- /* CAIRO_FORMAT_A1 */
- {
- {
- 0, 0x00,
- 0, 0x00,
- 0, 0x00,
- 0, 0x01
- },
- 1
- },
- };
- const struct tmpl_t *tmpl;
- XCBRenderQueryPictFormatsRep *r;
- XCBRenderPICTFORMINFOIter fi;
-
- if(fmt < 0 || fmt >= (sizeof(templates) / sizeof(*templates)))
- return ret;
- tmpl = templates + fmt;
-
- r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0);
- if(!r)
- return ret;
-
- for(fi = XCBRenderQueryPictFormatsFormatsIter(r); fi.rem; XCBRenderPICTFORMINFONext(&fi))
- {
- const XCBRenderDIRECTFORMAT *t, *f;
- if(fi.data->type != XCBRenderPictTypeDirect)
- continue;
- if(fi.data->depth != tmpl->depth)
- continue;
- t = &tmpl->direct;
- f = &fi.data->direct;
- if(t->red_mask && (t->red_mask != f->red_mask || t->red_shift != f->red_shift))
- continue;
- if(t->green_mask && (t->green_mask != f->green_mask || t->green_shift != f->green_shift))
- continue;
- if(t->blue_mask && (t->blue_mask != f->blue_mask || t->blue_shift != f->blue_shift))
- continue;
- if(t->alpha_mask && (t->alpha_mask != f->alpha_mask || t->alpha_shift != f->alpha_shift))
- continue;
-
- ret = fi.data->id;
- }
-
- free(r);
- return ret;
-}
-
-void
-cairo_set_target_xcb (cairo_t *cr,
- XCBConnection *dpy,
- XCBDRAWABLE drawable,
- XCBVISUALTYPE *visual,
- cairo_format_t format)
-{
- cairo_surface_t *surface;
-
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
-
- surface = cairo_xcb_surface_create (dpy, drawable, visual, format);
- if (surface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface (cr, surface);
-
- /* cairo_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy (surface);
-}
-
-typedef struct cairo_xcb_surface {
- cairo_surface_t base;
-
- XCBConnection *dpy;
- XCBGCONTEXT gc;
- XCBDRAWABLE drawable;
- int owns_pixmap;
- XCBVISUALTYPE *visual;
- cairo_format_t format;
-
- int render_major;
- int render_minor;
-
- int width;
- int height;
-
- XCBRenderPICTURE picture;
-} cairo_xcb_surface_t;
-
-#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
- (((surface)->render_major > major) || \
- (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
-
-#define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-
-#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
-#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
-
-#define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
-#define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
-
-#define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-
-#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
-#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
-
-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;
- }
-}
-
-static cairo_surface_t *
-_cairo_xcb_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- cairo_xcb_surface_t *src = abstract_src;
- XCBConnection *dpy = src->dpy;
- XCBDRAWABLE d;
- cairo_xcb_surface_t *surface;
-
- /* XXX: There's a pretty lame heuristic here. This assumes that
- * all non-Render X servers do not support depth-32 pixmaps, (and
- * that they do support depths 1, 8, and 24). Obviously, it would
- * be much better to check the depths that are actually
- * supported. */
- if (!dpy
- || (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)
- && format == CAIRO_FORMAT_ARGB32))
- {
- return NULL;
- }
-
- d.pixmap = XCBPIXMAPNew (dpy);
- XCBCreatePixmap (dpy, _CAIRO_FORMAT_DEPTH (format),
- d.pixmap, src->drawable,
- width, height);
-
- surface = (cairo_xcb_surface_t *)
- cairo_xcb_surface_create (dpy, d, NULL, format);
- surface->owns_pixmap = 1;
-
- surface->width = width;
- surface->height = height;
-
- return &surface->base;
-}
-
-static void
-_cairo_xcb_surface_destroy (void *abstract_surface)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
- if (surface->picture.xid)
- XCBRenderFreePicture (surface->dpy, surface->picture);
-
- if (surface->owns_pixmap)
- XCBFreePixmap (surface->dpy, surface->drawable.pixmap);
-
- if (surface->gc.xid)
- XCBFreeGC (surface->dpy, surface->gc);
-
- surface->dpy = 0;
-
- free (surface);
-}
-
-static double
-_cairo_xcb_surface_pixels_per_inch (void *abstract_surface)
-{
- /* XXX: We should really get this value from somewhere like Xft.dpy */
- return 96.0;
-}
-
-static int
-bits_per_pixel(XCBConnection *c, int depth)
-{
- XCBFORMAT *fmt = XCBConnSetupSuccessRepPixmapFormats(XCBGetSetup(c));
- XCBFORMAT *fmtend = fmt + XCBConnSetupSuccessRepPixmapFormatsLength(XCBGetSetup(c));
-
- for(; fmt != fmtend; ++fmt)
- if(fmt->depth == depth)
- return fmt->bits_per_pixel;
-
- if(depth <= 4)
- return 4;
- if(depth <= 8)
- return 8;
- if(depth <= 16)
- return 16;
- return 32;
-}
-
-static int
-bytes_per_line(XCBConnection *c, int width, int bpp)
-{
- int bitmap_pad = XCBGetSetup(c)->bitmap_format_scanline_pad;
- return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3;
-}
-
-static cairo_status_t
-_get_image_surface (cairo_xcb_surface_t *surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect)
-{
- cairo_image_surface_t *image;
- XCBGetGeometryRep *geomrep;
- XCBGetImageRep *imagerep;
- int bpp;
- int x1, y1, x2, y2;
-
- geomrep = XCBGetGeometryReply(surface->dpy, XCBGetGeometry(surface->dpy, surface->drawable), 0);
- if(!geomrep)
- return 0;
-
- surface->width = geomrep->width;
- surface->height = geomrep->height;
- free(geomrep);
-
- x1 = 0;
- y1 = 0;
- x2 = surface->width;
- y2 = surface->height;
-
- if (interest_rect) {
- if (interest_rect->x > x1)
- x1 = interest_rect->x;
- if (interest_rect->y > y1)
- y1 = interest_rect->y;
- if (interest_rect->x + interest_rect->width < x2)
- x2 = interest_rect->x + interest_rect->width;
- if (interest_rect->y + interest_rect->height < y2)
- y2 = interest_rect->y + interest_rect->height;
-
- if (x1 >= x2 || y1 >= y2) {
- *image_out = NULL;
- return CAIRO_STATUS_SUCCESS;
- }
- }
-
- if (image_rect) {
- image_rect->x = x1;
- image_rect->y = y1;
- image_rect->width = x2 - x1;
- image_rect->height = y2 - y1;
- }
-
- imagerep = XCBGetImageReply(surface->dpy,
- XCBGetImage(surface->dpy, ZPixmap,
- surface->drawable,
- x1, y1,
- x2 - x1, y2 - y1,
- AllPlanes), 0);
- if(!imagerep)
- return 0;
-
- bpp = bits_per_pixel(surface->dpy, imagerep->depth);
-
- if (surface->visual) {
- cairo_format_masks_t masks;
-
- /* XXX: Add support here for pictures with external alpha? */
-
- masks.bpp = bpp;
- masks.alpha_mask = 0;
- masks.red_mask = surface->visual->red_mask;
- masks.green_mask = surface->visual->green_mask;
- masks.blue_mask = surface->visual->blue_mask;
-
- image = _cairo_image_surface_create_with_masks (XCBGetImageData(imagerep),
- &masks,
- x2 - x1,
- y2 - y1,
- bytes_per_line(surface->dpy, surface->width, bpp));
- } else {
- image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data (XCBGetImageData(imagerep),
- surface->format,
- x2 - x1,
- y2 - y1,
- bytes_per_line(surface->dpy, surface->width, bpp));
- }
-
- /* Let the surface take ownership of the data */
- /* XXX: Can probably come up with a cleaner API here. */
- _cairo_image_surface_assume_ownership_of_data (image);
- /* FIXME: imagerep can't be freed correctly, I think. must copy. :-( */
-
- _cairo_image_surface_set_repeat (image, surface->base.repeat);
- _cairo_image_surface_set_matrix (image, &(surface->base.matrix));
-
- *image_out = image;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface)
-{
- if (surface->gc.xid)
- return;
-
- surface->gc = XCBGCONTEXTNew(surface->dpy);
- XCBCreateGC (surface->dpy, surface->gc, surface->drawable, 0, 0);
-}
-
-static cairo_status_t
-_draw_image_surface (cairo_xcb_surface_t *surface,
- cairo_image_surface_t *image,
- int dst_x,
- int dst_y)
-{
- int bpp, data_len;
-
- _cairo_xcb_surface_ensure_gc (surface);
- bpp = bits_per_pixel(surface->dpy, image->depth);
- data_len = bytes_per_line(surface->dpy, image->width, bpp) * image->height;
- XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc,
- image->width,
- image->height,
- dst_x, dst_y,
- /* left_pad */ 0, image->depth,
- data_len, image->data);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
- cairo_image_surface_t *image;
- cairo_status_t status;
-
- status = _get_image_surface (surface, NULL, &image, NULL);
- if (status == CAIRO_STATUS_SUCCESS) {
- cairo_surface_set_filter (&image->base, surface->base.filter);
- cairo_surface_set_matrix (&image->base, &surface->base.matrix);
- cairo_surface_set_repeat (&image->base, surface->base.repeat);
-
- *image_out = image;
- }
-
- return status;
-}
-
-static void
-_cairo_xcb_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
- cairo_surface_destroy (&image->base);
-}
-
-static cairo_status_t
-_cairo_xcb_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect_out,
- void **image_extra)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
- cairo_image_surface_t *image;
- cairo_status_t status;
-
- status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
- if (status == CAIRO_STATUS_SUCCESS)
- *image_out = image;
-
- return status;
-}
-
-static void
-_cairo_xcb_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
-
- /* ignore errors */
- _draw_image_surface (surface, image, image_rect->x, image_rect->y);
-
- cairo_surface_destroy (&image->base);
-}
-
-static cairo_status_t
-_cairo_xcb_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
- cairo_xcb_surface_t *clone;
-
- if (src->backend == surface->base.backend ) {
- cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src;
-
- if (xcb_src->dpy == surface->dpy) {
- *clone_out = src;
- cairo_surface_reference (src);
-
- return CAIRO_STATUS_SUCCESS;
- }
- } else if (_cairo_surface_is_image (src)) {
- cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
-
- clone = (cairo_xcb_surface_t *)
- _cairo_xcb_surface_create_similar (surface, image_src->format, 0,
- image_src->width, image_src->height);
- if (clone == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- _draw_image_surface (clone, image_src, 0, 0);
-
- *clone_out = &clone->base;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface,
- cairo_matrix_t *matrix)
-{
- XCBRenderTRANSFORM xtransform;
-
- if (!surface->picture.xid)
- return CAIRO_STATUS_SUCCESS;
-
- xtransform.matrix11 = _cairo_fixed_from_double (matrix->m[0][0]);
- xtransform.matrix12 = _cairo_fixed_from_double (matrix->m[1][0]);
- xtransform.matrix13 = _cairo_fixed_from_double (matrix->m[2][0]);
-
- xtransform.matrix21 = _cairo_fixed_from_double (matrix->m[0][1]);
- xtransform.matrix22 = _cairo_fixed_from_double (matrix->m[1][1]);
- xtransform.matrix23 = _cairo_fixed_from_double (matrix->m[2][1]);
-
- xtransform.matrix31 = 0;
- xtransform.matrix32 = 0;
- xtransform.matrix33 = _cairo_fixed_from_double (1);
-
- if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
- {
- static const XCBRenderTRANSFORM identity = {
- 1 << 16, 0x00000, 0x00000,
- 0x00000, 1 << 16, 0x00000,
- 0x00000, 0x00000, 1 << 16
- };
-
- if (memcmp (&xtransform, &identity, sizeof (XCBRenderTRANSFORM)) == 0)
- return CAIRO_STATUS_SUCCESS;
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface,
- cairo_filter_t filter)
-{
- char *render_filter;
-
- if (!surface->picture.xid)
- return CAIRO_STATUS_SUCCESS;
-
- if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
- {
- if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
- return CAIRO_STATUS_SUCCESS;
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- switch (filter) {
- case CAIRO_FILTER_FAST:
- render_filter = "fast";
- break;
- case CAIRO_FILTER_GOOD:
- render_filter = "good";
- break;
- case CAIRO_FILTER_BEST:
- render_filter = "best";
- break;
- case CAIRO_FILTER_NEAREST:
- render_filter = "nearest";
- break;
- case CAIRO_FILTER_BILINEAR:
- render_filter = "bilinear";
- break;
- default:
- render_filter = "best";
- break;
- }
-
- XCBRenderSetPictureFilter(surface->dpy, surface->picture,
- strlen(render_filter), render_filter, 0, NULL);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, int repeat)
-{
- CARD32 mask = XCBRenderCPRepeat;
- CARD32 pa[] = { repeat };
-
- if (!surface->picture.xid)
- return CAIRO_STATUS_SUCCESS;
-
- XCBRenderChangePicture (surface->dpy, surface->picture, mask, pa);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_set_attributes (cairo_xcb_surface_t *surface,
- cairo_surface_attributes_t *attributes)
-{
- cairo_int_status_t status;
-
- status = _cairo_xcb_surface_set_matrix (surface, &attributes->matrix);
- if (status)
- return status;
-
- switch (attributes->extend) {
- case CAIRO_EXTEND_NONE:
- _cairo_xcb_surface_set_repeat (surface, 0);
- break;
- case CAIRO_EXTEND_REPEAT:
- _cairo_xcb_surface_set_repeat (surface, 1);
- break;
- case CAIRO_EXTEND_REFLECT:
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- status = _cairo_xcb_surface_set_filter (surface, attributes->filter);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static int
-_render_operator (cairo_operator_t operator)
-{
- switch (operator) {
- case CAIRO_OPERATOR_CLEAR:
- return XCBRenderPictOpClear;
- case CAIRO_OPERATOR_SRC:
- return XCBRenderPictOpSrc;
- case CAIRO_OPERATOR_DST:
- return XCBRenderPictOpDst;
- case CAIRO_OPERATOR_OVER:
- return XCBRenderPictOpOver;
- case CAIRO_OPERATOR_OVER_REVERSE:
- return XCBRenderPictOpOverReverse;
- case CAIRO_OPERATOR_IN:
- return XCBRenderPictOpIn;
- case CAIRO_OPERATOR_IN_REVERSE:
- return XCBRenderPictOpInReverse;
- case CAIRO_OPERATOR_OUT:
- return XCBRenderPictOpOut;
- case CAIRO_OPERATOR_OUT_REVERSE:
- return XCBRenderPictOpOutReverse;
- case CAIRO_OPERATOR_ATOP:
- return XCBRenderPictOpAtop;
- case CAIRO_OPERATOR_ATOP_REVERSE:
- return XCBRenderPictOpAtopReverse;
- case CAIRO_OPERATOR_XOR:
- return XCBRenderPictOpXor;
- case CAIRO_OPERATOR_ADD:
- return XCBRenderPictOpAdd;
- case CAIRO_OPERATOR_SATURATE:
- return XCBRenderPictOpSaturate;
- default:
- return XCBRenderPictOpOver;
- }
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_composite (cairo_operator_t operator,
- cairo_pattern_t *src_pattern,
- cairo_pattern_t *mask_pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- cairo_surface_attributes_t src_attr, mask_attr;
- cairo_xcb_surface_t *dst = abstract_dst;
- cairo_xcb_surface_t *src;
- cairo_xcb_surface_t *mask;
- cairo_int_status_t status;
-
- if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
- &dst->base,
- src_x, src_y,
- mask_x, mask_y,
- width, height,
- (cairo_surface_t **) &src,
- (cairo_surface_t **) &mask,
- &src_attr, &mask_attr);
- if (status)
- return status;
-
- status = _cairo_xcb_surface_set_attributes (src, &src_attr);
- if (CAIRO_OK (status))
- {
- if (mask)
- {
- status = _cairo_xcb_surface_set_attributes (mask, &mask_attr);
- if (CAIRO_OK (status))
- XCBRenderComposite (dst->dpy,
- _render_operator (operator),
- src->picture,
- mask->picture,
- dst->picture,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- mask_x + mask_attr.x_offset,
- mask_y + mask_attr.y_offset,
- dst_x, dst_y,
- width, height);
- }
- else
- {
- static XCBRenderPICTURE maskpict = { 0 };
-
- XCBRenderComposite (dst->dpy,
- _render_operator (operator),
- src->picture,
- maskpict,
- dst->picture,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- 0, 0,
- dst_x, dst_y,
- width, height);
- }
- }
-
- if (mask)
- _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr);
-
- _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_fill_rectangles (void *abstract_surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
- XCBRenderCOLOR render_color;
-
- if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- render_color.red = color->red_short;
- render_color.green = color->green_short;
- render_color.blue = color->blue_short;
- render_color.alpha = color->alpha_short;
-
- /* XXX: This XCBRECTANGLE cast is evil... it needs to go away somehow. */
- XCBRenderFillRectangles (surface->dpy,
- _render_operator (operator),
- surface->picture,
- render_color, num_rects, (XCBRECTANGLE *) rects);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- cairo_surface_attributes_t attributes;
- cairo_xcb_surface_t *dst = abstract_dst;
- cairo_xcb_surface_t *src;
- cairo_int_status_t status;
- int render_reference_x, render_reference_y;
- int render_src_x, render_src_y;
-
- if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_pattern_acquire_surface (pattern, &dst->base,
- src_x, src_y, width, height,
- (cairo_surface_t **) &src,
- &attributes);
- if (status)
- return status;
-
- if (traps[0].left.p1.y < traps[0].left.p2.y) {
- render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
- render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
- } else {
- render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
- render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
- }
-
- render_src_x = src_x + render_reference_x - dst_x;
- render_src_y = src_y + render_reference_y - dst_y;
-
- /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
- /* XXX: format_from_cairo is slow. should cache something. */
- status = _cairo_xcb_surface_set_attributes (src, &attributes);
- if (CAIRO_OK (status))
- XCBRenderTrapezoids (dst->dpy,
- _render_operator (operator),
- src->picture, dst->picture,
- format_from_cairo (dst->dpy, CAIRO_FORMAT_A8),
- render_src_x + attributes.x_offset,
- render_src_y + attributes.y_offset,
- num_traps, (XCBRenderTRAP *) traps);
-
- _cairo_pattern_release_surface (&dst->base, &src->base, &attributes);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_copy_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- /* FIXME */
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static const cairo_surface_backend_t cairo_xcb_surface_backend = {
- _cairo_xcb_surface_create_similar,
- _cairo_xcb_surface_destroy,
- _cairo_xcb_surface_pixels_per_inch,
- _cairo_xcb_surface_acquire_source_image,
- _cairo_xcb_surface_release_source_image,
- _cairo_xcb_surface_acquire_dest_image,
- _cairo_xcb_surface_release_dest_image,
- _cairo_xcb_surface_clone_similar,
- _cairo_xcb_surface_composite,
- _cairo_xcb_surface_fill_rectangles,
- _cairo_xcb_surface_composite_trapezoids,
- _cairo_xcb_surface_copy_page,
- _cairo_xcb_surface_show_page,
- _cairo_xcb_surface_set_clip_region,
- NULL /* show_glyphs */
-};
-
-static void
-query_render_version (XCBConnection *c, cairo_xcb_surface_t *surface)
-{
- XCBRenderQueryVersionRep *r;
-
- surface->render_major = -1;
- surface->render_minor = -1;
-
- if (!XCBRenderInit(c))
- return;
-
- r = XCBRenderQueryVersionReply(c, XCBRenderQueryVersion(c, 0, 6), 0);
- if (!r)
- return;
-
- surface->render_major = r->major_version;
- surface->render_minor = r->minor_version;
- free(r);
-}
-
-cairo_surface_t *
-cairo_xcb_surface_create (XCBConnection *dpy,
- XCBDRAWABLE drawable,
- XCBVISUALTYPE *visual,
- cairo_format_t format)
-{
- cairo_xcb_surface_t *surface;
-
- surface = malloc (sizeof (cairo_xcb_surface_t));
- if (surface == NULL)
- return NULL;
-
- _cairo_surface_init (&surface->base, &cairo_xcb_surface_backend);
-
- surface->dpy = dpy;
- surface->gc.xid = 0;
- surface->drawable = drawable;
- surface->owns_pixmap = 0;
- surface->visual = visual;
- surface->format = format;
-
- query_render_version(dpy, surface);
-
- if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
- {
- XCBRenderPICTFORMAT fmt;
- if(visual)
- fmt = format_from_visual (dpy, visual->visual_id);
- else
- fmt = format_from_cairo (dpy, format);
- surface->picture = XCBRenderPICTURENew(dpy);
- XCBRenderCreatePicture (dpy, surface->picture, drawable,
- fmt, 0, NULL);
- }
- else
- surface->picture.xid = 0;
-
- return (cairo_surface_t *) surface;
-}
diff --git a/src/cairo_xlib_surface.c b/src/cairo_xlib_surface.c
deleted file mode 100644
index 3eaef57e5..000000000
--- a/src/cairo_xlib_surface.c
+++ /dev/null
@@ -1,1530 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2002 University of Southern California
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#include "cairoint.h"
-#include "cairo-xlib.h"
-
-/**
- * cairo_set_target_drawable:
- * @cr: a #cairo_t
- * @dpy: an X display
- * @drawable: a window or pixmap on the default screen of @dpy
- *
- * Directs output for a #cairo_t to an Xlib drawable. @drawable must
- * be a Window or Pixmap on the default screen of @dpy using the
- * default colormap and visual. Using this function is slow because
- * the function must retrieve information about @drawable from the X
- * server.
-
- * The combination of cairo_xlib_surface_create() and
- * cairo_set_target_surface() is somewhat more flexible, although
- * it still is slow.
- **/
-void
-cairo_set_target_drawable (cairo_t *cr,
- Display *dpy,
- Drawable drawable)
-{
- cairo_surface_t *surface;
-
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
-
- surface = cairo_xlib_surface_create (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_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy (surface);
-}
-
-typedef struct _cairo_xlib_surface {
- cairo_surface_t base;
-
- Display *dpy;
- GC gc;
- Drawable drawable;
- int owns_pixmap;
- Visual *visual;
- cairo_format_t format;
-
- int render_major;
- int render_minor;
-
- int width;
- int height;
-
- Picture picture;
-} cairo_xlib_surface_t;
-
-#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
- (((surface)->render_major > major) || \
- (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
-
-#define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-
-
-#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
-#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
-
-#define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
-#define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
-
-#define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-
-#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
-#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
-
-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;
- }
-}
-
-static cairo_surface_t *
-_cairo_xlib_surface_create_with_size (Display *dpy,
- Drawable drawable,
- Visual *visual,
- cairo_format_t format,
- Colormap colormap,
- int width,
- int height);
-
-
-static cairo_surface_t *
-_cairo_xlib_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- cairo_xlib_surface_t *src = abstract_src;
- Display *dpy = src->dpy;
- int scr;
- Pixmap pix;
- cairo_xlib_surface_t *surface;
-
- /* As a good first approximation, if the display doesn't have COMPOSITE,
- * we're better off using image surfaces for all temporary operations
- */
- if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE(src)) {
- return cairo_image_surface_create (format, width, height);
- }
-
- scr = DefaultScreen (dpy);
-
- pix = XCreatePixmap (dpy, DefaultRootWindow (dpy),
- width <= 0 ? 1 : width, height <= 0 ? 1 : height,
- _CAIRO_FORMAT_DEPTH (format));
-
- surface = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_with_size (dpy, pix, NULL, format,
- DefaultColormap (dpy, scr),
- width, height);
- surface->owns_pixmap = 1;
-
- surface->width = width;
- surface->height = height;
-
- return &surface->base;
-}
-
-static void
-_cairo_xlib_surface_destroy (void *abstract_surface)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
- if (surface->picture)
- XRenderFreePicture (surface->dpy, surface->picture);
-
- if (surface->owns_pixmap)
- XFreePixmap (surface->dpy, surface->drawable);
-
- if (surface->gc)
- XFreeGC (surface->dpy, surface->gc);
-
- surface->dpy = 0;
-
- free (surface);
-}
-
-static double
-_cairo_xlib_surface_pixels_per_inch (void *abstract_surface)
-{
- /* XXX: We should really get this value from somewhere like Xft.dpy */
- return 96.0;
-}
-
-static cairo_status_t
-_get_image_surface (cairo_xlib_surface_t *surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect)
-{
- cairo_image_surface_t *image;
- XImage *ximage;
- Window root_ignore;
- int x_ignore, y_ignore, bwidth_ignore, depth_ignore;
- int x1, y1, x2, y2;
-
- XGetGeometry (surface->dpy,
- surface->drawable,
- &root_ignore, &x_ignore, &y_ignore,
- &surface->width, &surface->height,
- &bwidth_ignore, &depth_ignore);
-
- x1 = 0;
- y1 = 0;
- x2 = surface->width;
- y2 = surface->height;
-
- if (interest_rect) {
- if (interest_rect->x > x1)
- x1 = interest_rect->x;
- if (interest_rect->y > y1)
- y1 = interest_rect->y;
- if (interest_rect->x + interest_rect->width < x2)
- x2 = interest_rect->x + interest_rect->width;
- if (interest_rect->y + interest_rect->height < y2)
- y2 = interest_rect->y + interest_rect->height;
-
- if (x1 >= x2 || y1 >= y2) {
- *image_out = NULL;
- return CAIRO_STATUS_SUCCESS;
- }
- }
-
- if (image_rect) {
- image_rect->x = x1;
- image_rect->y = y1;
- image_rect->width = x2 - x1;
- image_rect->height = y2 - y1;
- }
-
- /* XXX: This should try to use the XShm extension if availible */
- ximage = XGetImage (surface->dpy,
- surface->drawable,
- x1, y1,
- x2 - x1, y2 - y1,
- AllPlanes, ZPixmap);
-
- if (surface->visual) {
- cairo_format_masks_t masks;
-
- /* XXX: Add support here for pictures with external alpha? */
-
- masks.bpp = ximage->bits_per_pixel;
- masks.alpha_mask = 0;
- masks.red_mask = surface->visual->red_mask;
- masks.green_mask = surface->visual->green_mask;
- masks.blue_mask = surface->visual->blue_mask;
-
- image = _cairo_image_surface_create_with_masks (ximage->data,
- &masks,
- ximage->width,
- ximage->height,
- ximage->bytes_per_line);
- } else {
- image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data (ximage->data,
- surface->format,
- ximage->width,
- ximage->height,
- ximage->bytes_per_line);
- }
-
- /* Let the surface take ownership of the data */
- /* XXX: Can probably come up with a cleaner API here. */
- _cairo_image_surface_assume_ownership_of_data (image);
- ximage->data = NULL;
- XDestroyImage (ximage);
-
- _cairo_image_surface_set_repeat (image, surface->base.repeat);
- _cairo_image_surface_set_matrix (image, &(surface->base.matrix));
-
- *image_out = image;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
-{
- if (surface->gc)
- return;
-
- surface->gc = XCreateGC (surface->dpy, surface->drawable, 0, NULL);
-}
-
-static cairo_status_t
-_draw_image_surface (cairo_xlib_surface_t *surface,
- cairo_image_surface_t *image,
- int dst_x,
- int dst_y)
-{
- XImage *ximage;
- unsigned bitmap_pad;
-
- if (image->depth > 16)
- bitmap_pad = 32;
- else if (image->depth > 8)
- bitmap_pad = 16;
- else
- bitmap_pad = 8;
-
- ximage = XCreateImage (surface->dpy,
- DefaultVisual(surface->dpy, DefaultScreen(surface->dpy)),
- image->depth,
- ZPixmap,
- 0,
- image->data,
- image->width,
- image->height,
- bitmap_pad,
- image->stride);
- if (ximage == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- _cairo_xlib_surface_ensure_gc (surface);
- XPutImage(surface->dpy, surface->drawable, surface->gc,
- ximage, 0, 0, dst_x, dst_y,
- image->width, image->height);
-
- /* Foolish XDestroyImage thinks it can free my data, but I won't
- stand for it. */
- ximage->data = NULL;
- XDestroyImage (ximage);
-
- return CAIRO_STATUS_SUCCESS;
-
-}
-
-static cairo_status_t
-_cairo_xlib_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
- cairo_image_surface_t *image;
- cairo_status_t status;
-
- status = _get_image_surface (surface, NULL, &image, NULL);
- if (status == CAIRO_STATUS_SUCCESS) {
- cairo_surface_set_filter (&image->base, surface->base.filter);
- cairo_surface_set_matrix (&image->base, &surface->base.matrix);
- cairo_surface_set_repeat (&image->base, surface->base.repeat);
-
- *image_out = image;
- }
-
- return status;
-}
-
-static void
-_cairo_xlib_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
- cairo_surface_destroy (&image->base);
-}
-
-static cairo_status_t
-_cairo_xlib_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect_out,
- void **image_extra)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
- cairo_image_surface_t *image;
- cairo_status_t status;
-
- status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
- if (status == CAIRO_STATUS_SUCCESS)
- *image_out = image;
-
- return status;
-}
-
-static void
-_cairo_xlib_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
-
- /* ignore errors */
- _draw_image_surface (surface, image, image_rect->x, image_rect->y);
-
- cairo_surface_destroy (&image->base);
-}
-
-static cairo_status_t
-_cairo_xlib_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
- cairo_xlib_surface_t *clone;
-
- if (src->backend == surface->base.backend ) {
- cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src;
-
- if (xlib_src->dpy == surface->dpy) {
- *clone_out = src;
- cairo_surface_reference (src);
-
- return CAIRO_STATUS_SUCCESS;
- }
- } else if (_cairo_surface_is_image (src)) {
- cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
-
- clone = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_similar (surface, image_src->format, 0,
- image_src->width, image_src->height);
- if (clone == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- _draw_image_surface (clone, image_src, 0, 0);
-
- *clone_out = &clone->base;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_status_t
-_cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
- cairo_matrix_t *matrix)
-{
- XTransform xtransform;
-
- if (!surface->picture)
- return CAIRO_STATUS_SUCCESS;
-
- xtransform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
- xtransform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
- xtransform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
-
- xtransform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
- xtransform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
- xtransform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
-
- xtransform.matrix[2][0] = 0;
- xtransform.matrix[2][1] = 0;
- xtransform.matrix[2][2] = _cairo_fixed_from_double (1);
-
- if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
- {
- static const XTransform identity = { {
- { 1 << 16, 0x00000, 0x00000 },
- { 0x00000, 1 << 16, 0x00000 },
- { 0x00000, 0x00000, 1 << 16 },
- } };
-
- if (memcmp (&xtransform, &identity, sizeof (XTransform)) == 0)
- return CAIRO_STATUS_SUCCESS;
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- XRenderSetPictureTransform (surface->dpy, surface->picture, &xtransform);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface,
- cairo_filter_t filter)
-{
- char *render_filter;
-
- if (!surface->picture)
- return CAIRO_STATUS_SUCCESS;
-
- if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
- {
- if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
- return CAIRO_STATUS_SUCCESS;
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- switch (filter) {
- case CAIRO_FILTER_FAST:
- render_filter = FilterFast;
- break;
- case CAIRO_FILTER_GOOD:
- render_filter = FilterGood;
- break;
- case CAIRO_FILTER_BEST:
- render_filter = FilterBest;
- break;
- case CAIRO_FILTER_NEAREST:
- render_filter = FilterNearest;
- break;
- case CAIRO_FILTER_BILINEAR:
- render_filter = FilterBilinear;
- break;
- default:
- render_filter = FilterBest;
- break;
- }
-
- XRenderSetPictureFilter (surface->dpy, surface->picture,
- render_filter, NULL, 0);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface, int repeat)
-{
- XRenderPictureAttributes pa;
- unsigned long mask;
-
- if (!surface->picture)
- return CAIRO_STATUS_SUCCESS;
-
- mask = CPRepeat;
- pa.repeat = repeat;
-
- XRenderChangePicture (surface->dpy, surface->picture, mask, &pa);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface,
- cairo_surface_attributes_t *attributes)
-{
- cairo_int_status_t status;
-
- status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix);
- if (status)
- return status;
-
- switch (attributes->extend) {
- case CAIRO_EXTEND_NONE:
- _cairo_xlib_surface_set_repeat (surface, 0);
- break;
- case CAIRO_EXTEND_REPEAT:
- _cairo_xlib_surface_set_repeat (surface, 1);
- break;
- case CAIRO_EXTEND_REFLECT:
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- status = _cairo_xlib_surface_set_filter (surface, attributes->filter);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static int
-_render_operator (cairo_operator_t operator)
-{
- switch (operator) {
- case CAIRO_OPERATOR_CLEAR:
- return PictOpClear;
- case CAIRO_OPERATOR_SRC:
- return PictOpSrc;
- case CAIRO_OPERATOR_DST:
- return PictOpDst;
- case CAIRO_OPERATOR_OVER:
- return PictOpOver;
- case CAIRO_OPERATOR_OVER_REVERSE:
- return PictOpOverReverse;
- case CAIRO_OPERATOR_IN:
- return PictOpIn;
- case CAIRO_OPERATOR_IN_REVERSE:
- return PictOpInReverse;
- case CAIRO_OPERATOR_OUT:
- return PictOpOut;
- case CAIRO_OPERATOR_OUT_REVERSE:
- return PictOpOutReverse;
- case CAIRO_OPERATOR_ATOP:
- return PictOpAtop;
- case CAIRO_OPERATOR_ATOP_REVERSE:
- return PictOpAtopReverse;
- case CAIRO_OPERATOR_XOR:
- return PictOpXor;
- case CAIRO_OPERATOR_ADD:
- return PictOpAdd;
- case CAIRO_OPERATOR_SATURATE:
- return PictOpSaturate;
- default:
- return PictOpOver;
- }
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_composite (cairo_operator_t operator,
- cairo_pattern_t *src_pattern,
- cairo_pattern_t *mask_pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- cairo_surface_attributes_t src_attr, mask_attr;
- cairo_xlib_surface_t *dst = abstract_dst;
- cairo_xlib_surface_t *src;
- cairo_xlib_surface_t *mask;
- cairo_int_status_t status;
-
- if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
- &dst->base,
- src_x, src_y,
- mask_x, mask_y,
- width, height,
- (cairo_surface_t **) &src,
- (cairo_surface_t **) &mask,
- &src_attr, &mask_attr);
- if (status)
- return status;
-
- status = _cairo_xlib_surface_set_attributes (src, &src_attr);
- if (CAIRO_OK (status))
- {
- if (mask)
- {
- status = _cairo_xlib_surface_set_attributes (mask, &mask_attr);
- if (CAIRO_OK (status))
- XRenderComposite (dst->dpy,
- _render_operator (operator),
- src->picture,
- mask->picture,
- dst->picture,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- mask_x + mask_attr.x_offset,
- mask_y + mask_attr.y_offset,
- dst_x, dst_y,
- width, height);
- }
- else
- {
- XRenderComposite (dst->dpy,
- _render_operator (operator),
- src->picture,
- 0,
- dst->picture,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- 0, 0,
- dst_x, dst_y,
- width, height);
- }
- }
-
- if (mask)
- _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr);
-
- _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_fill_rectangles (void *abstract_surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
- XRenderColor render_color;
-
- if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- render_color.red = color->red_short;
- render_color.green = color->green_short;
- render_color.blue = color->blue_short;
- render_color.alpha = color->alpha_short;
-
- /* XXX: This XRectangle cast is evil... it needs to go away somehow. */
- XRenderFillRectangles (surface->dpy,
- _render_operator (operator),
- surface->picture,
- &render_color, (XRectangle *) rects, num_rects);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- cairo_surface_attributes_t attributes;
- cairo_xlib_surface_t *dst = abstract_dst;
- cairo_xlib_surface_t *src;
- cairo_int_status_t status;
- int render_reference_x, render_reference_y;
- int render_src_x, render_src_y;
-
- if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_pattern_acquire_surface (pattern, &dst->base,
- src_x, src_y, width, height,
- (cairo_surface_t **) &src,
- &attributes);
- if (status)
- return status;
-
- if (traps[0].left.p1.y < traps[0].left.p2.y) {
- render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
- render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
- } else {
- render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
- render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
- }
-
- render_src_x = src_x + render_reference_x - dst_x;
- render_src_y = src_y + render_reference_y - dst_y;
-
- /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
- status = _cairo_xlib_surface_set_attributes (src, &attributes);
- if (CAIRO_OK (status))
- XRenderCompositeTrapezoids (dst->dpy,
- _render_operator (operator),
- src->picture, dst->picture,
- XRenderFindStandardFormat (dst->dpy, PictStandardA8),
- render_src_x + attributes.x_offset,
- render_src_y + attributes.y_offset,
- (XTrapezoid *) traps, num_traps);
-
- _cairo_pattern_release_surface (&dst->base, &src->base, &attributes);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_copy_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
-
- Region xregion;
- XRectangle xr;
- XRectangle *rects = NULL;
- XGCValues gc_values;
- pixman_box16_t *box;
- cairo_xlib_surface_t *surf;
- int n, m;
-
- surf = (cairo_xlib_surface_t *) abstract_surface;
-
- if (region == NULL) {
- /* NULL region == reset the clip */
- xregion = XCreateRegion();
- xr.x = 0;
- xr.y = 0;
- xr.width = surf->width;
- xr.height = surf->height;
- XUnionRectWithRegion (&xr, xregion, xregion);
- rects = malloc(sizeof(XRectangle));
- if (rects == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- rects[0] = xr;
- m = 1;
-
- } else {
- n = pixman_region_num_rects (region);
- /* XXX: Are we sure these are the semantics we want for an
- * empty, (not null) region? */
- if (n == 0)
- return CAIRO_STATUS_SUCCESS;
- rects = malloc(sizeof(XRectangle) * n);
- if (rects == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- box = pixman_region_rects (region);
- xregion = XCreateRegion();
-
- m = n;
- for (; n > 0; --n, ++box) {
- xr.x = (short) box->x1;
- xr.y = (short) box->y1;
- xr.width = (unsigned short) (box->x2 - box->x1);
- xr.height = (unsigned short) (box->y2 - box->y1);
- rects[n-1] = xr;
- XUnionRectWithRegion (&xr, xregion, xregion);
- }
- }
-
- _cairo_xlib_surface_ensure_gc (surf);
- XGetGCValues(surf->dpy, surf->gc, GCGraphicsExposures, &gc_values);
- XSetGraphicsExposures(surf->dpy, surf->gc, False);
- XSetClipRectangles(surf->dpy, surf->gc, 0, 0, rects, m, Unsorted);
- free(rects);
- if (surf->picture)
- XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
- XDestroyRegion(xregion);
- XSetGraphicsExposures(surf->dpy, surf->gc, gc_values.graphics_exposures);
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xlib_surface_show_glyphs (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs);
-
-static const cairo_surface_backend_t cairo_xlib_surface_backend = {
- _cairo_xlib_surface_create_similar,
- _cairo_xlib_surface_destroy,
- _cairo_xlib_surface_pixels_per_inch,
- _cairo_xlib_surface_acquire_source_image,
- _cairo_xlib_surface_release_source_image,
- _cairo_xlib_surface_acquire_dest_image,
- _cairo_xlib_surface_release_dest_image,
- _cairo_xlib_surface_clone_similar,
- _cairo_xlib_surface_composite,
- _cairo_xlib_surface_fill_rectangles,
- _cairo_xlib_surface_composite_trapezoids,
- _cairo_xlib_surface_copy_page,
- _cairo_xlib_surface_show_page,
- _cairo_xlib_surface_set_clip_region,
- _cairo_xlib_surface_show_glyphs
-};
-
-static cairo_surface_t *
-_cairo_xlib_surface_create_with_size (Display *dpy,
- Drawable drawable,
- Visual *visual,
- cairo_format_t format,
- Colormap colormap,
- int width,
- int height)
-{
- cairo_xlib_surface_t *surface;
- int render_standard;
-
- surface = malloc (sizeof (cairo_xlib_surface_t));
- if (surface == NULL)
- return NULL;
-
- _cairo_surface_init (&surface->base, &cairo_xlib_surface_backend);
-
- surface->visual = visual;
- surface->format = format;
-
- surface->dpy = dpy;
-
- surface->gc = 0;
- surface->drawable = drawable;
- surface->owns_pixmap = 0;
- surface->visual = visual;
- surface->width = width;
- surface->height = height;
-
- if (! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) {
- surface->render_major = -1;
- surface->render_minor = -1;
- }
-
- switch (format) {
- case CAIRO_FORMAT_A1:
- render_standard = PictStandardA1;
- break;
- case CAIRO_FORMAT_A8:
- render_standard = PictStandardA8;
- break;
- case CAIRO_FORMAT_RGB24:
- render_standard = PictStandardRGB24;
- break;
- case CAIRO_FORMAT_ARGB32:
- default:
- render_standard = PictStandardARGB32;
- break;
- }
-
- /* XXX: I'm currently ignoring the colormap. Is that bad? */
- if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
- surface->picture = XRenderCreatePicture (dpy, drawable,
- visual ?
- XRenderFindVisualFormat (dpy, visual) :
- XRenderFindStandardFormat (dpy, render_standard),
- 0, NULL);
- else
- surface->picture = 0;
-
- return (cairo_surface_t *) surface;
-}
-
-cairo_surface_t *
-cairo_xlib_surface_create (Display *dpy,
- Drawable drawable,
- Visual *visual,
- cairo_format_t format,
- Colormap colormap)
-{
- Window window_ignore;
- unsigned int int_ignore;
- unsigned int width, height;
-
- /* XXX: This call is a round-trip. We probably want to instead (or
- * also?) export a version that accepts width/height. Then, we'll
- * likely also need a resize function too.
- */
- XGetGeometry(dpy, drawable,
- &window_ignore, &int_ignore, &int_ignore,
- &width, &height,
- &int_ignore, &int_ignore);
-
- return _cairo_xlib_surface_create_with_size (dpy, drawable, visual, format,
- colormap, width, height);
-}
-DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create);
-
-/* RENDER glyphset cache code */
-
-typedef struct glyphset_cache {
- cairo_cache_t base;
- struct glyphset_cache *next;
- Display *display;
- XRenderPictFormat *a8_pict_format;
- GlyphSet glyphset;
- Glyph counter;
-} glyphset_cache_t;
-
-typedef struct {
- cairo_glyph_cache_key_t key;
- Glyph glyph;
- XGlyphInfo info;
- int refcount;
-} glyphset_cache_entry_t;
-
-static Glyph
-_next_xlib_glyph (glyphset_cache_t *cache)
-{
- return ++(cache->counter);
-}
-
-
-static cairo_status_t
-_xlib_glyphset_cache_create_entry (void *cache,
- void *key,
- void **return_entry)
-{
- glyphset_cache_t *g = (glyphset_cache_t *) cache;
- cairo_glyph_cache_key_t *k = (cairo_glyph_cache_key_t *)key;
- glyphset_cache_entry_t *v;
-
- cairo_status_t status;
-
- cairo_cache_t *im_cache;
- cairo_image_glyph_cache_entry_t *im;
-
- v = malloc (sizeof (glyphset_cache_entry_t));
- _cairo_lock_global_image_glyph_cache ();
- im_cache = _cairo_get_global_image_glyph_cache ();
-
- if (g == NULL || v == NULL || im_cache == NULL) {
- _cairo_unlock_global_image_glyph_cache ();
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- status = _cairo_cache_lookup (im_cache, key, (void **) (&im), NULL);
- if (status != CAIRO_STATUS_SUCCESS || im == NULL) {
- _cairo_unlock_global_image_glyph_cache ();
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- v->refcount = 1;
- v->key = *k;
- _cairo_unscaled_font_reference (v->key.unscaled);
-
- v->glyph = _next_xlib_glyph (g);
-
- v->info.width = im->image ? im->image->stride : im->size.width;
- v->info.height = im->size.height;
-
- /*
- * Most of the font rendering system thinks of glyph tiles as having
- * an origin at (0,0) and an x and y bounding box "offset" which
- * extends possibly off into negative coordinates, like so:
- *
- *
- * (x,y) <-- probably negative numbers
- * +----------------+
- * | . |
- * | . |
- * |......(0,0) |
- * | |
- * | |
- * +----------------+
- * (width+x,height+y)
- *
- * This is a postscript-y model, where each glyph has its own
- * coordinate space, so it's what we expose in terms of metrics. It's
- * apparantly what everyone's expecting. Everyone except the Render
- * extension. Render wants to see a glyph tile starting at (0,0), with
- * an origin offset inside, like this:
- *
- * (0,0)
- * +---------------+
- * | . |
- * | . |
- * |......(x,y) |
- * | |
- * | |
- * +---------------+
- * (width,height)
- *
- * Luckily, this is just the negation of the numbers we already have
- * sitting around for x and y.
- */
-
- v->info.x = -im->size.x;
- v->info.y = -im->size.y;
- v->info.xOff = 0;
- v->info.yOff = 0;
-
- XRenderAddGlyphs (g->display, g->glyphset,
- &(v->glyph), &(v->info), 1,
- im->image ? im->image->data : NULL,
- im->image ? v->info.height * v->info.width : 0);
-
- v->key.base.memory = im->image ? im->image->width * im->image->stride : 0;
- *return_entry = v;
- _cairo_unlock_global_image_glyph_cache ();
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_glyphset_cache_entry_reference (glyphset_cache_entry_t *e)
-{
- e->refcount++;
-}
-
-static void
-_xlib_glyphset_cache_destroy_cache (void *cache)
-{
- /* FIXME: will we ever release glyphset caches? */
-}
-
-static void
-_xlib_glyphset_cache_destroy_entry (void *cache, void *entry)
-{
- glyphset_cache_t *g;
- glyphset_cache_entry_t *v;
-
- g = (glyphset_cache_t *) cache;
- v = (glyphset_cache_entry_t *) entry;
-
- if (--v->refcount > 0)
- return;
-
- _cairo_unscaled_font_destroy (v->key.unscaled);
- XRenderFreeGlyphs (g->display, g->glyphset, &(v->glyph), 1);
- free (v);
-}
-
-static const cairo_cache_backend_t _xlib_glyphset_cache_backend = {
- _cairo_glyph_cache_hash,
- _cairo_glyph_cache_keys_equal,
- _xlib_glyphset_cache_create_entry,
- _xlib_glyphset_cache_destroy_entry,
- _xlib_glyphset_cache_destroy_cache
-};
-
-
-static glyphset_cache_t *
-_xlib_glyphset_caches = NULL;
-
-static void
-_lock_xlib_glyphset_caches (void)
-{
- /* FIXME: implement locking */
-}
-
-static void
-_unlock_xlib_glyphset_caches (void)
-{
- /* FIXME: implement locking */
-}
-
-static glyphset_cache_t *
-_get_glyphset_cache (Display *d)
-{
- /*
- * There should usually only be one, or a very small number, of
- * displays. So we just do a linear scan.
- */
-
- glyphset_cache_t *g;
-
- for (g = _xlib_glyphset_caches; g != NULL; g = g->next) {
- if (g->display == d)
- return g;
- }
-
- g = malloc (sizeof (glyphset_cache_t));
- if (g == NULL)
- goto ERR;
-
- g->counter = 0;
- g->display = d;
- g->a8_pict_format = XRenderFindStandardFormat (d, PictStandardA8);
- if (g->a8_pict_format == NULL)
- goto ERR;
-
- if (_cairo_cache_init (&g->base,
- &_xlib_glyphset_cache_backend,
- CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT))
- goto FREE_GLYPHSET_CACHE;
-
- g->glyphset = XRenderCreateGlyphSet (d, g->a8_pict_format);
- g->next = _xlib_glyphset_caches;
- _xlib_glyphset_caches = g;
- return g;
-
- FREE_GLYPHSET_CACHE:
- free (g);
-
- ERR:
- return NULL;
-}
-
-#define N_STACK_BUF 1024
-
-static cairo_status_t
-_cairo_xlib_surface_show_glyphs32 (cairo_font_t *font,
- cairo_operator_t operator,
- glyphset_cache_t *g,
- cairo_glyph_cache_key_t *key,
- cairo_xlib_surface_t *src,
- cairo_xlib_surface_t *self,
- int source_x,
- int source_y,
- const cairo_glyph_t *glyphs,
- glyphset_cache_entry_t **entries,
- int num_glyphs)
-{
- XGlyphElt32 *elts = NULL;
- XGlyphElt32 stack_elts [N_STACK_BUF];
-
- unsigned int *chars = NULL;
- unsigned int stack_chars [N_STACK_BUF];
-
- int i;
- int thisX, thisY;
- int lastX = 0, lastY = 0;
-
- /* Acquire arrays of suitable sizes. */
- if (num_glyphs < N_STACK_BUF) {
- elts = stack_elts;
- chars = stack_chars;
-
- } else {
- elts = malloc (num_glyphs * sizeof (XGlyphElt32));
- if (elts == NULL)
- goto FAIL;
-
- chars = malloc (num_glyphs * sizeof (unsigned int));
- if (chars == NULL)
- goto FREE_ELTS;
-
- }
-
- for (i = 0; i < num_glyphs; ++i) {
- chars[i] = entries[i]->glyph;
- elts[i].chars = &(chars[i]);
- elts[i].nchars = 1;
- elts[i].glyphset = g->glyphset;
- thisX = (int) floor (glyphs[i].x + 0.5);
- thisY = (int) floor (glyphs[i].y + 0.5);
- elts[i].xOff = thisX - lastX;
- elts[i].yOff = thisY - lastY;
- lastX = thisX;
- lastY = thisY;
- }
-
- XRenderCompositeText32 (self->dpy,
- _render_operator (operator),
- src->picture,
- self->picture,
- g->a8_pict_format,
- source_x, source_y,
- 0, 0,
- elts, num_glyphs);
-
- if (num_glyphs >= N_STACK_BUF) {
- free (chars);
- free (elts);
- }
-
- return CAIRO_STATUS_SUCCESS;
-
- FREE_ELTS:
- if (num_glyphs >= N_STACK_BUF)
- free (elts);
-
- FAIL:
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-
-static cairo_status_t
-_cairo_xlib_surface_show_glyphs16 (cairo_font_t *font,
- cairo_operator_t operator,
- glyphset_cache_t *g,
- cairo_glyph_cache_key_t *key,
- cairo_xlib_surface_t *src,
- cairo_xlib_surface_t *self,
- int source_x,
- int source_y,
- const cairo_glyph_t *glyphs,
- glyphset_cache_entry_t **entries,
- int num_glyphs)
-{
- XGlyphElt16 *elts = NULL;
- XGlyphElt16 stack_elts [N_STACK_BUF];
-
- unsigned short *chars = NULL;
- unsigned short stack_chars [N_STACK_BUF];
-
- int i;
- int thisX, thisY;
- int lastX = 0, lastY = 0;
-
- /* Acquire arrays of suitable sizes. */
- if (num_glyphs < N_STACK_BUF) {
- elts = stack_elts;
- chars = stack_chars;
-
- } else {
- elts = malloc (num_glyphs * sizeof (XGlyphElt16));
- if (elts == NULL)
- goto FAIL;
-
- chars = malloc (num_glyphs * sizeof (unsigned short));
- if (chars == NULL)
- goto FREE_ELTS;
-
- }
-
- for (i = 0; i < num_glyphs; ++i) {
- chars[i] = entries[i]->glyph;
- elts[i].chars = &(chars[i]);
- elts[i].nchars = 1;
- elts[i].glyphset = g->glyphset;
- thisX = (int) floor (glyphs[i].x + 0.5);
- thisY = (int) floor (glyphs[i].y + 0.5);
- elts[i].xOff = thisX - lastX;
- elts[i].yOff = thisY - lastY;
- lastX = thisX;
- lastY = thisY;
- }
-
- XRenderCompositeText16 (self->dpy,
- _render_operator (operator),
- src->picture,
- self->picture,
- g->a8_pict_format,
- source_x, source_y,
- 0, 0,
- elts, num_glyphs);
-
- if (num_glyphs >= N_STACK_BUF) {
- free (chars);
- free (elts);
- }
-
- return CAIRO_STATUS_SUCCESS;
-
- FREE_ELTS:
- if (num_glyphs >= N_STACK_BUF)
- free (elts);
-
- FAIL:
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-static cairo_status_t
-_cairo_xlib_surface_show_glyphs8 (cairo_font_t *font,
- cairo_operator_t operator,
- glyphset_cache_t *g,
- cairo_glyph_cache_key_t *key,
- cairo_xlib_surface_t *src,
- cairo_xlib_surface_t *self,
- int source_x,
- int source_y,
- const cairo_glyph_t *glyphs,
- glyphset_cache_entry_t **entries,
- int num_glyphs)
-{
- XGlyphElt8 *elts = NULL;
- XGlyphElt8 stack_elts [N_STACK_BUF];
-
- char *chars = NULL;
- char stack_chars [N_STACK_BUF];
-
- int i;
- int thisX, thisY;
- int lastX = 0, lastY = 0;
-
- /* Acquire arrays of suitable sizes. */
- if (num_glyphs < N_STACK_BUF) {
- elts = stack_elts;
- chars = stack_chars;
-
- } else {
- elts = malloc (num_glyphs * sizeof (XGlyphElt8));
- if (elts == NULL)
- goto FAIL;
-
- chars = malloc (num_glyphs * sizeof (char));
- if (chars == NULL)
- goto FREE_ELTS;
-
- }
-
- for (i = 0; i < num_glyphs; ++i) {
- chars[i] = entries[i]->glyph;
- elts[i].chars = &(chars[i]);
- elts[i].nchars = 1;
- elts[i].glyphset = g->glyphset;
- thisX = (int) floor (glyphs[i].x + 0.5);
- thisY = (int) floor (glyphs[i].y + 0.5);
- elts[i].xOff = thisX - lastX;
- elts[i].yOff = thisY - lastY;
- lastX = thisX;
- lastY = thisY;
- }
-
- XRenderCompositeText8 (self->dpy,
- _render_operator (operator),
- src->picture,
- self->picture,
- g->a8_pict_format,
- source_x, source_y,
- 0, 0,
- elts, num_glyphs);
-
- if (num_glyphs >= N_STACK_BUF) {
- free (chars);
- free (elts);
- }
-
- return CAIRO_STATUS_SUCCESS;
-
- FREE_ELTS:
- if (num_glyphs >= N_STACK_BUF)
- free (elts);
-
- FAIL:
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-
-static cairo_status_t
-_cairo_xlib_surface_show_glyphs (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_surface_attributes_t attributes;
- cairo_int_status_t status;
- unsigned int elt_size;
- cairo_xlib_surface_t *self = abstract_surface;
- cairo_xlib_surface_t *src;
- glyphset_cache_t *g;
- cairo_glyph_cache_key_t key;
- glyphset_cache_entry_t **entries;
- glyphset_cache_entry_t *stack_entries [N_STACK_BUF];
- int i;
-
- if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (self))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_pattern_acquire_surface (pattern, &self->base,
- source_x, source_y, width, height,
- (cairo_surface_t **) &src,
- &attributes);
- if (status)
- return status;
-
- status = _cairo_xlib_surface_set_attributes (src, &attributes);
- if (status)
- goto FAIL;
-
- /* Acquire an entry array of suitable size. */
- if (num_glyphs < N_STACK_BUF) {
- entries = stack_entries;
-
- } else {
- entries = malloc (num_glyphs * sizeof (glyphset_cache_entry_t *));
- if (entries == NULL)
- goto FAIL;
- }
-
- _lock_xlib_glyphset_caches ();
- g = _get_glyphset_cache (self->dpy);
- if (g == NULL)
- goto UNLOCK;
-
- /* Work out the index size to use. */
- elt_size = 8;
- _cairo_font_get_glyph_cache_key (font, &key);
-
- for (i = 0; i < num_glyphs; ++i) {
- key.index = glyphs[i].index;
- status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i]), NULL);
- if (status != CAIRO_STATUS_SUCCESS || entries[i] == NULL)
- goto UNLOCK;
-
- /* Referencing the glyph entries we use prevents them from
- * being freed if lookup of later entries causes them to
- * be ejected from the cache. It would be more efficient
- * (though more complex) to prevent them from being ejected
- * from the cache at all, so they could get reused later
- * in the same string.
- */
- _glyphset_cache_entry_reference (entries[i]);
-
- if (elt_size == 8 && entries[i]->glyph > 0xff)
- elt_size = 16;
- if (elt_size == 16 && entries[i]->glyph > 0xffff) {
- elt_size = 32;
- break;
- }
- }
-
- /* Call the appropriate sub-function. */
-
- if (elt_size == 8)
- status = _cairo_xlib_surface_show_glyphs8 (font, operator, g, &key, src, self,
- source_x + attributes.x_offset,
- source_y + attributes.y_offset,
- glyphs, entries, num_glyphs);
- else if (elt_size == 16)
- status = _cairo_xlib_surface_show_glyphs16 (font, operator, g, &key, src, self,
- source_x + attributes.x_offset,
- source_y + attributes.y_offset,
- glyphs, entries, num_glyphs);
- else
- status = _cairo_xlib_surface_show_glyphs32 (font, operator, g, &key, src, self,
- source_x + attributes.x_offset,
- source_y + attributes.y_offset,
- glyphs, entries, num_glyphs);
-
- for (i = 0; i < num_glyphs; ++i)
- _xlib_glyphset_cache_destroy_entry (g, entries[i]);
-
- UNLOCK:
- _unlock_xlib_glyphset_caches ();
-
- if (num_glyphs >= N_STACK_BUF)
- free (entries);
-
- FAIL:
- _cairo_pattern_release_surface (&self->base, &src->base, &attributes);
-
- return status;
-}
diff --git a/src/cairoint.h b/src/cairoint.h
index 50899eca8..90d59b2cb 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -52,11 +53,17 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
+#include <stdarg.h>
+
+#ifdef _MSC_VER
+#define _USE_MATH_DEFINES
+#endif
#include <math.h>
#include <limits.h>
-#include <stdint.h>
+#include <stdio.h>
#include "cairo.h"
+#include <pixman.h>
#if __GNUC__ >= 3 && defined(__ELF__)
# define slim_hidden_proto(name) slim_hidden_proto1(name, INT_##name)
@@ -85,7 +92,7 @@
#define cairo_private
#endif
-/* These macros allow us to deprecate a function by providing an alias
+/* This macro allow us to deprecate a function by providing an alias
for the old function name to the new function name. With this
macro, binary compatibility is preserved. The macro only works on
some platforms --- tough.
@@ -94,14 +101,15 @@
source code so that it will no longer link against the old
symbols. Instead it will give a descriptive error message
indicating that the old function has been deprecated by the new
- function. */
+ function.
+*/
#if __GNUC__ >= 2 && defined(__ELF__)
-# define DEPRECATE(old, new) \
+# define CAIRO_FUNCTION_ALIAS(old, new) \
extern __typeof (new) old \
__asm__ ("" #old) \
__attribute__((__alias__("" #new)))
#else
-# define DEPRECATE(old, new)
+# define CAIRO_FUNCTION_ALIAS(old, new)
#endif
#ifndef __GNUC__
@@ -119,6 +127,12 @@
#define TRUE 1
#endif
+#define ASSERT_NOT_REACHED \
+do { \
+ static const int NOT_REACHED = 0; \
+ assert (NOT_REACHED); \
+} while (0)
+
#include "cairo-wideint.h"
typedef int32_t cairo_fixed_16_16_t;
@@ -164,7 +178,7 @@ typedef struct _cairo_trapezoid {
cairo_line_t left, right;
} cairo_trapezoid_t;
-typedef struct _cairo_rectangle_int {
+typedef struct _cairo_rectangle {
short x, y;
unsigned short width, height;
} cairo_rectangle_t, cairo_glyph_size_t;
@@ -179,45 +193,12 @@ typedef enum cairo_int_status {
#define CAIRO_OK(status) ((status) == CAIRO_STATUS_SUCCESS)
-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_t; /* Don't want 32 bits if we can avoid it. */
-
typedef enum cairo_direction {
CAIRO_DIRECTION_FORWARD,
CAIRO_DIRECTION_REVERSE
} cairo_direction_t;
-#define CAIRO_PATH_BUF_SZ 64
-
-typedef struct _cairo_path_op_buf {
- int num_ops;
- cairo_path_op_t 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_points;
- cairo_point_t points[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_point_t last_move_point;
- cairo_point_t current_point;
- int has_current_point;
-} cairo_path_t;
+typedef struct _cairo_path_fixed cairo_path_fixed_t;
typedef struct _cairo_edge {
cairo_line_t edge;
@@ -302,6 +283,24 @@ _cairo_array_copy_element (cairo_array_t *array, int index, void *dst);
cairo_private int
_cairo_array_num_elements (cairo_array_t *array);
+typedef cairo_array_t cairo_user_data_array_t;
+
+cairo_private void
+_cairo_user_data_array_init (cairo_user_data_array_t *array);
+
+cairo_private void
+_cairo_user_data_array_destroy (cairo_user_data_array_t *array);
+
+cairo_private void *
+_cairo_user_data_array_get_data (cairo_user_data_array_t *array,
+ const cairo_user_data_key_t *key);
+
+cairo_private cairo_status_t
+_cairo_user_data_array_set_data (cairo_user_data_array_t *array,
+ const cairo_user_data_key_t *key,
+ void *user_data,
+ cairo_destroy_func_t destroy);
+
/* cairo_cache.c structures and functions */
typedef struct _cairo_cache_backend {
@@ -404,25 +403,34 @@ _cairo_hash_string (const char *c);
#define CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
#define CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
-typedef struct {
- double matrix[2][2];
-} cairo_font_scale_t;
+typedef struct _cairo_unscaled_font cairo_unscaled_font_t;
-struct _cairo_font_backend;
+typedef struct _cairo_unscaled_font_backend cairo_unscaled_font_backend_t;
+typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t;
+typedef struct _cairo_font_face_backend cairo_font_face_backend_t;
/*
* A cairo_unscaled_font_t is just an opaque handle we use in the
* glyph cache.
*/
-typedef struct {
+struct _cairo_unscaled_font {
+ int refcount;
+ const cairo_unscaled_font_backend_t *backend;
+};
+
+struct _cairo_scaled_font {
int refcount;
- const struct _cairo_font_backend *backend;
-} cairo_unscaled_font_t;
+ cairo_matrix_t font_matrix; /* font space => user space */
+ cairo_matrix_t ctm; /* user space => device space */
+ cairo_matrix_t scale; /* font space => device space */
+ cairo_font_face_t *font_face; /* may be NULL */
+ const cairo_scaled_font_backend_t *backend;
+};
-struct _cairo_font {
+struct _cairo_font_face {
int refcount;
- cairo_font_scale_t scale; /* font space => device space */
- const struct _cairo_font_backend *backend;
+ cairo_user_data_array_t user_data;
+ const cairo_font_face_backend_t *backend;
};
/* cairo_font.c is responsible for a global glyph cache:
@@ -438,7 +446,7 @@ struct _cairo_font {
typedef struct {
cairo_cache_entry_base_t base;
cairo_unscaled_font_t *unscaled;
- cairo_font_scale_t scale;
+ cairo_matrix_t scale; /* translation is ignored */
int flags;
unsigned long index;
} cairo_glyph_cache_key_t;
@@ -471,98 +479,109 @@ _cairo_glyph_cache_keys_equal (void *cache,
/* the font backend interface */
-typedef struct _cairo_font_backend {
- cairo_status_t (*create) (const char *family,
+struct _cairo_unscaled_font_backend {
+ void (*destroy) (void *unscaled_font);
+ cairo_status_t (*create_glyph) (void *unscaled_font,
+ cairo_image_glyph_cache_entry_t *entry);
+};
+
+struct _cairo_scaled_font_backend {
+ cairo_status_t (*create) (const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight,
- cairo_font_scale_t *scale,
- cairo_font_t **font);
-
- void (*destroy_font) (void *font);
- void (*destroy_unscaled_font) (void *font);
-
- cairo_status_t (*font_extents) (void *font,
- cairo_font_extents_t *extents);
-
- cairo_status_t (*text_to_glyphs) (void *font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs);
-
- cairo_status_t (*glyph_extents) (void *font,
- cairo_glyph_t *glyphs,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ cairo_scaled_font_t **font);
+
+ void (*destroy) (void *font);
+
+ cairo_status_t (*font_extents) (void *font,
+ cairo_font_extents_t *extents);
+
+ cairo_status_t (*text_to_glyphs) (void *font,
+ const char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs);
+
+ cairo_status_t (*glyph_extents) (void *font,
+ cairo_glyph_t *glyphs,
int num_glyphs,
- cairo_text_extents_t *extents);
+ cairo_text_extents_t *extents);
- cairo_status_t (*glyph_bbox) (void *font,
- const cairo_glyph_t *glyphs,
+ cairo_status_t (*glyph_bbox) (void *font,
+ const cairo_glyph_t *glyphs,
int num_glyphs,
- cairo_box_t *bbox);
+ cairo_box_t *bbox);
- cairo_status_t (*show_glyphs) (void *font,
+ cairo_status_t (*show_glyphs) (void *font,
cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *surface,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *surface,
int source_x,
int source_y,
int dest_x,
int dest_y,
unsigned int width,
unsigned int height,
- const cairo_glyph_t *glyphs,
+ const cairo_glyph_t *glyphs,
int num_glyphs);
- cairo_status_t (*glyph_path) (void *font,
- cairo_glyph_t *glyphs,
+ cairo_status_t (*glyph_path) (void *font,
+ cairo_glyph_t *glyphs,
int num_glyphs,
- cairo_path_t *path);
- void (*get_glyph_cache_key) (void *font,
- cairo_glyph_cache_key_t *key);
-
- cairo_status_t (*create_glyph) (cairo_image_glyph_cache_entry_t *entry);
+ cairo_path_fixed_t *path);
+ void (*get_glyph_cache_key) (void *font,
+ cairo_glyph_cache_key_t *key);
+};
-} cairo_font_backend_t;
+struct _cairo_font_face_backend {
+ /* The destroy() function is allowed to resurrect the font face
+ * by re-referencing. This is needed for the FreeType backend.
+ */
+ void (*destroy) (void *font_face);
+ cairo_status_t (*create_font) (void *font_face,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ cairo_scaled_font_t **scaled_font);
+};
/* concrete font backends */
-#ifdef CAIRO_HAS_FT_FONT
+#if CAIRO_HAS_FT_FONT
-extern const cairo_private struct _cairo_font_backend cairo_ft_font_backend;
+extern const cairo_private struct _cairo_scaled_font_backend cairo_ft_scaled_font_backend;
#endif
-#ifdef CAIRO_HAS_WIN32_FONT
+#if CAIRO_HAS_WIN32_FONT
-extern const cairo_private struct _cairo_font_backend cairo_win32_font_backend;
+extern const cairo_private struct _cairo_scaled_font_backend cairo_win32_scaled_font_backend;
#endif
-#ifdef CAIRO_HAS_ATSUI_FONT
+#if CAIRO_HAS_ATSUI_FONT
-extern const cairo_private struct _cairo_font_backend cairo_atsui_font_backend;
+extern const cairo_private struct _cairo_scaled_font_backend cairo_atsui_scaled_font_backend;
#endif
typedef struct _cairo_surface_backend {
cairo_surface_t *
(*create_similar) (void *surface,
- cairo_format_t format,
- int drawable,
- int width,
- int height);
+ cairo_format_t format,
+ int drawable,
+ int width,
+ int height);
- void
- (*destroy) (void *surface);
-
- double
- (*pixels_per_inch) (void *surface);
+ cairo_status_t
+ (*finish) (void *surface);
cairo_status_t
- (* acquire_source_image) (void *abstract_surface,
+ (*acquire_source_image) (void *abstract_surface,
cairo_image_surface_t **image_out,
void **image_extra);
void
- (* release_source_image) (void *abstract_surface,
+ (*release_source_image) (void *abstract_surface,
cairo_image_surface_t *image,
void *image_extra);
@@ -587,39 +606,39 @@ typedef struct _cairo_surface_backend {
/* XXX: dst should be the first argument for consistency */
cairo_int_status_t
- (*composite) (cairo_operator_t operator,
+ (*composite) (cairo_operator_t operator,
cairo_pattern_t *src,
cairo_pattern_t *mask,
void *dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height);
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height);
cairo_int_status_t
(*fill_rectangles) (void *surface,
- cairo_operator_t operator,
+ cairo_operator_t operator,
const cairo_color_t *color,
cairo_rectangle_t *rects,
- int num_rects);
+ int num_rects);
/* XXX: dst should be the first argument for consistency */
cairo_int_status_t
- (*composite_trapezoids) (cairo_operator_t operator,
+ (*composite_trapezoids) (cairo_operator_t operator,
cairo_pattern_t *pattern,
void *dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
- int num_traps);
+ int num_traps);
cairo_int_status_t
(*copy_page) (void *surface);
@@ -630,29 +649,47 @@ typedef struct _cairo_surface_backend {
cairo_int_status_t
(*set_clip_region) (void *surface,
pixman_region16_t *region);
+
+ /* Get the extents of the current surface. For many surface types
+ * this will be as simple as { x=0, y=0, width=surface->width,
+ * height=surface->height}.
+ *
+ * This function need not take account of any clipping from
+ * set_clip_region since the generic version of set_clip_region
+ * saves those, and the generic get_clip_extents will only call
+ * into the specific surface->get_extents if there is no current
+ * clip.
+ */
+ cairo_int_status_t
+ (*get_extents) (void *surface,
+ cairo_rectangle_t *rectangle);
+
/*
* This is an optional entry to let the surface manage its own glyph
* resources. If null, the font will be asked to render against this
* surface, using image surfaces as glyphs.
*/
- cairo_status_t
- (*show_glyphs) (cairo_font_t *font,
- cairo_operator_t operator,
+ cairo_int_status_t
+ (*show_glyphs) (cairo_scaled_font_t *font,
+ cairo_operator_t operator,
cairo_pattern_t *pattern,
void *surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
const cairo_glyph_t *glyphs,
- int num_glyphs);
-} cairo_surface_backend_t;
+ int num_glyphs);
-struct _cairo_matrix {
- double m[3][2];
-};
+ cairo_int_status_t
+ (*fill_path) (cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ void *dst,
+ cairo_path_fixed_t *path);
+
+} cairo_surface_backend_t;
typedef struct _cairo_format_masks {
int bpp;
@@ -662,14 +699,26 @@ typedef struct _cairo_format_masks {
unsigned long blue_mask;
} cairo_format_masks_t;
+typedef struct _cairo_surface_save cairo_surface_save_t;
+
struct _cairo_surface {
const cairo_surface_backend_t *backend;
unsigned int ref_count;
+ cairo_bool_t finished;
+ cairo_user_data_array_t user_data;
cairo_matrix_t matrix;
cairo_filter_t filter;
int repeat;
+
+ double device_x_offset;
+ double device_y_offset;
+
+ cairo_surface_save_t *saves; /* Stack of saved states from cairo_surface_begin/end() */
+ int level; /* Number saved states */
+
+ pixman_region16_t *clip_region;
};
struct _cairo_image_surface {
@@ -677,7 +726,7 @@ struct _cairo_image_surface {
/* libic-specific fields */
cairo_format_t format;
- char *data;
+ unsigned char *data;
int owns_data;
int width;
@@ -706,6 +755,12 @@ struct _cairo_color {
unsigned short alpha_short;
};
+typedef enum {
+ CAIRO_STOCK_WHITE,
+ CAIRO_STOCK_BLACK,
+ CAIRO_STOCK_TRANSPARENT
+} cairo_stock_t;
+
#define CAIRO_EXTEND_DEFAULT CAIRO_EXTEND_NONE
#define CAIRO_FILTER_DEFAULT CAIRO_FILTER_BEST
@@ -727,13 +782,11 @@ struct _cairo_pattern {
cairo_matrix_t matrix;
cairo_filter_t filter;
cairo_extend_t extend;
- double alpha;
};
typedef struct _cairo_solid_pattern {
cairo_pattern_t base;
-
- double red, green, blue;
+ cairo_color_t color;
} cairo_solid_pattern_t;
typedef struct _cairo_surface_pattern {
@@ -787,6 +840,7 @@ typedef struct _cairo_surface_attributes {
int x_offset;
int y_offset;
cairo_bool_t acquired;
+ cairo_bool_t clip_saved;
void *extra;
} cairo_surface_attributes_t;
@@ -800,20 +854,20 @@ typedef struct _cairo_traps {
#define CAIRO_FONT_SLANT_DEFAULT CAIRO_FONT_SLANT_NORMAL
#define CAIRO_FONT_WEIGHT_DEFAULT CAIRO_FONT_WEIGHT_NORMAL
-#if defined (CAIRO_HAS_WIN32_FONT)
+#if CAIRO_HAS_WIN32_FONT
#define CAIRO_FONT_FAMILY_DEFAULT "Arial"
-#define CAIRO_FONT_BACKEND_DEFAULT &cairo_win32_font_backend
+#define CAIRO_FONT_BACKEND_DEFAULT &cairo_win32_scaled_font_backend
-#elif defined (CAIRO_HAS_ATSUI_FONT)
+#elif CAIRO_HAS_ATSUI_FONT
#define CAIRO_FONT_FAMILY_DEFAULT "Monaco"
-#define CAIRO_FONT_BACKEND_DEFAULT &cairo_atsui_font_backend
+#define CAIRO_FONT_BACKEND_DEFAULT &cairo_atsui_scaled_font_backend
-#elif defined (CAIRO_HAS_FT_FONT)
+#elif CAIRO_HAS_FT_FONT
#define CAIRO_FONT_FAMILY_DEFAULT "serif"
-#define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_font_backend
+#define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_scaled_font_backend
#endif
@@ -824,7 +878,7 @@ typedef struct _cairo_traps {
#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
-#define CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT 96.0
+#define CAIRO_GSTATE_DEFAULT_FONT_SIZE 10.0
/* Need a name distinct from the cairo_clip function */
typedef struct _cairo_clip_rec {
@@ -833,55 +887,7 @@ typedef struct _cairo_clip_rec {
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;
-
- char *font_family; /* NULL means CAIRO_FONT_FAMILY_DEFAULT; */
- cairo_font_slant_t font_slant;
- cairo_font_weight_t font_weight;
-
- cairo_font_t *font; /* Specific to the current CTM */
-
- cairo_surface_t *surface;
-
- cairo_pattern_t *pattern;
- double alpha;
-
- cairo_clip_rec_t clip;
-
- double pixels_per_inch;
-
- cairo_matrix_t font_matrix;
-
- cairo_matrix_t ctm;
- cairo_matrix_t ctm_inverse;
-
- cairo_path_t path;
-
- cairo_pen_t pen_regular;
-
- struct _cairo_gstate *next;
-} cairo_gstate_t;
-
-struct _cairo {
- unsigned int ref_count;
- cairo_gstate_t *gstate;
- cairo_status_t status;
-};
+typedef struct _cairo_gstate cairo_gstate_t;
typedef struct _cairo_stroke_face {
cairo_point_t ccw;
@@ -920,13 +926,13 @@ _cairo_fixed_integer_floor (cairo_fixed_t f);
cairo_private int
_cairo_fixed_integer_ceil (cairo_fixed_t f);
-
/* cairo_gstate.c */
cairo_private cairo_gstate_t *
-_cairo_gstate_create (void);
+_cairo_gstate_create (cairo_surface_t *target);
cairo_private cairo_status_t
-_cairo_gstate_init (cairo_gstate_t *gstate);
+_cairo_gstate_init (cairo_gstate_t *gstate,
+ cairo_surface_t *target);
cairo_private cairo_status_t
_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other);
@@ -949,68 +955,54 @@ _cairo_gstate_begin_group (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_end_group (cairo_gstate_t *gstate);
-cairo_private cairo_status_t
-_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface);
-
cairo_private cairo_surface_t *
-_cairo_gstate_current_target_surface (cairo_gstate_t *gstate);
+_cairo_gstate_get_target (cairo_gstate_t *gstate);
cairo_private cairo_status_t
-_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern);
+_cairo_gstate_set_source (cairo_gstate_t *gstate, cairo_pattern_t *source);
+
+cairo_status_t
+_cairo_gstate_set_source_solid (cairo_gstate_t *gstate,
+ const cairo_color_t *color);
cairo_private cairo_pattern_t *
-_cairo_gstate_current_pattern (cairo_gstate_t *gstate);
+_cairo_gstate_get_source (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator);
cairo_private cairo_operator_t
-_cairo_gstate_current_operator (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, double blue);
-
-cairo_private cairo_status_t
-_cairo_gstate_current_rgb_color (cairo_gstate_t *gstate,
- double *red,
- double *green,
- double *blue);
+_cairo_gstate_get_operator (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance);
cairo_private double
-_cairo_gstate_current_tolerance (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_alpha (cairo_gstate_t *gstate, double alpha);
-
-cairo_private double
-_cairo_gstate_current_alpha (cairo_gstate_t *gstate);
+_cairo_gstate_get_tolerance (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule);
cairo_private cairo_fill_rule_t
-_cairo_gstate_current_fill_rule (cairo_gstate_t *gstate);
+_cairo_gstate_get_fill_rule (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width);
cairo_private double
-_cairo_gstate_current_line_width (cairo_gstate_t *gstate);
+_cairo_gstate_get_line_width (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap);
cairo_private cairo_line_cap_t
-_cairo_gstate_current_line_cap (cairo_gstate_t *gstate);
+_cairo_gstate_get_line_cap (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join);
cairo_private cairo_line_join_t
-_cairo_gstate_current_line_join (cairo_gstate_t *gstate);
+_cairo_gstate_get_line_join (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, double offset);
@@ -1019,10 +1011,10 @@ cairo_private cairo_status_t
_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit);
cairo_private double
-_cairo_gstate_current_miter_limit (cairo_gstate_t *gstate);
+_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate);
cairo_private void
-_cairo_gstate_current_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix);
+_cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix);
cairo_private cairo_status_t
_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty);
@@ -1034,94 +1026,46 @@ cairo_private cairo_status_t
_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle);
cairo_private cairo_status_t
-_cairo_gstate_concat_matrix (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix);
+_cairo_gstate_transform (cairo_gstate_t *gstate,
+ const cairo_matrix_t *matrix);
cairo_private cairo_status_t
-_cairo_gstate_default_matrix (cairo_gstate_t *gstate);
+_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
+ const cairo_matrix_t *matrix);
cairo_private cairo_status_t
_cairo_gstate_identity_matrix (cairo_gstate_t *gstate);
cairo_private cairo_status_t
-_cairo_gstate_transform_point (cairo_gstate_t *gstate, double *x, double *y);
-
-cairo_private cairo_status_t
-_cairo_gstate_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy);
+_cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y);
cairo_private cairo_status_t
-_cairo_gstate_inverse_transform_point (cairo_gstate_t *gstate, double *x, double *y);
+_cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate, double *dx, double *dy);
cairo_private cairo_status_t
-_cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy);
+_cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y);
cairo_private cairo_status_t
-_cairo_gstate_new_path (cairo_gstate_t *gstate);
+_cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate, double *dx, double *dy);
-cairo_private cairo_status_t
-_cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y);
-
-cairo_private cairo_status_t
-_cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y);
-
-cairo_private cairo_status_t
-_cairo_gstate_curve_to (cairo_gstate_t *gstate,
- double x1, double y1,
- double x2, double y2,
- double x3, double y3);
-
-cairo_private cairo_status_t
-_cairo_gstate_arc (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle1, double angle2);
-
-cairo_private cairo_status_t
-_cairo_gstate_arc_negative (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle1, double angle2);
-
-cairo_private cairo_status_t
-_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy);
-
-cairo_private cairo_status_t
-_cairo_gstate_rel_line_to (cairo_gstate_t *gstate, double dx, double dy);
-
-cairo_private cairo_status_t
-_cairo_gstate_rel_curve_to (cairo_gstate_t *gstate,
- double dx1, double dy1,
- double dx2, double dy2,
- double dx3, double dy3);
-
-/* XXX: NYI
-cairo_private cairo_status_t
-_cairo_gstate_stroke_path (cairo_gstate_t *gstate);
-*/
+cairo_private void
+_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y);
-cairo_private cairo_status_t
-_cairo_gstate_close_path (cairo_gstate_t *gstate);
+cairo_private void
+_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y);
cairo_private cairo_status_t
-_cairo_gstate_current_point (cairo_gstate_t *gstate, double *x, double *y);
+_cairo_gstate_paint (cairo_gstate_t *gstate);
cairo_private cairo_status_t
-_cairo_gstate_interpret_path (cairo_gstate_t *gstate,
- cairo_move_to_func_t *move_to,
- cairo_line_to_func_t *line_to,
- cairo_curve_to_func_t *curve_to,
- cairo_close_path_func_t *close_path,
- void *closure);
+_cairo_gstate_mask (cairo_gstate_t *gstate,
+ cairo_pattern_t *mask);
cairo_private cairo_status_t
-_cairo_gstate_stroke (cairo_gstate_t *gstate);
+_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
cairo_private cairo_status_t
-_cairo_gstate_fill (cairo_gstate_t *gstate);
+_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
cairo_private cairo_status_t
_cairo_gstate_copy_page (cairo_gstate_t *gstate);
@@ -1130,85 +1074,82 @@ cairo_private cairo_status_t
_cairo_gstate_show_page (cairo_gstate_t *gstate);
cairo_private cairo_status_t
-_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
+_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2);
cairo_private cairo_status_t
-_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
+_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2);
cairo_private cairo_status_t
-_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
- double x,
- double y,
- cairo_bool_t *inside_ret);
+_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
+ double x,
+ double y,
+ cairo_bool_t *inside_ret);
cairo_private cairo_status_t
-_cairo_gstate_in_fill (cairo_gstate_t *gstate,
- double x,
- double y,
- cairo_bool_t *inside_ret);
+_cairo_gstate_in_fill (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
+ double x,
+ double y,
+ cairo_bool_t *inside_ret);
cairo_private cairo_status_t
-_cairo_gstate_init_clip (cairo_gstate_t *gstate);
+_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
cairo_private cairo_status_t
-_cairo_gstate_clip (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_restore_external_state (cairo_gstate_t *gstate);
+_cairo_gstate_reset_clip (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_show_surface (cairo_gstate_t *gstate,
cairo_surface_t *surface,
- int width,
- int height);
+ double x,
+ double y,
+ double width,
+ double height);
cairo_private cairo_status_t
-_cairo_gstate_select_font (cairo_gstate_t *gstate,
- const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight);
+_cairo_gstate_select_font_face (cairo_gstate_t *gstate,
+ const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight);
cairo_private cairo_status_t
-_cairo_gstate_scale_font (cairo_gstate_t *gstate,
- double scale);
+_cairo_gstate_set_font_size (cairo_gstate_t *gstate,
+ double size);
-cairo_private void
-_cairo_gstate_current_font_scale (cairo_gstate_t *gstate,
- cairo_font_scale_t *sc);
-
+void
+_cairo_gstate_get_font_matrix (cairo_gstate_t *gstate,
+ cairo_matrix_t *matrix);
+
cairo_private cairo_status_t
-_cairo_gstate_transform_font (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix);
+_cairo_gstate_set_font_matrix (cairo_gstate_t *gstate,
+ const cairo_matrix_t *matrix);
cairo_private cairo_status_t
-_cairo_gstate_current_font (cairo_gstate_t *gstate,
- cairo_font_t **font);
-
-cairo_private void
-_cairo_gstate_set_font_transform (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix);
-
-cairo_private void
-_cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix);
+_cairo_gstate_get_font_face (cairo_gstate_t *gstate,
+ cairo_font_face_t **font_face);
cairo_private cairo_status_t
-_cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
- cairo_font_extents_t *extents);
+_cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
+ cairo_font_extents_t *extents);
cairo_private cairo_status_t
-_cairo_gstate_set_font (cairo_gstate_t *gstate,
- cairo_font_t *font);
+_cairo_gstate_set_font_face (cairo_gstate_t *gstate,
+ cairo_font_face_t *font_face);
cairo_private cairo_status_t
_cairo_gstate_text_to_glyphs (cairo_gstate_t *font,
- const unsigned char *utf8,
+ const char *utf8,
+ double x,
+ double y,
cairo_glyph_t **glyphs,
- int *num_glyphs);
+ int *num_glyphs);
cairo_private cairo_status_t
_cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
@@ -1222,45 +1163,70 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
int num_glyphs);
cairo_private cairo_status_t
-_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
- cairo_glyph_t *glyphs,
- int num_glyphs);
+_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_fixed_t *path);
/* cairo_color.c */
+cairo_private const cairo_color_t *
+_cairo_stock_color (cairo_stock_t stock);
+
+#define CAIRO_COLOR_WHITE _cairo_stock_color (CAIRO_STOCK_WHITE)
+#define CAIRO_COLOR_BLACK _cairo_stock_color (CAIRO_STOCK_BLACK)
+#define CAIRO_COLOR_TRANSPARENT _cairo_stock_color (CAIRO_STOCK_TRANSPARENT)
+
cairo_private void
_cairo_color_init (cairo_color_t *color);
cairo_private void
-_cairo_color_fini (cairo_color_t *color);
+_cairo_color_init_rgb (cairo_color_t *color,
+ double red, double green, double blue);
cairo_private void
-_cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blue);
+_cairo_color_init_rgba (cairo_color_t *color,
+ double red, double green, double blue,
+ double alpha);
cairo_private void
-_cairo_color_get_rgb (const cairo_color_t *color,
- double *red, double *green, double *blue);
+_cairo_color_multiply_alpha (cairo_color_t *color,
+ double alpha);
cairo_private void
-_cairo_color_set_alpha (cairo_color_t *color, double alpha);
+_cairo_color_get_rgba (cairo_color_t *color,
+ double *red,
+ double *green,
+ double *blue,
+ double *alpha);
-/* cairo_font.c */
+cairo_private void
+_cairo_color_get_rgba_premultiplied (cairo_color_t *color,
+ double *red,
+ double *green,
+ double *blue,
+ double *alpha);
-cairo_private cairo_status_t
-_cairo_font_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight,
- cairo_font_scale_t *sc,
- cairo_font_t **font);
+/* cairo-font.c */
+
+cairo_private void
+_cairo_font_face_init (cairo_font_face_t *font_face,
+ const cairo_font_face_backend_t *backend);
+
+cairo_private cairo_font_face_t *
+_cairo_simple_font_face_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight);
cairo_private void
-_cairo_font_init (cairo_font_t *font,
- cairo_font_scale_t *scale,
- const cairo_font_backend_t *backend);
+_cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ const cairo_scaled_font_backend_t *backend);
cairo_private void
-_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
- const struct _cairo_font_backend *backend);
+_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
+ const cairo_unscaled_font_backend_t *backend);
cairo_private void
_cairo_unscaled_font_reference (cairo_unscaled_font_t *font);
@@ -1269,56 +1235,50 @@ cairo_private void
_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font);
cairo_private cairo_status_t
-_cairo_font_font_extents (cairo_font_t *font,
- cairo_font_extents_t *extents);
+_cairo_scaled_font_font_extents (cairo_scaled_font_t *scaled_font,
+ cairo_font_extents_t *extents);
cairo_private cairo_status_t
-_cairo_font_text_to_glyphs (cairo_font_t *font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs);
+_cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
+ const char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs);
cairo_private cairo_status_t
-_cairo_font_glyph_extents (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents);
+_cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents);
cairo_private cairo_status_t
-_cairo_font_glyph_bbox (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox);
+_cairo_scaled_font_glyph_bbox (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox);
cairo_private cairo_status_t
-_cairo_font_show_glyphs (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_pattern_t *source,
- cairo_surface_t *surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int widht,
- unsigned int height,
- cairo_glyph_t *glyphs,
- int num_glyphs);
+_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
+ cairo_operator_t operator,
+ cairo_pattern_t *source,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_glyph_t *glyphs,
+ int num_glyphs);
cairo_private cairo_status_t
-_cairo_font_glyph_path (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path);
-
-cairo_private cairo_status_t
-_cairo_font_glyph_path (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path);
+_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_fixed_t *path);
cairo_private void
-_cairo_font_get_glyph_cache_key (cairo_font_t *font,
- cairo_glyph_cache_key_t *key);
+_cairo_scaled_font_get_glyph_cache_key (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_cache_key_t *key);
/* cairo_hull.c */
cairo_private cairo_status_t
@@ -1326,76 +1286,97 @@ _cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices);
/* cairo_path.c */
cairo_private void
-_cairo_path_init (cairo_path_t *path);
+_cairo_path_fixed_init (cairo_path_fixed_t *path);
cairo_private cairo_status_t
-_cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other);
+_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
+ cairo_path_fixed_t *other);
cairo_private void
-_cairo_path_fini (cairo_path_t *path);
+_cairo_path_fixed_fini (cairo_path_fixed_t *path);
-cairo_private cairo_status_t
-_cairo_path_move_to (cairo_path_t *path, cairo_point_t *point);
+cairo_status_t
+_cairo_path_fixed_move_to (cairo_path_fixed_t *path,
+ cairo_fixed_t x,
+ cairo_fixed_t y);
-cairo_private cairo_status_t
-_cairo_path_rel_move_to (cairo_path_t *path, cairo_slope_t *slope);
+cairo_status_t
+_cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path,
+ cairo_fixed_t dx,
+ cairo_fixed_t dy);
-cairo_private cairo_status_t
-_cairo_path_line_to (cairo_path_t *path, cairo_point_t *point);
+cairo_status_t
+_cairo_path_fixed_line_to (cairo_path_fixed_t *path,
+ cairo_fixed_t x,
+ cairo_fixed_t y);
-cairo_private cairo_status_t
-_cairo_path_rel_line_to (cairo_path_t *path, cairo_slope_t *slope);
+cairo_status_t
+_cairo_path_fixed_rel_line_to (cairo_path_fixed_t *path,
+ cairo_fixed_t dx,
+ cairo_fixed_t dy);
-cairo_private cairo_status_t
-_cairo_path_curve_to (cairo_path_t *path,
- cairo_point_t *p0,
- cairo_point_t *p1,
- cairo_point_t *p2);
+cairo_status_t
+_cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
+ cairo_fixed_t x0, cairo_fixed_t y0,
+ cairo_fixed_t x1, cairo_fixed_t y1,
+ cairo_fixed_t x2, cairo_fixed_t y2);
-cairo_private cairo_status_t
-_cairo_path_rel_curve_to (cairo_path_t *path,
- cairo_slope_t *s0,
- cairo_slope_t *s1,
- cairo_slope_t *s2);
+cairo_status_t
+_cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path,
+ cairo_fixed_t dx0, cairo_fixed_t dy0,
+ cairo_fixed_t dx1, cairo_fixed_t dy1,
+ cairo_fixed_t dx2, cairo_fixed_t dy2);
cairo_private cairo_status_t
-_cairo_path_close_path (cairo_path_t *path);
+_cairo_path_fixed_close_path (cairo_path_fixed_t *path);
-cairo_private cairo_status_t
-_cairo_path_current_point (cairo_path_t *path, cairo_point_t *point);
+cairo_status_t
+_cairo_path_fixed_get_current_point (cairo_path_fixed_t *path,
+ cairo_fixed_t *x,
+ cairo_fixed_t *y);
-typedef cairo_status_t (cairo_path_move_to_func_t) (void *closure,
- cairo_point_t *point);
+typedef cairo_status_t
+(cairo_path_fixed_move_to_func_t) (void *closure,
+ cairo_point_t *point);
-typedef cairo_status_t (cairo_path_line_to_func_t) (void *closure,
- cairo_point_t *point);
+typedef cairo_status_t
+(cairo_path_fixed_line_to_func_t) (void *closure,
+ cairo_point_t *point);
-typedef cairo_status_t (cairo_path_curve_to_func_t) (void *closure,
- cairo_point_t *p0,
- cairo_point_t *p1,
- cairo_point_t *p2);
+typedef cairo_status_t
+(cairo_path_fixed_curve_to_func_t) (void *closure,
+ cairo_point_t *p0,
+ cairo_point_t *p1,
+ cairo_point_t *p2);
-typedef cairo_status_t (cairo_path_close_path_func_t) (void *closure);
+typedef cairo_status_t
+(cairo_path_fixed_close_path_func_t) (void *closure);
cairo_private cairo_status_t
-_cairo_path_interpret (cairo_path_t *path,
- cairo_direction_t dir,
- cairo_path_move_to_func_t *move_to,
- cairo_path_line_to_func_t *line_to,
- cairo_path_curve_to_func_t *curve_to,
- cairo_path_close_path_func_t *close_path,
- void *closure);
+_cairo_path_fixed_interpret (cairo_path_fixed_t *path,
+ cairo_direction_t dir,
+ cairo_path_fixed_move_to_func_t *move_to,
+ cairo_path_fixed_line_to_func_t *line_to,
+ cairo_path_fixed_curve_to_func_t *curve_to,
+ cairo_path_fixed_close_path_func_t *close_path,
+ void *closure);
cairo_private cairo_status_t
-_cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2);
+_cairo_path_fixed_bounds (cairo_path_fixed_t *path,
+ double *x1, double *y1,
+ double *x2, double *y2);
/* cairo_path_fill.c */
cairo_private cairo_status_t
-_cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps);
+_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
+ cairo_gstate_t *gstate,
+ cairo_traps_t *traps);
/* cairo_path_stroke.c */
cairo_private cairo_status_t
-_cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps);
+_cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path,
+ cairo_gstate_t *gstate,
+ cairo_traps_t *traps);
/* cairo_surface.c */
cairo_private cairo_surface_t *
@@ -1406,24 +1387,33 @@ _cairo_surface_create_similar_scratch (cairo_surface_t *other,
int height);
cairo_private cairo_surface_t *
-_cairo_surface_create_similar_solid (cairo_surface_t *other,
- cairo_format_t format,
- int width,
- int height,
- cairo_color_t *color);
+_cairo_surface_create_similar_solid (cairo_surface_t *other,
+ cairo_format_t format,
+ int width,
+ int height,
+ const cairo_color_t *color);
cairo_private void
_cairo_surface_init (cairo_surface_t *surface,
const cairo_surface_backend_t *backend);
cairo_private cairo_status_t
-_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_surface_begin (cairo_surface_t *surface);
+
+cairo_private cairo_status_t
+_cairo_surface_begin_reset_clip (cairo_surface_t *surface);
+
+cairo_private cairo_status_t
+_cairo_surface_end (cairo_surface_t *surface);
+
+cairo_private cairo_status_t
+_cairo_surface_fill_rectangle (cairo_surface_t *surface,
+ cairo_operator_t operator,
+ const cairo_color_t *color,
+ int x,
+ int y,
+ int width,
+ int height);
cairo_private cairo_status_t
_cairo_surface_composite (cairo_operator_t operator,
@@ -1446,6 +1436,12 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
cairo_rectangle_t *rects,
int num_rects);
+cairo_private cairo_int_status_t
+_cairo_surface_fill_path (cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *dst,
+ cairo_path_fixed_t *path);
+
cairo_private cairo_status_t
_cairo_surface_composite_trapezoids (cairo_operator_t operator,
cairo_pattern_t *pattern,
@@ -1465,9 +1461,6 @@ _cairo_surface_copy_page (cairo_surface_t *surface);
cairo_private cairo_status_t
_cairo_surface_show_page (cairo_surface_t *surface);
-cairo_private double
-_cairo_surface_pixels_per_inch (cairo_surface_t *surface);
-
cairo_private cairo_status_t
_cairo_surface_acquire_source_image (cairo_surface_t *surface,
cairo_image_surface_t **image_out,
@@ -1498,13 +1491,32 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
cairo_surface_t **clone_out);
cairo_private cairo_status_t
-_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region);
+_cairo_surface_set_clip_region (cairo_surface_t *surface,
+ pixman_region16_t *region);
+
+cairo_private cairo_status_t
+_cairo_surface_get_clip_extents (cairo_surface_t *surface,
+ cairo_rectangle_t *rectangle);
+
+cairo_private cairo_status_t
+_cairo_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs);
/* cairo_image_surface.c */
cairo_private cairo_image_surface_t *
-_cairo_image_surface_create_with_masks (char *data,
- cairo_format_masks_t *format,
+_cairo_image_surface_create_with_masks (unsigned char *data,
+ cairo_format_masks_t *format,
int width,
int height,
int stride);
@@ -1514,7 +1526,7 @@ _cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface);
cairo_private cairo_status_t
_cairo_image_surface_set_matrix (cairo_image_surface_t *surface,
- cairo_matrix_t *matrix);
+ const cairo_matrix_t *matrix);
cairo_private cairo_status_t
_cairo_image_surface_set_filter (cairo_image_surface_t *surface,
@@ -1605,44 +1617,39 @@ _cairo_spline_fini (cairo_spline_t *spline);
/* cairo_matrix.c */
cairo_private void
-_cairo_matrix_init (cairo_matrix_t *matrix);
+_cairo_matrix_get_affine (const cairo_matrix_t *matrix,
+ double *xx, double *yx,
+ double *xy, double *yy,
+ double *x0, double *y0);
cairo_private void
-_cairo_matrix_fini (cairo_matrix_t *matrix);
-
-cairo_private cairo_status_t
-_cairo_matrix_set_translate (cairo_matrix_t *matrix,
- double tx, double ty);
-
-cairo_private cairo_status_t
-_cairo_matrix_set_scale (cairo_matrix_t *matrix,
- double sx, double sy);
-
-cairo_private cairo_status_t
-_cairo_matrix_set_rotate (cairo_matrix_t *matrix,
- double angle);
-
-cairo_private cairo_status_t
-_cairo_matrix_transform_bounding_box (cairo_matrix_t *matrix,
+_cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
double *x, double *y,
double *width, double *height);
-cairo_private cairo_status_t
-_cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det);
+cairo_private void
+_cairo_matrix_compute_determinant (const cairo_matrix_t *matrix, double *det);
-cairo_private cairo_status_t
-_cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, double *lambda2);
+cairo_private void
+_cairo_matrix_compute_eigen_values (const cairo_matrix_t *matrix,
+ double *lambda1, double *lambda2);
cairo_private cairo_status_t
-_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy, int x_major);
+_cairo_matrix_compute_scale_factors (const cairo_matrix_t *matrix,
+ double *sx, double *sy, int x_major);
cairo_private cairo_bool_t
-_cairo_matrix_is_integer_translation(cairo_matrix_t *matrix, int *itx, int *ity);
+_cairo_matrix_is_integer_translation(const cairo_matrix_t *matrix,
+ int *itx, int *ity);
/* cairo_traps.c */
cairo_private void
_cairo_traps_init (cairo_traps_t *traps);
+cairo_private cairo_status_t
+_cairo_traps_init_box (cairo_traps_t *traps,
+ cairo_box_t *box);
+
cairo_private void
_cairo_traps_fini (cairo_traps_t *traps);
@@ -1663,6 +1670,10 @@ _cairo_traps_contain (cairo_traps_t *traps, double x, double y);
cairo_private void
_cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents);
+cairo_private cairo_status_t
+_cairo_traps_extract_region (cairo_traps_t *tr,
+ pixman_region16_t **region);
+
/* cairo_slope.c */
cairo_private void
_cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b);
@@ -1683,7 +1694,7 @@ _cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other);
cairo_private void
_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
- double red, double green, double blue);
+ const cairo_color_t *color);
cairo_private void
_cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
@@ -1702,21 +1713,14 @@ cairo_private void
_cairo_pattern_fini (cairo_pattern_t *pattern);
cairo_private cairo_pattern_t *
-_cairo_pattern_create_solid (double red, double green, double blue);
-
-cairo_private cairo_status_t
-_cairo_pattern_get_rgb (cairo_pattern_t *pattern,
- double *red, double *green, double *blue);
+_cairo_pattern_create_solid (const cairo_color_t *color);
cairo_private void
-_cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha);
-
-cairo_private void
-_cairo_pattern_transform (cairo_pattern_t *pattern,
- cairo_matrix_t *ctm_inverse);
+_cairo_pattern_transform (cairo_pattern_t *pattern,
+ const cairo_matrix_t *ctm_inverse);
cairo_private cairo_bool_t
-_cairo_pattern_is_opaque (cairo_pattern_t *pattern);
+_cairo_pattern_is_opaque_solid (cairo_pattern_t *pattern);
cairo_private cairo_int_status_t
_cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
@@ -1752,37 +1756,71 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src,
/* cairo_unicode.c */
cairo_private cairo_status_t
-_cairo_utf8_to_ucs4 (const char *str,
- int len,
- uint32_t **result,
- int *items_written);
+_cairo_utf8_to_ucs4 (const unsigned char *str,
+ int len,
+ uint32_t **result,
+ int *items_written);
cairo_private cairo_status_t
-_cairo_utf8_to_utf16 (const char *str,
- int len,
- uint16_t **result,
- int *items_written);
+_cairo_utf8_to_utf16 (const unsigned char *str,
+ int len,
+ uint16_t **result,
+ int *items_written);
+
+/* cairo_output_stream.c */
+
+typedef struct _cairo_output_stream cairo_output_stream_t;
+
+cairo_private cairo_output_stream_t *
+_cairo_output_stream_create (cairo_write_func_t write_func,
+ void *closure);
+
+cairo_private void
+_cairo_output_stream_destroy (cairo_output_stream_t *stream);
+
+cairo_private cairo_status_t
+_cairo_output_stream_write (cairo_output_stream_t *stream,
+ const void *data, size_t length);
+
+cairo_private cairo_status_t
+_cairo_output_stream_vprintf (cairo_output_stream_t *stream,
+ const char *fmt, va_list ap);
+
+cairo_private cairo_status_t
+_cairo_output_stream_printf (cairo_output_stream_t *stream,
+ const char *fmt, ...);
+
+cairo_private long
+_cairo_output_stream_get_position (cairo_output_stream_t *status);
+
+cairo_private cairo_status_t
+_cairo_output_stream_get_status (cairo_output_stream_t *stream);
+
+cairo_output_stream_t *
+_cairo_output_stream_create_for_file (const char *filename);
/* Avoid unnecessary PLT entries. */
+slim_hidden_proto(cairo_get_current_point)
+slim_hidden_proto(cairo_fill_preserve)
+slim_hidden_proto(cairo_clip_preserve)
slim_hidden_proto(cairo_close_path)
-slim_hidden_proto(cairo_matrix_copy)
slim_hidden_proto(cairo_matrix_invert)
slim_hidden_proto(cairo_matrix_multiply)
slim_hidden_proto(cairo_matrix_scale)
-slim_hidden_proto(cairo_matrix_set_affine)
-slim_hidden_proto(cairo_matrix_set_identity)
+slim_hidden_proto(cairo_matrix_init)
+slim_hidden_proto(cairo_matrix_init_identity)
+slim_hidden_proto(cairo_matrix_init_translate)
+slim_hidden_proto(cairo_matrix_init_scale)
+slim_hidden_proto(cairo_matrix_init_rotate)
slim_hidden_proto(cairo_matrix_transform_distance)
slim_hidden_proto(cairo_matrix_transform_point)
slim_hidden_proto(cairo_move_to)
+slim_hidden_proto(cairo_new_path)
slim_hidden_proto(cairo_rel_line_to)
slim_hidden_proto(cairo_restore)
slim_hidden_proto(cairo_save)
-slim_hidden_proto(cairo_set_target_surface)
-slim_hidden_proto(cairo_surface_create_for_image)
+slim_hidden_proto(cairo_stroke_preserve)
slim_hidden_proto(cairo_surface_destroy)
-slim_hidden_proto(cairo_surface_get_matrix)
-slim_hidden_proto(cairo_surface_set_matrix)
-slim_hidden_proto(cairo_surface_set_repeat)
#endif