summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am51
-rw-r--r--src/cairo-array.c134
-rw-r--r--src/cairo-atsui-font.c807
-rw-r--r--src/cairo-atsui.h50
-rw-r--r--src/cairo-cache.c30
-rw-r--r--src/cairo-color.c13
-rw-r--r--src/cairo-features.h.in14
-rw-r--r--src/cairo-fixed.c18
-rw-r--r--src/cairo-font.c16
-rw-r--r--src/cairo-ft-font.c176
-rw-r--r--src/cairo-ft.h62
-rw-r--r--src/cairo-glitz-surface.c233
-rw-r--r--src/cairo-glitz.h53
-rw-r--r--src/cairo-gstate.c490
-rw-r--r--src/cairo-hash.c30
-rw-r--r--src/cairo-image-surface.c6
-rw-r--r--src/cairo-matrix.c73
-rw-r--r--src/cairo-pdf-surface.c2208
-rw-r--r--src/cairo-pdf.h62
-rw-r--r--src/cairo-png.h59
-rw-r--r--src/cairo-polygon.c5
-rw-r--r--src/cairo-ps-surface.c3
-rw-r--r--src/cairo-ps.h63
-rw-r--r--src/cairo-quartz-surface.c392
-rw-r--r--src/cairo-quartz.h58
-rw-r--r--src/cairo-spline.c5
-rw-r--r--src/cairo-wideint.c148
-rw-r--r--src/cairo-wideint.h123
-rw-r--r--src/cairo-xcb-surface.c2
-rw-r--r--src/cairo-xcb.h54
-rw-r--r--src/cairo-xlib-surface.c157
-rw-r--r--src/cairo-xlib.h71
-rw-r--r--src/cairo.c11
-rw-r--r--src/cairo.h153
-rw-r--r--src/cairo_array.c134
-rw-r--r--src/cairo_atsui_font.c807
-rw-r--r--src/cairo_cache.c30
-rw-r--r--src/cairo_color.c13
-rw-r--r--src/cairo_fixed.c18
-rw-r--r--src/cairo_font.c16
-rw-r--r--src/cairo_ft_font.c176
-rw-r--r--src/cairo_gdip_font.cpp665
-rw-r--r--src/cairo_gdip_surface.cpp727
-rw-r--r--src/cairo_glitz_surface.c233
-rw-r--r--src/cairo_gstate.c490
-rw-r--r--src/cairo_image_surface.c6
-rw-r--r--src/cairo_matrix.c73
-rw-r--r--src/cairo_pdf_surface.c2208
-rw-r--r--src/cairo_png_surface.c1
-rw-r--r--src/cairo_polygon.c5
-rw-r--r--src/cairo_ps_surface.c3
-rw-r--r--src/cairo_quartz_surface.c392
-rw-r--r--src/cairo_spline.c5
-rw-r--r--src/cairo_wideint.c148
-rw-r--r--src/cairo_wideint.h272
-rw-r--r--src/cairo_xcb_surface.c2
-rw-r--r--src/cairo_xlib_surface.c157
-rw-r--r--src/cairoint.h570
58 files changed, 11411 insertions, 1570 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 8343cb1ce..d4155e817 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,24 +1,53 @@
+cairoincludedir = $(includedir)/cairo
+cairoinclude_HEADERS = \
+ cairo.h \
+ cairo-atsui.h \
+ cairo-features.h\
+ cairo-ft.h \
+ cairo-glitz.h \
+ cairo-pdf.h \
+ cairo-png.h \
+ cairo-ps.h \
+ cairo-quartz.h \
+ cairo-xcb.h \
+ cairo-xlib.h
+
lib_LTLIBRARIES = libcairo.la
-include_HEADERS = cairo.h cairo-features.h
if CAIRO_HAS_PS_SURFACE
-libcairo_ps_sources = cairo_ps_surface.c
+libcairo_ps_sources = cairo_ps_surface.c cairo-ps.h
+endif
+
+if CAIRO_HAS_PDF_SURFACE
+libcairo_pdf_sources = cairo_pdf_surface.c cairo-pdf.h
endif
if CAIRO_HAS_PNG_SURFACE
-libcairo_png_sources = cairo_png_surface.c
+libcairo_png_sources = cairo_png_surface.c cairo-png.h
endif
if CAIRO_HAS_XLIB_SURFACE
-libcairo_xlib_sources = cairo_xlib_surface.c
+libcairo_xlib_sources = cairo_xlib_surface.c cairo-xlib.h
+endif
+
+if CAIRO_HAS_QUARTZ_SURFACE
+libcairo_quartz_sources = cairo_quartz_surface.c cairo-quartz.h
endif
if CAIRO_HAS_XCB_SURFACE
-libcairo_xcb_sources = cairo_xcb_surface.c
+libcairo_xcb_sources = cairo_xcb_surface.c cairo-xcb.h
endif
if CAIRO_HAS_GLITZ_SURFACE
-libcairo_glitz_sources = cairo_glitz_surface.c
+libcairo_glitz_sources = cairo_glitz_surface.c cairo-glitz.h
+endif
+
+if CAIRO_HAS_ATSUI_FONT
+libcairo_atsui_sources = cairo_atsui_font.c cairo-atsui.h
+endif
+
+if CAIRO_HAS_FT_FONT
+libcairo_ft_sources = cairo_ft_font.c cairo-ft.h
endif
# These names match automake style variable definition conventions so
@@ -31,11 +60,11 @@ XRENDER_LIBS=@XRENDER_LIBS@
libcairo_la_SOURCES = \
cairo.c \
cairo.h \
+ cairo_array.c \
cairo_cache.c \
cairo_color.c \
cairo_fixed.c \
cairo_font.c \
- cairo_ft_font.c \
cairo_gstate.c \
cairo_hull.c \
cairo_image_surface.c \
@@ -52,10 +81,14 @@ libcairo_la_SOURCES = \
cairo_traps.c \
cairo_pattern.c \
cairo_wideint.c \
- cairo_wideint.h \
+ cairo-wideint.h \
+ $(libcairo_atsui_sources)\
+ $(libcairo_ft_sources)\
$(libcairo_ps_sources) \
+ $(libcairo_pdf_sources) \
$(libcairo_png_sources) \
$(libcairo_xlib_sources)\
+ $(libcairo_quartz_sources)\
$(libcairo_xcb_sources) \
$(libcairo_glitz_sources)\
cairoint.h
@@ -64,4 +97,4 @@ libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined
INCLUDES = -I$(srcdir) $(CAIRO_CFLAGS)
-libcairo_la_LIBADD = $(CAIRO_LIBS) -lm
+libcairo_la_LIBADD = $(CAIRO_LIBS)
diff --git a/src/cairo-array.c b/src/cairo-array.c
new file mode 100644
index 000000000..2b1cf9d61
--- /dev/null
+++ b/src/cairo-array.c
@@ -0,0 +1,134 @@
+/* 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
new file mode 100644
index 000000000..52cfc6bd8
--- /dev/null
+++ b/src/cairo-atsui-font.c
@@ -0,0 +1,807 @@
+/* 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-atsui.h b/src/cairo-atsui.h
new file mode 100644
index 000000000..94b30432a
--- /dev/null
+++ b/src/cairo-atsui.h
@@ -0,0 +1,50 @@
+/* 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 <cairo.h>
+
+#ifndef CAIRO_ATSUI_H
+#define CAIRO_ATSUI_H
+#ifdef CAIRO_HAS_ATSUI_FONT
+
+/* ATSUI platform-specific font interface */
+
+#include <Carbon/Carbon.h>
+
+cairo_font_t *
+cairo_atsui_font_create(ATSUStyle style);
+
+#endif /* CAIRO_HAS_ATSUI_FONT */
+#endif /* CAIRO_ATSUI_H */
diff --git a/src/cairo-cache.c b/src/cairo-cache.c
index a33d69a04..b097b609b 100644
--- a/src/cairo-cache.c
+++ b/src/cairo-cache.c
@@ -43,7 +43,7 @@
* Packard.
*/
-static cairo_cache_arrangement_t cache_arrangements [] = {
+static const cairo_cache_arrangement_t cache_arrangements [] = {
{ 16, 43, 41 },
{ 32, 73, 71 },
{ 64, 151, 149 },
@@ -114,7 +114,6 @@ static cairo_cache_arrangement_t cache_arrangements [] = {
(!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i)))))
#ifdef CAIRO_DO_SANITY_CHECKING
-#include <assert.h>
static void
_cache_sane_state (cairo_cache_t *cache)
{
@@ -122,13 +121,12 @@ _cache_sane_state (cairo_cache_t *cache)
assert (cache->entries != NULL);
assert (cache->backend != NULL);
assert (cache->arrangement != NULL);
- assert (cache->refcount > 0);
- assert (cache->used_memory <= cache->max_memory);
+ /* 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)
-#define assert(x)
#endif
static void
@@ -140,7 +138,7 @@ _entry_destroy (cairo_cache_t *cache, unsigned long i)
{
cairo_cache_entry_base_t *entry = cache->entries[i];
assert(cache->live_entries > 0);
- assert(cache->used_memory > entry->memory);
+ assert(cache->used_memory >= entry->memory);
cache->live_entries--;
cache->used_memory -= entry->memory;
@@ -183,10 +181,12 @@ _cache_lookup (cairo_cache_t *cache,
if (predicate != NULL)
{
/* We are looking up an exact entry. */
- if (*probe != NULL
- && *probe != DEAD_ENTRY
- && (*probe)->hashcode == hash
- && predicate (cache, key, *probe))
+ 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
@@ -230,8 +230,7 @@ _find_exact_live_entry_for (cairo_cache_t *cache,
return _cache_lookup (cache, key, cache->backend->keys_equal);
}
-
-static cairo_cache_arrangement_t *
+static const cairo_cache_arrangement_t *
_find_cache_arrangement (unsigned long proposed_size)
{
unsigned long idx;
@@ -302,7 +301,7 @@ _cairo_cache_init (cairo_cache_t *cache,
const cairo_cache_backend_t *backend,
unsigned long max_memory)
{
- assert(backend != NULL);
+ assert (backend != NULL);
if (cache != NULL){
cache->arrangement = &cache_arrangements[0];
@@ -342,7 +341,7 @@ _cairo_cache_destroy (cairo_cache_t *cache)
_cache_sane_state (cache);
- if (cache->refcount-- > 0)
+ if (--cache->refcount > 0)
return;
for (i = 0; i < cache->arrangement->size; ++i) {
@@ -419,7 +418,8 @@ _cairo_cache_lookup (cairo_cache_t *cache,
_entry_destroy (cache, idx);
}
- assert(cache->max_memory >= (cache->used_memory + new_entry->memory));
+ /* 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);
diff --git a/src/cairo-color.c b/src/cairo-color.c
index 2fe793ac8..899b1e3d5 100644
--- a/src/cairo-color.c
+++ b/src/cairo-color.c
@@ -36,7 +36,7 @@
#include "cairoint.h"
-static cairo_color_t const CAIRO_COLOR_DEFAULT = {
+static cairo_color_t const CAIRO_COLOR_WHITE = {
1.0, 1.0, 1.0, 1.0,
0xffff, 0xffff, 0xffff, 0xffff
};
@@ -47,7 +47,7 @@ _cairo_color_compute_shorts (cairo_color_t *color);
void
_cairo_color_init (cairo_color_t *color)
{
- *color = CAIRO_COLOR_DEFAULT;
+ *color = CAIRO_COLOR_WHITE;
}
void
@@ -69,9 +69,12 @@ _cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blu
void
_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue)
{
- *red = color->red;
- *green = color->green;
- *blue = color->blue;
+ if (red)
+ *red = color->red;
+ if (green)
+ *green = color->green;
+ if (blue)
+ *blue = color->blue;
}
void
diff --git a/src/cairo-features.h.in b/src/cairo-features.h.in
index 632ad8d72..e2a62ba66 100644
--- a/src/cairo-features.h.in
+++ b/src/cairo-features.h.in
@@ -1,6 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2003 University of Southern California
+ * 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
@@ -34,19 +34,27 @@
* Carl Worth <cworth@east.isi.edu>
*/
-#ifndef _CAIRO_CONFIG_H_
-#define _CAIRO_CONFIG_H_
+#ifndef CAIRO_FEATURES_H
+#define CAIRO_FEATURES_H
#define @PS_SURFACE_FEATURE@
+#define @PDF_SURFACE_FEATURE@
+
#define @PNG_SURFACE_FEATURE@
#define @XLIB_SURFACE_FEATURE@
+#define @QUARTZ_SURFACE_FEATURE@
+
#define @XCB_SURFACE_FEATURE@
#define @GLITZ_SURFACE_FEATURE@
+#define @FT_FONT_FEATURE@
+
+#define @ATSUI_FONT_FEATURE@
+
#define @SANITY_CHECKING_FEATURE@
#endif
diff --git a/src/cairo-fixed.c b/src/cairo-fixed.c
index 32368d7fc..ee31718ef 100644
--- a/src/cairo-fixed.c
+++ b/src/cairo-fixed.c
@@ -71,3 +71,21 @@ _cairo_fixed_integer_part (cairo_fixed_t f)
{
return f >> 16;
}
+
+int
+_cairo_fixed_integer_floor (cairo_fixed_t f)
+{
+ if (f >= 0)
+ return f >> 16;
+ else
+ return -((-f - 1) >> 16) - 1;
+}
+
+int
+_cairo_fixed_integer_ceil (cairo_fixed_t f)
+{
+ if (f >= 0)
+ return ((f - 1)>>16) + 1;
+ else
+ return - (-f >> 16);
+}
diff --git a/src/cairo-font.c b/src/cairo-font.c
index 5ad9f0417..f5fc0e981 100644
--- a/src/cairo-font.c
+++ b/src/cairo-font.c
@@ -36,7 +36,6 @@
#include "cairoint.h"
-
/* First we implement a global font cache for named fonts. */
typedef struct {
@@ -54,9 +53,9 @@ typedef struct {
static unsigned long
_font_cache_hash (void *cache, void *key)
{
+ unsigned long hash;
cairo_font_cache_key_t *in;
in = (cairo_font_cache_key_t *) key;
- unsigned long hash;
/* 1607 and 1451 are just a couple random primes. */
hash = _cairo_hash_string (in->family);
@@ -86,12 +85,11 @@ _font_cache_create_entry (void *cache,
void *key,
void **return_value)
{
+ const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
cairo_font_cache_key_t *k;
cairo_font_cache_entry_t *entry;
k = (cairo_font_cache_key_t *) key;
- const struct cairo_font_backend *backend = CAIRO_FONT_BACKEND_DEFAULT;
-
/* XXX: The current freetype backend may return NULL, (for example
* if no fonts are installed), but I would like to guarantee that
* the toy API always returns at least *some* font, so I would
@@ -145,7 +143,7 @@ _font_cache_destroy_cache (void *cache)
free (cache);
}
-const struct cairo_cache_backend cairo_font_cache_backend = {
+static const cairo_cache_backend_t cairo_font_cache_backend = {
_font_cache_hash,
_font_cache_keys_equal,
_font_cache_create_entry,
@@ -153,7 +151,6 @@ const struct cairo_cache_backend cairo_font_cache_backend = {
_font_cache_destroy_cache
};
-
static void
_lock_global_font_cache (void)
{
@@ -239,8 +236,8 @@ _cairo_font_init (cairo_font_t *scaled,
}
cairo_status_t
-_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_font_backend_t *backend)
{
font->refcount = 1;
font->backend = backend;
@@ -476,7 +473,7 @@ _image_glyph_cache_destroy_cache (void *cache)
free (cache);
}
-const cairo_cache_backend_t cairo_image_cache_backend = {
+static const cairo_cache_backend_t cairo_image_cache_backend = {
_cairo_glyph_cache_hash,
_cairo_glyph_cache_keys_equal,
_image_glyph_cache_create_entry,
@@ -484,7 +481,6 @@ const cairo_cache_backend_t cairo_image_cache_backend = {
_image_glyph_cache_destroy_cache
};
-
void
_cairo_lock_global_image_glyph_cache()
{
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index f757db09c..b928b04fc 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -23,6 +23,8 @@
*/
#include "cairoint.h"
+#include "cairo-ft.h"
+
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
@@ -50,6 +52,16 @@ typedef struct {
} ft_font_val_t;
+/*
+ * 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;
+
static ft_font_val_t *
_create_from_face (FT_Face face, int owns_face)
{
@@ -246,7 +258,7 @@ _ft_font_cache_destroy_cache (void *cache)
free (fc);
}
-const struct cairo_cache_backend _ft_font_cache_backend = {
+static const cairo_cache_backend_t _ft_font_cache_backend = {
_ft_font_cache_hash,
_ft_font_cache_keys_equal,
_ft_font_cache_create_entry,
@@ -254,7 +266,6 @@ const struct cairo_cache_backend _ft_font_cache_backend = {
_ft_font_cache_destroy_cache
};
-
static ft_cache_t *_global_ft_cache = NULL;
static void
@@ -297,7 +308,7 @@ _get_global_ft_cache (void)
/* implement the backend interface */
-const struct cairo_font_backend cairo_ft_font_backend;
+const cairo_font_backend_t cairo_ft_font_backend;
static cairo_unscaled_font_t *
_cairo_ft_font_create (const char *family,
@@ -402,10 +413,10 @@ _cairo_ft_font_destroy (void *abstract_font)
static void
_utf8_to_ucs4 (char const *utf8,
FT_ULong **ucs4,
- size_t *nchars)
+ int *nchars)
{
int len = 0, step = 0;
- size_t n = 0, alloc = 0;
+ int n = 0, alloc = 0;
FcChar32 u = 0;
if (utf8 == NULL || ucs4 == NULL || nchars == NULL)
@@ -433,11 +444,67 @@ _utf8_to_ucs4 (char const *utf8,
*nchars = n;
}
+/*
+ * Split a matrix into the component pieces of scale and shape
+ */
+
+static void
+_cairo_ft_font_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);
+}
+
+/*
+ * Set the font transformation
+ */
+
+static void
+_cairo_ft_font_install_transform (ft_font_transform_t *sf, FT_Face face)
+{
+ FT_Matrix mat;
+
+ 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(face, &mat, NULL);
+
+ FT_Set_Char_Size(face,
+ (FT_F26Dot6) (sf->x_scale * 64.0),
+ (FT_F26Dot6) (sf->y_scale * 64.0),
+ 0, 0);
+}
+
static void
_install_font_scale (cairo_font_scale_t *sc, FT_Face face)
{
cairo_matrix_t normalized;
- double scale_x, scale_y;
+ double x_scale, y_scale;
double xx, xy, yx, yy, tx, ty;
FT_Matrix mat;
@@ -455,8 +522,9 @@ _install_font_scale (cairo_font_scale_t *sc, FT_Face face)
sc->matrix[1][1],
0, 0);
- _cairo_matrix_compute_scale_factors (&normalized, &scale_x, &scale_y);
- cairo_matrix_scale (&normalized, 1.0 / scale_x, 1.0 / scale_y);
+ _cairo_matrix_compute_scale_factors (&normalized, &x_scale, &y_scale,
+ /* XXX */ 1);
+ cairo_matrix_scale (&normalized, 1.0 / x_scale, 1.0 / y_scale);
cairo_matrix_get_affine (&normalized,
&xx /* 00 */ , &yx /* 01 */,
&xy /* 10 */, &yy /* 11 */,
@@ -470,8 +538,8 @@ _install_font_scale (cairo_font_scale_t *sc, FT_Face face)
FT_Set_Transform(face, &mat, NULL);
FT_Set_Pixel_Sizes(face,
- (FT_UInt) scale_x,
- (FT_UInt) scale_y);
+ (FT_UInt) x_scale,
+ (FT_UInt) y_scale);
}
static cairo_status_t
@@ -481,6 +549,9 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
cairo_glyph_t **glyphs,
int *nglyphs)
{
+ double x = 0., y = 0.;
+ size_t i;
+ FT_ULong *ucs4 = NULL;
cairo_ft_font_t *font = abstract_font;
FT_Face face = font->val->face;
cairo_glyph_cache_key_t key;
@@ -490,10 +561,6 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
key.unscaled = &font->base;
key.scale = *sc;
- double x = 0., y = 0.;
- size_t i;
- FT_ULong *ucs4 = NULL;
-
_utf8_to_ucs4 (utf8, &ucs4, nglyphs);
if (ucs4 == NULL)
@@ -527,7 +594,7 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
continue;
x += val->extents.x_advance;
- y -= val->extents.y_advance;
+ y += val->extents.y_advance;
}
_cairo_unlock_global_image_glyph_cache ();
@@ -544,13 +611,19 @@ _cairo_ft_font_font_extents (void *abstract_font,
cairo_ft_font_t *font = abstract_font;
FT_Face face = font->val->face;
FT_Size_Metrics *metrics = &face->size->metrics;
+ ft_font_transform_t sf;
- _install_font_scale (sc, face);
+ _cairo_ft_font_compute_transform (&sf, sc);
+ _cairo_ft_font_install_transform (&sf, face);
- extents->ascent = DOUBLE_FROM_26_6(metrics->ascender);
- extents->descent = DOUBLE_FROM_26_6(metrics->descender);
- extents->height = DOUBLE_FROM_26_6(metrics->height);
- extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance);
+ /*
+ * Get to unscaled metrics so that the upper level can get back to
+ * user space
+ */
+ extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / sf.y_scale;
+ extents->descent = DOUBLE_FROM_26_6(metrics->descender) / sf.y_scale;
+ extents->height = DOUBLE_FROM_26_6(metrics->height) / sf.y_scale;
+ extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / sf.x_scale;
/* FIXME: this doesn't do vertical layout atm. */
extents->max_y_advance = 0.0;
@@ -614,7 +687,7 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
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_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;
@@ -635,12 +708,12 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
}
_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_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 + 0 - origin.y;
+ extents->y_advance = glyphs[i-1].y + (img == NULL ? 0 : img->extents.y_advance) - origin.y;
return CAIRO_STATUS_SUCCESS;
}
@@ -688,7 +761,7 @@ _cairo_ft_font_glyph_bbox (void *abstract_font,
continue;
x1 = _cairo_fixed_from_double (glyphs[i].x + img->size.x);
- y1 = _cairo_fixed_from_double (glyphs[i].y - img->size.y);
+ 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);
@@ -763,10 +836,10 @@ _cairo_ft_font_show_glyphs (void *abstract_font,
&(img->image->base),
surface,
source_x + x + img->size.x,
- source_y + y - img->size.y,
+ source_y + y + img->size.y,
0, 0,
x + img->size.x,
- y - img->size.y,
+ y + img->size.y,
(double) img->size.width,
(double) img->size.height);
@@ -919,21 +992,39 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
FT_BBox cbox;
FT_Bitmap bitmap;
FT_Glyph_Metrics *metrics;
+ ft_font_transform_t sf;
glyphslot = font->val->face->glyph;
metrics = &glyphslot->metrics;
- _install_font_scale (&val->key.scale, font->val->face);
+ _cairo_ft_font_compute_transform (&sf, &val->key.scale);
+ _cairo_ft_font_install_transform (&sf, font->val->face);
if (FT_Load_Glyph (font->val->face, val->key.index, FT_LOAD_DEFAULT) != 0)
return CAIRO_STATUS_NO_MEMORY;
- val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX);
- val->extents.y_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingY);
- val->extents.width = DOUBLE_FROM_26_6 (metrics->width);
- val->extents.height = DOUBLE_FROM_26_6 (metrics->height);
- val->extents.x_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->advance.x);
- val->extents.y_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->advance.y);
+ /*
+ * 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) / sf.x_scale;
+ val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / sf.y_scale;
+
+ val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / sf.x_scale;
+ val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / sf.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 (font->val->face->glyph->metrics.horiAdvance) / sf.x_scale;
+ val->extents.y_advance = 0 / sf.y_scale;
outline = &glyphslot->outline;
@@ -982,16 +1073,21 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
_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);
+ val->size.x = (short) (cbox.xMin >> 6);
+ val->size.y = - (short) (cbox.yMax >> 6);
return CAIRO_STATUS_SUCCESS;
}
-const struct cairo_font_backend cairo_ft_font_backend = {
+const cairo_font_backend_t cairo_ft_font_backend = {
_cairo_ft_font_create,
_cairo_ft_font_destroy,
_cairo_ft_font_font_extents,
diff --git a/src/cairo-ft.h b/src/cairo-ft.h
new file mode 100644
index 000000000..57d439ab2
--- /dev/null
+++ b/src/cairo-ft.h
@@ -0,0 +1,62 @@
+/* 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@isi.edu>
+ */
+
+#include <cairo.h>
+
+#ifndef CAIRO_FT_H
+#define CAIRO_FT_H
+#ifdef CAIRO_HAS_FT_FONT
+
+/* Fontconfig/Freetype platform-specific font interface */
+
+#include <fontconfig/fontconfig.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+cairo_font_t *
+cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern);
+
+cairo_font_t *
+cairo_ft_font_create_for_ft_face (FT_Face face);
+
+FT_Face
+cairo_ft_font_face (cairo_font_t *ft_font);
+
+FcPattern *
+cairo_ft_font_pattern (cairo_font_t *ft_font);
+
+#endif /* CAIRO_HAS_FT_FONT */
+#endif /* CAIRO_FT_H */
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 21e889204..69fc82f2e 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -25,6 +25,7 @@
*/
#include "cairoint.h"
+#include "cairo-glitz.h"
#define GLITZ_FIXED_TO_FLOAT(f) \
(((glitz_float_t) (f)) / 65536)
@@ -52,8 +53,6 @@ cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface)
if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
return;
- glitz_surface_reference (surface);
-
crsurface = cairo_glitz_surface_create (surface);
if (crsurface == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
@@ -65,10 +64,9 @@ cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface)
cairo_surface_destroy (crsurface);
}
-typedef struct cairo_glitz_surface {
+typedef struct _cairo_glitz_surface {
cairo_surface_t base;
- unsigned long features;
glitz_surface_t *surface;
glitz_format_t *format;
@@ -119,21 +117,29 @@ _cairo_glitz_surface_get_image (void *abstract_surface)
width = glitz_surface_get_width (surface->surface);
height = glitz_surface_get_height (surface->surface);
- if (surface->format->red_size > 0) {
+ 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;
-
- if (surface->format->alpha_size > 0)
- format.alpha_mask = 0xff000000;
- else
- format.alpha_mask = 0x0;
-
+ format.alpha_mask = 0xff000000;
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;
}
pf.masks.bpp = format.bpp;
@@ -306,8 +312,6 @@ _glitz_operator (cairo_operator_t op)
return GLITZ_OPERATOR_XOR;
case CAIRO_OPERATOR_ADD:
return GLITZ_OPERATOR_ADD;
- case CAIRO_OPERATOR_SATURATE:
- return GLITZ_OPERATOR_SATURATE;
case CAIRO_OPERATOR_OVER:
default:
return GLITZ_OPERATOR_OVER;
@@ -319,14 +323,17 @@ _glitz_surface_create_solid (glitz_surface_t *other,
glitz_format_name_t format_name,
glitz_color_t *color)
{
- glitz_surface_t *surface;
+ glitz_drawable_t *drawable;
glitz_format_t *format;
+ glitz_surface_t *surface;
+
+ drawable = glitz_surface_get_drawable (other);
- format = glitz_surface_find_similar_standard_format (other, format_name);
+ format = glitz_find_standard_format (drawable, format_name);
if (format == NULL)
return NULL;
- surface = glitz_surface_create_similar (other, format, 1, 1);
+ surface = glitz_surface_create (drawable, format, 1, 1);
if (surface == NULL)
return NULL;
@@ -337,70 +344,126 @@ _glitz_surface_create_solid (glitz_surface_t *other,
return surface;
}
+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;
+ glitz_pbuffer_attributes_t attributes;
+ 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;
+
+ attributes.width = glitz_surface_get_width (surface);
+ attributes.height = glitz_surface_get_height (surface);
+ mask = GLITZ_PBUFFER_WIDTH_MASK | GLITZ_PBUFFER_HEIGHT_MASK;
+
+ pbuffer = glitz_create_pbuffer_drawable (drawable, dformat,
+ &attributes, mask);
+ if (!pbuffer)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (glitz_drawable_get_width (pbuffer) < attributes.width ||
+ glitz_drawable_get_height (pbuffer) < attributes.height) {
+ glitz_drawable_destroy (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;
+}
+
+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 drawable,
+ int draw,
int width,
int height)
{
cairo_glitz_surface_t *src = abstract_src;
- glitz_surface_t *surface;
cairo_surface_t *crsurface;
- glitz_format_t *glitz_format;
- glitz_format_t templ;
- unsigned long mask;
+ glitz_drawable_t *drawable;
+ glitz_surface_t *surface;
+ glitz_format_t *gformat;
+
+ drawable = glitz_surface_get_drawable (src->surface);
- templ.read.offscreen = 1;
- mask = GLITZ_FORMAT_READ_OFFSCREEN_MASK;
+ gformat = glitz_find_standard_format (drawable, _glitz_format (format));
+ if (gformat == NULL)
+ return NULL;
- if (drawable) {
- templ.draw.offscreen = 1;
- if (src->features & GLITZ_FEATURE_OFFSCREEN_MULTISAMPLE_MASK) {
- templ.multisample.samples = src->format->multisample.samples;
- mask |= GLITZ_FORMAT_MULTISAMPLE_SAMPLES_MASK;
- }
- } else
- templ.draw.offscreen = 0;
-
- mask |= GLITZ_FORMAT_DRAW_OFFSCREEN_MASK;
-
- switch (format) {
- case CAIRO_FORMAT_A1:
- case CAIRO_FORMAT_A8:
- templ.alpha_size = 8;
- mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
- break;
- case CAIRO_FORMAT_RGB24:
- templ.red_size = 8;
- mask |= GLITZ_FORMAT_RED_SIZE_MASK;
- break;
- case CAIRO_FORMAT_ARGB32:
- default:
- templ.alpha_size = templ.red_size = 8;
- mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
- mask |= GLITZ_FORMAT_RED_SIZE_MASK;
- break;
- }
-
- glitz_format =
- glitz_surface_find_similar_format (src->surface, mask, &templ, 0);
- if (glitz_format == NULL) {
- mask &= ~GLITZ_FORMAT_DRAW_OFFSCREEN_MASK;
- glitz_format =
- glitz_surface_find_similar_format (src->surface, mask, &templ, 0);
- if (glitz_format == NULL)
- return NULL;
- }
-
- surface = glitz_surface_create_similar (src->surface, glitz_format,
- width, height);
+ surface = glitz_surface_create (drawable, gformat, width, height);
if (surface == NULL)
return NULL;
crsurface = cairo_glitz_surface_create (surface);
- if (crsurface == NULL)
- glitz_surface_destroy (surface);
+
+ glitz_surface_destroy (surface);
return crsurface;
}
@@ -449,6 +512,9 @@ _glitz_composite (glitz_operator_t op,
glitz_buffer_t *geometry,
glitz_geometry_format_t *format)
{
+ if (_glitz_ensure_target (dst))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (glitz_surface_get_status (dst))
return CAIRO_STATUS_NO_TARGET_SURFACE;
@@ -494,6 +560,9 @@ _cairo_glitz_surface_composite (cairo_operator_t op,
cairo_glitz_surface_t *mask_clone = NULL;
cairo_int_status_t status;
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (generic_src->backend != dst->base.backend) {
src_clone = _cairo_glitz_surface_clone_similar (dst, generic_src,
CAIRO_FORMAT_ARGB32);
@@ -540,6 +609,9 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
{
cairo_glitz_surface_t *dst = abstract_dst;
glitz_color_t glitz_color;
+
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
glitz_color.red = color->red_short;
glitz_color.green = color->green_short;
@@ -613,9 +685,16 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
free (data);
return status;
- } else
+ } else {
+ if (glitz_surface_get_width (dst->surface) != 1 ||
+ glitz_surface_get_height (dst->surface) != 1) {
+ if (_glitz_ensure_target (dst->surface))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
glitz_set_rectangles (dst->surface, &glitz_color,
(glitz_rectangle_t *) rects, n_rects);
+ }
return CAIRO_STATUS_SUCCESS;
}
@@ -639,6 +718,9 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
int x_dst, y_dst, x_rel, y_rel, width, height;
void *data;
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (generic_src->backend != dst->base.backend)
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -764,10 +846,13 @@ _cairo_glitz_surface_create_pattern (void *abstract_dst,
break;
/* fall-through */
case CAIRO_PATTERN_LINEAR: {
+ glitz_drawable_t *drawable;
glitz_fixed16_16_t *params;
int i, n_params;
- if (!(dst->features & GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK))
+ 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)
@@ -885,7 +970,7 @@ _cairo_glitz_surface_set_clip_region (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static const struct cairo_surface_backend cairo_glitz_surface_backend = {
+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,
@@ -918,8 +1003,8 @@ cairo_glitz_surface_create (glitz_surface_t *surface)
_cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend);
+ glitz_surface_reference (surface);
crsurface->surface = surface;
- crsurface->features = glitz_surface_get_features (surface);
crsurface->format = glitz_surface_get_format (surface);
_cairo_pattern_init (&crsurface->pattern);
diff --git a/src/cairo-glitz.h b/src/cairo-glitz.h
new file mode 100644
index 000000000..350d10233
--- /dev/null
+++ b/src/cairo-glitz.h
@@ -0,0 +1,53 @@
+/* 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@isi.edu>
+ */
+
+#include <cairo.h>
+
+#ifndef CAIRO_GLITZ_H
+#define CAIRO_GLITZ_H
+#ifdef CAIRO_HAS_GLITZ_SURFACE
+
+#include <glitz.h>
+
+void
+cairo_set_target_glitz (cairo_t *cr,
+ glitz_surface_t *surface);
+
+cairo_surface_t *
+cairo_glitz_surface_create (glitz_surface_t *surface);
+
+#endif /* CAIRO_HAS_GLITZ_SURFACE */
+#endif /* CAIRO_GLITZ_H */
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 9f9de69e1..e855a7a66 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -86,7 +86,7 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
gstate->clip.region = NULL;
gstate->clip.surface = NULL;
- gstate->pattern = _cairo_pattern_create_solid (1.0, 1.0, 1.0);
+ gstate->pattern = _cairo_pattern_create_solid (0.0, 0.0, 0.0);
gstate->alpha = 1.0;
gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT;
@@ -1096,8 +1096,10 @@ _cairo_gstate_current_point (cairo_gstate_t *gstate, double *x_ret, double *y_re
cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y);
}
- *x_ret = x;
- *y_ret = y;
+ if (x_ret)
+ *x_ret = x;
+ if (y_ret)
+ *y_ret = y;
return CAIRO_STATUS_SUCCESS;
}
@@ -1363,6 +1365,54 @@ BAIL:
return status;
}
+static cairo_status_t
+_calculate_region_for_intermediate_clip_surface (pixman_region16_t *out,
+ cairo_box_t *extents,
+ cairo_clip_rec_t *clip_rect)
+{
+ cairo_status_t status;
+ pixman_region16_t *extents_region, *clip_region;
+ pixman_box16_t clip_box, pixman_extents;
+
+ pixman_extents.x1 = _cairo_fixed_integer_floor (extents->p1.x);
+ pixman_extents.y1 = _cairo_fixed_integer_floor (extents->p1.y);
+ pixman_extents.x2 = _cairo_fixed_integer_ceil (extents->p2.x);
+ pixman_extents.y2 = _cairo_fixed_integer_ceil (extents->p2.y);
+ extents_region = pixman_region_create_simple (&pixman_extents);
+ if (extents_region == NULL)
+ {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL0;
+ }
+
+ clip_box.x1 = clip_rect->x;
+ clip_box.y1 = clip_rect->y;
+ clip_box.x2 = clip_rect->x + clip_rect->width;
+ clip_box.y2 = clip_rect->y + clip_rect->height;
+ clip_region = pixman_region_create_simple (&clip_box);
+ if (clip_region == NULL)
+ {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL1;
+ }
+
+ if (pixman_region_intersect (out,
+ extents_region,
+ clip_region)
+ == PIXMAN_REGION_STATUS_FAILURE)
+ status = CAIRO_STATUS_NO_MEMORY;
+ else
+ status = CAIRO_STATUS_SUCCESS;
+
+ pixman_region_destroy (extents_region);
+ BAIL1:
+ pixman_region_destroy (clip_region);
+
+ BAIL0:
+ return status;
+}
+
+
/* Warning: This call modifies the coordinates of traps */
static cairo_status_t
_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
@@ -1385,25 +1435,38 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
int i;
cairo_surface_t *intermediate;
cairo_color_t empty_color;
+ pixman_box16_t *draw_extents;
+ pixman_region16_t *draw_region;
- _cairo_color_init (&empty_color);
- _cairo_color_set_alpha (&empty_color, 0.);
- intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
- CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
- &empty_color);
- if (intermediate == NULL) {
+ draw_region = pixman_region_create ();
+ if (draw_region == NULL)
+ {
status = CAIRO_STATUS_NO_MEMORY;
goto BAIL0;
}
+
+ _cairo_traps_extents (traps, &extents);
+
+ status = _calculate_region_for_intermediate_clip_surface (draw_region,
+ &extents,
+ &gstate->clip);
+ if (status)
+ goto BAIL1;
+
+ /* Shortcut if empty */
+ if (!pixman_region_not_empty (draw_region)) {
+ status = CAIRO_STATUS_SUCCESS;
+ goto BAIL1;
+ }
+
+ draw_extents = pixman_region_extents (draw_region);
/* 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 clip
- surface. */
- xoff = _cairo_fixed_from_double (gstate->clip.x);
- yoff = _cairo_fixed_from_double (gstate->clip.y);
+ the coordinates to align with the offset origin of the
+ intermediate surface. */
+ xoff = _cairo_fixed_from_int (draw_extents->x1);
+ yoff = _cairo_fixed_from_int (draw_extents->y1);
for (i=0, t=traps->traps; i < traps->num_traps; i++, t++) {
t->top -= yoff;
t->bottom -= yoff;
@@ -1428,11 +1491,22 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
_cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0);
_cairo_pattern_set_alpha (&pattern, 1.0);
- _cairo_traps_extents (traps, &extents);
status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
if (status)
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,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1,
+ &empty_color);
+ if (intermediate == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL2;
+ }
+
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
pattern.source, intermediate,
x_src,
@@ -1440,30 +1514,32 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
traps->traps,
traps->num_traps);
if (status)
- goto BAIL2;
+ goto BAIL3;
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
gstate->clip.surface,
NULL,
intermediate,
- 0, 0, 0, 0, 0, 0,
- gstate->clip.width, gstate->clip.height);
+ draw_extents->x1 - gstate->clip.x,
+ draw_extents->y1 - gstate->clip.y,
+ 0, 0,
+ 0, 0,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
if (status)
- goto BAIL2;
+ goto BAIL3;
_cairo_pattern_fini (&pattern);
_cairo_pattern_init_copy (&pattern, src);
- extents.p1.x = _cairo_fixed_from_int (gstate->clip.x);
- extents.p1.y = _cairo_fixed_from_int (gstate->clip.y);
- extents.p2.x =
- _cairo_fixed_from_int (gstate->clip.x + gstate->clip.width);
- extents.p2.y =
- _cairo_fixed_from_int (gstate->clip.y + gstate->clip.height);
+ extents.p1.x = _cairo_fixed_from_int (draw_extents->x1);
+ extents.p1.y = _cairo_fixed_from_int (draw_extents->y1);
+ extents.p2.x = _cairo_fixed_from_int (draw_extents->x2);
+ extents.p2.y = _cairo_fixed_from_int (draw_extents->y2);
status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
if (status)
- goto BAIL2;
+ goto BAIL3;
if (dst == gstate->clip.surface)
xoff = yoff = 0;
@@ -1474,13 +1550,16 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
0, 0,
xoff >> 16,
yoff >> 16,
- gstate->clip.width,
- gstate->clip.height);
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
+
- BAIL2:
+ BAIL3:
cairo_surface_destroy (intermediate);
- BAIL1:
+ BAIL2:
_cairo_pattern_fini (&pattern);
+ BAIL1:
+ pixman_region_destroy (draw_region);
BAIL0:
if (status)
@@ -1705,6 +1784,25 @@ extract_transformed_rectangle(cairo_matrix_t *mat,
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)
{
@@ -1762,6 +1860,10 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
_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. */
@@ -1799,7 +1901,7 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
_cairo_traps_fini (&traps);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
@@ -1809,7 +1911,7 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
int height)
{
- /* We are dealing with 5 coordinate spaces in this function. this makes
+ /* 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.
@@ -1833,12 +1935,16 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
* 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 6th space in here, which is the space of the
+ * (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
@@ -1897,15 +2003,16 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
_cairo_pattern_init (&pattern);
+ 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);
+
if ((gstate->pattern->type != CAIRO_PATTERN_SOLID) ||
(gstate->alpha != 1.0)) {
/* I'm allowing any type of pattern for the mask right now.
Maybe this is bad. Will allow for some cool effects though. */
_cairo_pattern_init_copy (&pattern, gstate->pattern);
- 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);
status = _cairo_gstate_create_pattern (gstate, &pattern, &pattern_extents);
if (status)
return status;
@@ -1915,13 +2022,36 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
{
cairo_surface_t *intermediate;
cairo_color_t empty_color;
+ pixman_box16_t *draw_extents;
+ pixman_region16_t *draw_region;
+ draw_region = pixman_region_create ();
+ if (draw_region == NULL)
+ {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL0;
+ }
+
+ status = _calculate_region_for_intermediate_clip_surface (draw_region,
+ &pattern_extents,
+ &gstate->clip);
+ if (status)
+ goto BAIL1;
+
+ /* Shortcut if empty */
+ if (!pixman_region_not_empty (draw_region)) {
+ status = CAIRO_STATUS_SUCCESS;
+ goto BAIL1;
+ }
+
+ draw_extents = pixman_region_extents (draw_region);
+
_cairo_color_init (&empty_color);
_cairo_color_set_alpha (&empty_color, .0);
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1,
&empty_color);
/* it is not completely clear what the "right" way to combine the
@@ -1935,27 +2065,33 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
gstate->clip.surface,
pattern.source,
intermediate,
- 0, 0,
+ draw_extents->x1 - gstate->clip.x,
+ draw_extents->y1 - gstate->clip.y,
0, 0,
0, 0,
- gstate->clip.width,
- gstate->clip.height);
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
+
if (status)
- goto BAIL;
+ goto BAIL2;
status = _cairo_surface_composite (gstate->operator,
surface,
intermediate,
gstate->surface,
- gstate->clip.x, gstate->clip.y,
+ draw_extents->x1, draw_extents->y1,
0, 0,
- gstate->clip.x, gstate->clip.y,
- gstate->clip.width,
- gstate->clip.height);
+ draw_extents->x1, draw_extents->y1,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
- BAIL:
+ BAIL2:
cairo_surface_destroy (intermediate);
+ BAIL1:
+ pixman_region_destroy (draw_region);
+ BAIL0:
+ ;
}
else
{
@@ -1992,21 +2128,14 @@ _cairo_gstate_select_font (cairo_gstate_t *gstate,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
- cairo_unscaled_font_t *tmp;
-
- tmp = _cairo_unscaled_font_create (family, slant, weight);
+ if (gstate->font)
+ _cairo_unscaled_font_destroy (gstate->font);
- if (tmp == NULL)
+ gstate->font = _cairo_unscaled_font_create (family, slant, weight);
+ if (gstate->font == NULL)
return CAIRO_STATUS_NO_MEMORY;
- if (gstate->font != tmp)
- {
- if (gstate->font != NULL)
- _cairo_unscaled_font_destroy (gstate->font);
-
- cairo_matrix_set_identity (&gstate->font_matrix);
- gstate->font = tmp;
- }
+ cairo_matrix_set_identity (&gstate->font_matrix);
return CAIRO_STATUS_SUCCESS;
}
@@ -2171,30 +2300,27 @@ _cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
{
cairo_int_status_t status;
cairo_font_scale_t sc;
- double dummy = 0.0;
+ double font_scale_x, font_scale_y;
_build_font_scale (gstate, &sc);
status = _cairo_unscaled_font_font_extents (gstate->font, &sc, extents);
- /* The font responded in device space; convert to user space. */
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &dummy,
- &extents->ascent);
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &dummy,
- &extents->descent);
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &dummy,
- &extents->height);
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &extents->max_x_advance,
- &extents->max_y_advance);
-
+ _cairo_matrix_compute_scale_factors (&gstate->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;
}
@@ -2208,18 +2334,20 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
cairo_font_scale_t sc;
cairo_point_t point;
- double dev_x, dev_y;
+ double origin_x, origin_y;
int i;
_build_font_scale (gstate, &sc);
status = _cairo_path_current_point (&gstate->path, &point);
if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
- dev_x = 0.0;
- dev_y = 0.0;
+ origin_x = 0.0;
+ origin_y = 0.0;
} else {
- dev_x = _cairo_fixed_to_double (point.x);
- dev_y = _cairo_fixed_to_double (point.y);
+ 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_unscaled_font_text_to_glyphs (gstate->font,
@@ -2228,15 +2356,16 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs))
return status;
- /* The font responded in device space, starting from (0,0); add any
- current point offset in device space, and convert to user space. */
+ /* 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) {
- (*glyphs)[i].x += dev_x;
- (*glyphs)[i].y += dev_y;
- cairo_matrix_transform_point (&gstate->ctm_inverse,
- &((*glyphs)[i].x),
- &((*glyphs)[i].y));
+ 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;
@@ -2265,44 +2394,88 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
int num_glyphs,
cairo_text_extents_t *extents)
{
- cairo_status_t status;
- cairo_glyph_t *transformed_glyphs;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_glyph_t origin_glyph;
+ cairo_text_extents_t origin_extents;
cairo_font_scale_t sc;
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;
- _build_font_scale (gstate, &sc);
-
- 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)
+ if (!num_glyphs)
{
- transformed_glyphs[i] = glyphs[i];
- cairo_matrix_transform_point (&gstate->ctm,
- &transformed_glyphs[i].x,
- &transformed_glyphs[i].y);
+ 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;
}
- status = _cairo_unscaled_font_glyph_extents (gstate->font, &sc,
- transformed_glyphs, num_glyphs,
- extents);
-
- /* The font responded in device space; convert to user space. */
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &extents->x_bearing,
- &extents->y_bearing);
+ _build_font_scale (gstate, &sc);
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &extents->width,
- &extents->height);
+ 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_unscaled_font_glyph_extents (gstate->font, &sc,
+ &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 (&gstate->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 (&gstate->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;
+ }
+ }
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &extents->x_advance,
- &extents->y_advance);
+ x = origin_extents.x_advance;
+ y = origin_extents.y_advance;
+ cairo_matrix_transform_point (&gstate->font_matrix,
+ &x, &y);
+ x_pos = glyphs[i].x + x;
+ y_pos = glyphs[i].y + y;
+ }
- free (transformed_glyphs);
+ 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;
return status;
}
@@ -2338,55 +2511,84 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
transformed_glyphs, num_glyphs,
&bbox);
if (status)
- return status;
+ goto CLEANUP_GLYPHS;
status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox);
if (status)
- return status;
+ goto CLEANUP_GLYPHS;
if (gstate->clip.surface)
{
cairo_surface_t *intermediate;
cairo_color_t empty_color;
+ pixman_box16_t *draw_extents;
+ pixman_region16_t *draw_region;
+
+ draw_region = pixman_region_create ();
+ if (draw_region == NULL)
+ {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL0;
+ }
+
+ status = _calculate_region_for_intermediate_clip_surface (draw_region,
+ &bbox,
+ &gstate->clip);
+ if (status) {
+ goto BAIL1;
+ }
+ /* Shortcut if empty */
+ if (!pixman_region_not_empty (draw_region)) {
+ status = CAIRO_STATUS_SUCCESS;
+ goto BAIL1;
+ }
+
+ draw_extents = pixman_region_extents (draw_region);
+
_cairo_color_init (&empty_color);
_cairo_color_set_alpha (&empty_color, .0);
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1,
&empty_color);
+ if (intermediate == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL1;
+ }
- /* move the glyphs again, from dev space to clip space */
+ /* move the glyphs again, from dev space to intermediate space */
for (i = 0; i < num_glyphs; ++i)
{
- transformed_glyphs[i].x -= gstate->clip.x;
- transformed_glyphs[i].y -= gstate->clip.y;
+ transformed_glyphs[i].x -= draw_extents->x1;
+ transformed_glyphs[i].y -= draw_extents->y1;
}
status = _cairo_unscaled_font_show_glyphs (gstate->font,
&sc,
CAIRO_OPERATOR_ADD,
pattern.source, intermediate,
- gstate->clip.x - pattern.source_offset.x,
- gstate->clip.y - pattern.source_offset.y,
+ draw_extents->x1 - pattern.source_offset.x,
+ draw_extents->y1 - pattern.source_offset.y,
transformed_glyphs, num_glyphs);
if (status)
- goto BAIL;
+ goto BAIL2;
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
gstate->clip.surface,
NULL,
intermediate,
- 0, 0,
+ draw_extents->x1 - gstate->clip.x,
+ draw_extents->y1 - gstate->clip.y,
0, 0,
0, 0,
- gstate->clip.width,
- gstate->clip.height);
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
if (status)
- goto BAIL;
+ goto BAIL2;
status = _cairo_surface_composite (gstate->operator,
pattern.source,
@@ -2394,14 +2596,17 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
gstate->surface,
0, 0,
0, 0,
- gstate->clip.x,
- gstate->clip.y,
- gstate->clip.width,
- gstate->clip.height);
-
- BAIL:
- cairo_surface_destroy (intermediate);
+ draw_extents->x1,
+ draw_extents->y1,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
+ BAIL2:
+ cairo_surface_destroy (intermediate);
+ BAIL1:
+ pixman_region_destroy (draw_region);
+ BAIL0:
+ ;
}
else
{
@@ -2416,6 +2621,7 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
_cairo_pattern_fini (&pattern);
+ CLEANUP_GLYPHS:
free (transformed_glyphs);
return status;
diff --git a/src/cairo-hash.c b/src/cairo-hash.c
index a33d69a04..b097b609b 100644
--- a/src/cairo-hash.c
+++ b/src/cairo-hash.c
@@ -43,7 +43,7 @@
* Packard.
*/
-static cairo_cache_arrangement_t cache_arrangements [] = {
+static const cairo_cache_arrangement_t cache_arrangements [] = {
{ 16, 43, 41 },
{ 32, 73, 71 },
{ 64, 151, 149 },
@@ -114,7 +114,6 @@ static cairo_cache_arrangement_t cache_arrangements [] = {
(!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i)))))
#ifdef CAIRO_DO_SANITY_CHECKING
-#include <assert.h>
static void
_cache_sane_state (cairo_cache_t *cache)
{
@@ -122,13 +121,12 @@ _cache_sane_state (cairo_cache_t *cache)
assert (cache->entries != NULL);
assert (cache->backend != NULL);
assert (cache->arrangement != NULL);
- assert (cache->refcount > 0);
- assert (cache->used_memory <= cache->max_memory);
+ /* 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)
-#define assert(x)
#endif
static void
@@ -140,7 +138,7 @@ _entry_destroy (cairo_cache_t *cache, unsigned long i)
{
cairo_cache_entry_base_t *entry = cache->entries[i];
assert(cache->live_entries > 0);
- assert(cache->used_memory > entry->memory);
+ assert(cache->used_memory >= entry->memory);
cache->live_entries--;
cache->used_memory -= entry->memory;
@@ -183,10 +181,12 @@ _cache_lookup (cairo_cache_t *cache,
if (predicate != NULL)
{
/* We are looking up an exact entry. */
- if (*probe != NULL
- && *probe != DEAD_ENTRY
- && (*probe)->hashcode == hash
- && predicate (cache, key, *probe))
+ 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
@@ -230,8 +230,7 @@ _find_exact_live_entry_for (cairo_cache_t *cache,
return _cache_lookup (cache, key, cache->backend->keys_equal);
}
-
-static cairo_cache_arrangement_t *
+static const cairo_cache_arrangement_t *
_find_cache_arrangement (unsigned long proposed_size)
{
unsigned long idx;
@@ -302,7 +301,7 @@ _cairo_cache_init (cairo_cache_t *cache,
const cairo_cache_backend_t *backend,
unsigned long max_memory)
{
- assert(backend != NULL);
+ assert (backend != NULL);
if (cache != NULL){
cache->arrangement = &cache_arrangements[0];
@@ -342,7 +341,7 @@ _cairo_cache_destroy (cairo_cache_t *cache)
_cache_sane_state (cache);
- if (cache->refcount-- > 0)
+ if (--cache->refcount > 0)
return;
for (i = 0; i < cache->arrangement->size; ++i) {
@@ -419,7 +418,8 @@ _cairo_cache_lookup (cairo_cache_t *cache,
_entry_destroy (cache, idx);
}
- assert(cache->max_memory >= (cache->used_memory + new_entry->memory));
+ /* 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);
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index cbdc018a1..14e30f695 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -169,7 +169,7 @@ cairo_image_surface_create_for_data (char *data,
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),
@@ -199,7 +199,7 @@ 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);
@@ -490,7 +490,7 @@ _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
+static cairo_int_status_t
_cairo_image_abstract_surface_create_pattern (void *abstract_surface,
cairo_pattern_t *pattern,
cairo_box_t *box)
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index 7fc2694f3..b964b688c 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -34,6 +34,7 @@
* Carl D. Worth <cworth@isi.edu>
*/
+#define _GNU_SOURCE
#include <stdlib.h>
#include <math.h>
@@ -124,9 +125,20 @@ cairo_matrix_get_affine (cairo_matrix_t *matrix,
double *c, double *d,
double *tx, double *ty)
{
- *a = matrix->m[0][0]; *b = matrix->m[0][1];
- *c = matrix->m[1][0]; *d = matrix->m[1][1];
- *tx = matrix->m[2][0]; *ty = matrix->m[2][1];
+ 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;
}
@@ -176,9 +188,17 @@ 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,
- cos (radians), sin (radians),
- -sin (radians), cos (radians),
+ c, s,
+ -s, c,
0, 0);
}
@@ -398,19 +418,42 @@ _cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, dou
/* 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)
+_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy, int x_major)
{
- double x, y;
+ double det;
- x = 1.0;
- y = 0.0;
- cairo_matrix_transform_distance (matrix, &x, &y);
- *sx = sqrt(x*x + y*y);
+ _cairo_matrix_compute_determinant (matrix, &det);
- x = 0.0;
- y = 1.0;
- cairo_matrix_transform_distance (matrix, &x, &y);
- *sy = sqrt(x*x + y*y);
+ 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;
}
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
new file mode 100644
index 000000000..23230aa74
--- /dev/null
+++ b/src/cairo-pdf-surface.c
@@ -0,0 +1,2208 @@
+/* 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: This seems broken to me. What about users without freetype
+ * that want to use a cairo PDF surface? */
+#include "cairo-ft.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?
+ *
+ * - Why isn't the pattern passed to composite traps instead of
+ * pattern->source? If composite traps needs an image or a surface it
+ * can call create_pattern().
+ *
+ * - 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;
+
+ /* HACK: Non-null if this surface was created for a pattern. */
+ cairo_pattern_t *pattern;
+
+ 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
+#define OFFSET_TABLE_SIZE 12
+#define TABLE_DIRECTORY_ENTRY_SIZE 16
+
+#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,
+ cairo_font_scale_t *scale)
+{
+ cairo_font_t scaled_font;
+ FT_Face face;
+ cairo_pdf_ft_font_t *font;
+ unsigned long size;
+ int i, j;
+
+ /* FIXME: Why do I have to pass a scaled font to get the FT_Face? */
+ _cairo_font_init (&scaled_font, scale, unscaled_font);
+ face = cairo_ft_font_face (&scaled_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->face = face;
+ 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;
+
+ 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, 0);
+ 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;
+
+ if (cairo_pdf_ft_font_write_offset_table (font))
+ return font->status;
+
+ start = cairo_pdf_ft_font_align_output (font);
+ end = start;
+
+ 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:
+ 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;
+
+ surface->pattern = NULL;
+ _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_font_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_image_surface_t *
+_cairo_pdf_surface_get_image (void *abstract_surface)
+{
+ return NULL;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_set_image (void *abstract_surface,
+ cairo_image_surface_t *image)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_set_matrix (void *abstract_surface,
+ cairo_matrix_t *matrix)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_set_filter (void *abstract_surface,
+ cairo_filter_t filter)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_set_repeat (void *abstract_surface,
+ int repeat)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+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_image_surface_t *image)
+{
+ cairo_pdf_document_t *document = dst->document;
+ FILE *file = document->file;
+ unsigned id;
+ cairo_matrix_t i2u;
+
+ id = emit_image_data (dst->document, image);
+ if (id == 0)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ _cairo_pdf_surface_add_xobject (dst, id);
+
+ _cairo_pdf_surface_ensure_stream (dst);
+
+ cairo_matrix_copy (&i2u, &image->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);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* 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_pdf_surface_t *src,
+ int width, int height)
+{
+ cairo_pdf_document_t *document = dst->document;
+ FILE *file = document->file;
+ cairo_matrix_t i2u;
+ cairo_pdf_stream_t *stream;
+ int num_streams, i;
+
+ if (src->pattern != NULL)
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_pdf_surface_ensure_stream (dst);
+
+ 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_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)
+{
+ cairo_pdf_surface_t *dst = abstract_dst;
+ cairo_pdf_surface_t *src;
+ cairo_image_surface_t *image;
+
+ if (generic_src->backend == &cairo_pdf_surface_backend) {
+ src = (cairo_pdf_surface_t *) generic_src;
+ return _cairo_pdf_surface_composite_pdf (dst, src, width, height);
+ }
+ else {
+ image = _cairo_surface_get_image (generic_src);
+ return _cairo_pdf_surface_composite_image (dst, image);
+ }
+}
+
+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;
+
+ if (surface->pattern != NULL)
+ return CAIRO_STATUS_SUCCESS;
+
+ _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_tiling_pattern (cairo_operator_t operator,
+ cairo_pdf_surface_t *dst,
+ cairo_pattern_t *pattern)
+{
+ cairo_pdf_document_t *document = dst->document;
+ FILE *file = document->file;
+ cairo_pdf_stream_t *stream;
+ cairo_image_surface_t *image;
+ char entries[250];
+ unsigned int id, alpha;
+ cairo_matrix_t pm;
+
+ if (pattern->u.surface.surface->backend == &cairo_pdf_surface_backend) {
+ return;
+ }
+
+ image = _cairo_surface_get_image (pattern->u.surface.surface);
+
+ _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->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);
+
+ _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);
+}
+
+static unsigned int
+emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_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_char[0], file);
+ fputc (pattern->stops[0].color_char[1], file);
+ fputc (pattern->stops[0].color_char[2], file);
+ fputc (pattern->stops[1].color_char[0], file);
+ fputc (pattern->stops[1].color_char[1], file);
+ fputc (pattern->stops[1].color_char[2], 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_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);
+
+ cairo_matrix_copy (&p2u, &pattern->matrix);
+ cairo_matrix_invert (&p2u);
+
+ x0 = pattern->u.linear.point0.x;
+ y0 = pattern->u.linear.point0.y;
+ cairo_matrix_transform_point (&p2u, &x0, &y0);
+ x1 = pattern->u.linear.point1.x;
+ y1 = pattern->u.linear.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 [ %s %s ]\r\n"
+ " >>\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ pattern_id,
+ document->height_inches * document->y_ppi,
+ x0, y0, x1, y1,
+ function_id,
+ (1 || pattern->extend) ? "true" : "false",
+ (1 || pattern->extend) ? "true" : "false");
+
+ _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_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);
+
+ cairo_matrix_copy (&p2u, &pattern->matrix);
+ cairo_matrix_invert (&p2u);
+
+ x0 = pattern->u.radial.center0.x;
+ y0 = pattern->u.radial.center0.y;
+ r0 = pattern->u.radial.radius0;
+ cairo_matrix_transform_point (&p2u, &x0, &y0);
+ x1 = pattern->u.radial.center1.x;
+ y1 = pattern->u.radial.center1.y;
+ r1 = pattern->u.radial.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);
+
+ 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 [ %s %s ]\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,
+ (1 || pattern->extend) ? "true" : "false",
+ (1 || pattern->extend) ? "true" : "false");
+
+ _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 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_surface_t *generic_src,
+ void *abstract_dst,
+ int x_src,
+ int y_src,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+{
+ cairo_pdf_surface_t *surface = abstract_dst;
+ cairo_pdf_surface_t *source = (cairo_pdf_surface_t *) generic_src;
+ cairo_pdf_document_t *document = surface->document;
+ cairo_pattern_t *pattern;
+ FILE *file = document->file;
+ int i;
+ unsigned int alpha;
+
+ /* FIXME: we really just want the original pattern here, not a
+ * source surface. */
+ pattern = source->pattern;
+
+ if (source->base.backend != &cairo_pdf_surface_backend) {
+ printf ("_cairo_pdf_surface_composite_trapezoids: not a pdf source\r");
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (pattern == NULL) {
+ printf ("_cairo_pdf_surface_composite_trapezoids: "
+ "non-pattern pdf source\r");
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_SOLID:
+ 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->color.red,
+ pattern->color.green,
+ pattern->color.blue,
+ alpha);
+ break;
+
+ case CAIRO_PATTERN_SURFACE:
+ emit_tiling_pattern (operator, surface, pattern);
+ break;
+
+ case CAIRO_PATTERN_LINEAR:
+ emit_linear_pattern (surface, pattern);
+ break;
+
+ case CAIRO_PATTERN_RADIAL:
+ emit_radial_pattern (surface, pattern );
+ break;
+ }
+
+ /* 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_int_status_t
+_cairo_pdf_surface_create_pattern (void *abstract_surface,
+ cairo_pattern_t *pattern,
+ cairo_box_t *extents)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_pdf_surface_t *source;
+
+ source = (cairo_pdf_surface_t *)
+ _cairo_pdf_surface_create_for_document (surface->document, 0, 0);
+ source->pattern = pattern;
+ pattern->source = &source->base;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_pdf_font_t *
+_cairo_pdf_document_get_font (cairo_pdf_document_t *document,
+ cairo_unscaled_font_t *unscaled_font,
+ cairo_font_scale_t *scale)
+{
+ cairo_pdf_font_t *font;
+ unsigned int num_fonts, i;
+
+ num_fonts = _cairo_array_num_elements (&document->fonts);
+ for (i = 0; i < num_fonts; i++) {
+ _cairo_array_copy_element (&document->fonts, i, &font);
+ if (font->unscaled_font == unscaled_font)
+ return font;
+ }
+
+ /* FIXME: Figure out here which font backend is in use and call
+ * the appropriate constructor. */
+ font = cairo_pdf_ft_font_create (document, unscaled_font, scale);
+ if (font == NULL)
+ return NULL;
+
+ if (_cairo_array_append (&document->fonts, &font, 1) == NULL) {
+ cairo_pdf_font_destroy (font);
+ return NULL;
+ }
+
+ return font;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_show_glyphs (cairo_unscaled_font_t *font,
+ cairo_font_scale_t *scale,
+ cairo_operator_t operator,
+ cairo_surface_t *source,
+ void *abstract_surface,
+ int source_x,
+ int source_y,
+ 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, scale);
+ if (pdf_font == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ _cairo_pdf_surface_ensure_stream (surface);
+
+ fprintf (file, "0 0 0 rg 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 (%c) Tj",
+ scale->matrix[0][0],
+ scale->matrix[0][1],
+ scale->matrix[1][0],
+ -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_get_image,
+ _cairo_pdf_surface_set_image,
+ _cairo_pdf_surface_set_matrix,
+ _cairo_pdf_surface_set_filter,
+ _cairo_pdf_surface_set_repeat,
+ _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_create_pattern,
+ _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 /%s\r\n"
+ " /Flags 32\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-pdf.h b/src/cairo-pdf.h
new file mode 100644
index 000000000..0f624af31
--- /dev/null
+++ b/src/cairo-pdf.h
@@ -0,0 +1,62 @@
+/* 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@isi.edu>
+ */
+
+#include <cairo.h>
+
+#ifndef CAIRO_PDF_H
+#define CAIRO_PDF_H
+#ifdef CAIRO_HAS_PDF_SURFACE
+
+#include <stdio.h>
+
+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 (FILE *file,
+ double width_inches,
+ double height_inches,
+ double x_pixels_per_inch,
+ double y_pixels_per_inch);
+
+#endif /* CAIRO_HAS_PDF_SURFACE */
+#endif /* CAIRO_PDF_H */
diff --git a/src/cairo-png.h b/src/cairo-png.h
new file mode 100644
index 000000000..766d6f91f
--- /dev/null
+++ b/src/cairo-png.h
@@ -0,0 +1,59 @@
+/* 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@isi.edu>
+ */
+
+#include <cairo.h>
+
+#ifndef CAIRO_PNG_H
+#define CAIRO_PNG_H
+#ifdef CAIRO_HAS_PNG_SURFACE
+
+#include <stdio.h>
+
+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);
+
+#endif /* CAIRO_HAS_PNG_SURFACE */
+#endif /* CAIRO_PNG_H */
diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c
index 8fa32f9f6..e85858033 100644
--- a/src/cairo-polygon.c
+++ b/src/cairo-polygon.c
@@ -37,8 +37,6 @@
#include <stdlib.h>
#include "cairoint.h"
-#define CAIRO_POLYGON_GROWTH_INC 10
-
/* private functions */
static cairo_status_t
@@ -104,7 +102,8 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_poin
}
if (polygon->num_edges >= polygon->edges_size) {
- status = _cairo_polygon_grow_by (polygon, CAIRO_POLYGON_GROWTH_INC);
+ int additional = polygon->edges_size ? polygon->edges_size : 16;
+ status = _cairo_polygon_grow_by (polygon, additional);
if (status) {
return status;
}
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index bfdfada38..4da8162c7 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -35,6 +35,7 @@
*/
#include "cairoint.h"
+#include "cairo-ps.h"
#include <time.h>
#include <zlib.h>
@@ -130,8 +131,6 @@ cairo_ps_surface_create (FILE *file,
"%%%%CreationDate: %s",
ctime (&now));
fprintf (file,
- "%%%%Copyright: 2003 Carl Worth and Keith Packard\n");
- 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 */
diff --git a/src/cairo-ps.h b/src/cairo-ps.h
new file mode 100644
index 000000000..ae8e72192
--- /dev/null
+++ b/src/cairo-ps.h
@@ -0,0 +1,63 @@
+/* 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@isi.edu>
+ */
+
+#include <cairo.h>
+
+#ifndef CAIRO_PS_H
+#define CAIRO_PS_H
+#ifdef CAIRO_HAS_PS_SURFACE
+
+#include <stdio.h>
+
+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);
+
+#endif /* CAIRO_HAS_PS_SURFACE */
+#endif /* CAIRO_PS_H */
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
new file mode 100644
index 000000000..b7103b051
--- /dev/null
+++ b/src/cairo-quartz-surface.c
@@ -0,0 +1,392 @@
+/* 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-quartz.h b/src/cairo-quartz.h
new file mode 100644
index 000000000..918bc18d7
--- /dev/null
+++ b/src/cairo-quartz.h
@@ -0,0 +1,58 @@
+/* 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@isi.edu>
+ */
+
+#include <cairo.h>
+
+#ifndef CAIRO_QUARTZ_H
+#define CAIRO_QUARTZ_H
+#ifdef CAIRO_HAS_QUARTZ_SURFACE
+
+#include <Carbon/Carbon.h>
+
+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,
+ int height);
+
+#endif /* CAIRO_HAS_QUARTZ_SURFACE */
+#endif /* CAIRO_QUARTZ_H */
+
diff --git a/src/cairo-spline.c b/src/cairo-spline.c
index bed351ef4..ff290d9dd 100644
--- a/src/cairo-spline.c
+++ b/src/cairo-spline.c
@@ -54,8 +54,6 @@ _cairo_spline_error_squared (cairo_spline_t *spline);
static cairo_status_t
_cairo_spline_decompose_into (cairo_spline_t *spline, double tolerance_squared, cairo_spline_t *result);
-#define CAIRO_SPLINE_GROWTH_INC 100
-
cairo_int_status_t
_cairo_spline_init (cairo_spline_t *spline,
cairo_point_t *a, cairo_point_t *b,
@@ -136,7 +134,8 @@ _cairo_spline_add_point (cairo_spline_t *spline, cairo_point_t *point)
}
if (spline->num_points >= spline->points_size) {
- status = _cairo_spline_grow_by (spline, CAIRO_SPLINE_GROWTH_INC);
+ int additional = spline->points_size ? spline->points_size : 32;
+ status = _cairo_spline_grow_by (spline, additional);
if (status)
return status;
}
diff --git a/src/cairo-wideint.c b/src/cairo-wideint.c
index 67ba3f9b9..953108339 100644
--- a/src/cairo-wideint.c
+++ b/src/cairo-wideint.c
@@ -1,25 +1,37 @@
/*
- * $Id: cairo-wideint.c,v 1.1 2004-05-28 19:37:15 keithp Exp $
+ * $Id: cairo-wideint.c,v 1.4 2005-01-19 15:07:00 cworth Exp $
*
* Copyright © 2004 Keith Packard
*
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
+ * 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.
*
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
+ * 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"
@@ -44,7 +56,7 @@ static const unsigned char top_bit[256] =
#define _cairo_uint32s_to_uint64(h,l) ((uint64_t) (h) << 32 | (l))
-const cairo_uquorem64_t
+cairo_uquorem64_t
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
{
cairo_uquorem64_t qr;
@@ -56,7 +68,7 @@ _cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
#else
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint32_to_uint64 (uint32_t i)
{
cairo_uint64_t q;
@@ -66,7 +78,7 @@ _cairo_uint32_to_uint64 (uint32_t i)
return q;
}
-const cairo_int64_t
+cairo_int64_t
_cairo_int32_to_int64 (int32_t i)
{
cairo_uint64_t q;
@@ -86,7 +98,7 @@ _cairo_uint32s_to_uint64 (uint32_t h, uint32_t l)
return q;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint64_t s;
@@ -98,7 +110,7 @@ _cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b)
return s;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint64_t s;
@@ -114,7 +126,7 @@ _cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b)
#define uint32_hi(i) ((i) >> 16)
#define uint32_carry16 ((1) << 16)
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint32x32_64_mul (uint32_t a, uint32_t b)
{
cairo_uint64_t s;
@@ -142,7 +154,18 @@ _cairo_uint32x32_64_mul (uint32_t a, uint32_t b)
return s;
}
-const cairo_uint64_t
+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;
@@ -152,7 +175,7 @@ _cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b)
return s;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_lsl (cairo_uint64_t a, int shift)
{
if (shift >= 32)
@@ -169,7 +192,7 @@ _cairo_uint64_lsl (cairo_uint64_t a, int shift)
return a;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_rsl (cairo_uint64_t a, int shift)
{
if (shift >= 32)
@@ -188,7 +211,7 @@ _cairo_uint64_rsl (cairo_uint64_t a, int shift)
#define _cairo_uint32_rsa(a,n) ((uint32_t) (((int32_t) (a)) >> (n)))
-const cairo_int64_t
+cairo_int64_t
_cairo_uint64_rsa (cairo_int64_t a, int shift)
{
if (shift >= 32)
@@ -205,20 +228,20 @@ _cairo_uint64_rsa (cairo_int64_t a, int shift)
return a;
}
-const int
+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));
}
-const int
+int
_cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b)
{
return a.hi == b.hi && a.lo == b.lo;
}
-const int
+int
_cairo_int64_lt (cairo_int64_t a, cairo_int64_t b)
{
if (_cairo_int64_negative (a) && !_cairo_int64_negative (b))
@@ -228,7 +251,7 @@ _cairo_int64_lt (cairo_int64_t a, cairo_int64_t b)
return _cairo_uint64_lt (a, b);
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_not (cairo_uint64_t a)
{
a.lo = ~a.lo;
@@ -236,7 +259,7 @@ _cairo_uint64_not (cairo_uint64_t a)
return a;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_negate (cairo_uint64_t a)
{
a.lo = ~a.lo;
@@ -325,7 +348,7 @@ _cairo_uint64x32_normalized_divrem (cairo_uint64_t num, uint32_t den)
return qr;
}
-const cairo_uquorem64_t
+cairo_uquorem64_t
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
{
cairo_uquorem32_t qr32;
@@ -444,7 +467,7 @@ _cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
#endif /* !HAVE_UINT64_T */
-const cairo_quorem64_t
+cairo_quorem64_t
_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den)
{
int num_neg = _cairo_int64_negative (num);
@@ -470,7 +493,7 @@ _cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den)
#if HAVE_UINT128_T
-const cairo_uquorem128_t
+cairo_uquorem128_t
_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
{
cairo_uquorem128_t qr;
@@ -482,7 +505,7 @@ _cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
#else
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint32_to_uint128 (uint32_t i)
{
cairo_uint128_t q;
@@ -492,7 +515,7 @@ _cairo_uint32_to_uint128 (uint32_t i)
return q;
}
-const cairo_int128_t
+cairo_int128_t
_cairo_int32_to_int128 (int32_t i)
{
cairo_int128_t q;
@@ -502,7 +525,7 @@ _cairo_int32_to_int128 (int32_t i)
return q;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint64_to_uint128 (cairo_uint64_t i)
{
cairo_uint128_t q;
@@ -512,7 +535,7 @@ _cairo_uint64_to_uint128 (cairo_uint64_t i)
return q;
}
-const cairo_int128_t
+cairo_int128_t
_cairo_int64_to_int128 (cairo_int64_t i)
{
cairo_int128_t q;
@@ -522,7 +545,7 @@ _cairo_int64_to_int128 (cairo_int64_t i)
return q;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b)
{
cairo_uint128_t s;
@@ -534,7 +557,7 @@ _cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b)
return s;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b)
{
cairo_uint128_t s;
@@ -594,7 +617,7 @@ static const cairo_uint64_t uint64_carry32 = { 0, 1 };
#endif
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint128_t s;
@@ -622,7 +645,22 @@ _cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b)
return s;
}
-const cairo_uint128_t
+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;
@@ -635,7 +673,7 @@ _cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b)
return s;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_lsl (cairo_uint128_t a, int shift)
{
if (shift >= 64)
@@ -653,7 +691,7 @@ _cairo_uint128_lsl (cairo_uint128_t a, int shift)
return a;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_rsl (cairo_uint128_t a, int shift)
{
if (shift >= 64)
@@ -671,7 +709,7 @@ _cairo_uint128_rsl (cairo_uint128_t a, int shift)
return a;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_rsa (cairo_int128_t a, int shift)
{
if (shift >= 64)
@@ -689,7 +727,7 @@ _cairo_uint128_rsa (cairo_int128_t a, int shift)
return a;
}
-const int
+int
_cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b)
{
return (_cairo_uint64_lt (a.hi, b.hi) ||
@@ -697,7 +735,7 @@ _cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b)
_cairo_uint64_lt (a.lo, b.lo)));
}
-const int
+int
_cairo_int128_lt (cairo_int128_t a, cairo_int128_t b)
{
if (_cairo_int128_negative (a) && !_cairo_int128_negative (b))
@@ -707,7 +745,7 @@ _cairo_int128_lt (cairo_int128_t a, cairo_int128_t b)
return _cairo_uint128_lt (a, b);
}
-const int
+int
_cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b)
{
return (_cairo_uint64_eq (a.hi, b.hi) &&
@@ -722,7 +760,7 @@ _cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b)
/*
* den >= num.hi
*/
-static const cairo_uquorem64_t
+static cairo_uquorem64_t
_cairo_uint128x64_normalized_divrem (cairo_uint128_t num, cairo_uint64_t den)
{
cairo_uquorem64_t qr64;
@@ -786,7 +824,7 @@ _cairo_uint128x64_normalized_divrem (cairo_uint128_t num, cairo_uint64_t den)
#if HAVE_UINT64_T
-static const int
+static int
_cairo_leading_zeros64 (cairo_uint64_t q)
{
int top = 0;
@@ -823,7 +861,7 @@ _cairo_leading_zeros64 (cairo_uint64_t d)
#endif
-const cairo_uquorem128_t
+cairo_uquorem128_t
_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
{
cairo_uquorem64_t qr64;
@@ -943,7 +981,7 @@ _cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
return qr;
}
-const cairo_int128_t
+cairo_int128_t
_cairo_int128_negate (cairo_int128_t a)
{
a.lo = _cairo_uint64_not (a.lo);
@@ -951,7 +989,7 @@ _cairo_int128_negate (cairo_int128_t a)
return _cairo_uint128_add (a, _cairo_uint32_to_uint128 (1));
}
-const cairo_int128_t
+cairo_int128_t
_cairo_int128_not (cairo_int128_t a)
{
a.lo = _cairo_uint64_not (a.lo);
@@ -961,7 +999,7 @@ _cairo_int128_not (cairo_int128_t a)
#endif /* !HAVE_UINT128_T */
-const cairo_quorem128_t
+cairo_quorem128_t
_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den)
{
int num_neg = _cairo_int128_negative (num);
diff --git a/src/cairo-wideint.h b/src/cairo-wideint.h
index d08e039f1..abe36f9d4 100644
--- a/src/cairo-wideint.h
+++ b/src/cairo-wideint.h
@@ -1,25 +1,38 @@
/*
- * $Id: cairo-wideint.h,v 1.1 2004-05-28 19:37:15 keithp Exp $
+ * $Id: cairo-wideint.h,v 1.6 2005-01-19 15:11:14 cworth Exp $
*
* Copyright © 2004 Keith Packard
*
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
+ * 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>
*
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef CAIRO_WIDEINT_H
@@ -33,7 +46,7 @@
* as a pair of 32-bit ints
*/
-#define I __internal_linkage
+#define I cairo_private
#if !HAVE_UINT64_T
@@ -41,31 +54,31 @@ typedef struct _cairo_uint64 {
uint32_t lo, hi;
} cairo_uint64_t, cairo_int64_t;
-const cairo_uint64_t I _cairo_uint32_to_uint64 (uint32_t i);
+cairo_uint64_t I _cairo_uint32_to_uint64 (uint32_t i);
#define _cairo_uint64_to_uint32(a) ((a).lo)
-const cairo_uint64_t I _cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b);
-const cairo_uint64_t I _cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b);
-const cairo_uint64_t I _cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b);
-const cairo_uint64_t I _cairo_uint32x32_64_mul (uint32_t a, uint32_t b);
-const cairo_uint64_t I _cairo_uint64_lsl (cairo_uint64_t a, int shift);
-const cairo_uint64_t I _cairo_uint64_rsl (cairo_uint64_t a, int shift);
-const cairo_uint64_t I _cairo_uint64_rsa (cairo_uint64_t a, int shift);
-const int _cairo_uint64_lt (cairo_uint64_t a, cairo_uint64_t b);
-const int _cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b);
-const cairo_uint64_t I _cairo_uint64_negate (cairo_uint64_t a);
+cairo_uint64_t I _cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b);
+cairo_uint64_t I _cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b);
+cairo_uint64_t I _cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b);
+cairo_uint64_t I _cairo_uint32x32_64_mul (uint32_t a, uint32_t b);
+cairo_uint64_t I _cairo_uint64_lsl (cairo_uint64_t a, int shift);
+cairo_uint64_t I _cairo_uint64_rsl (cairo_uint64_t a, int shift);
+cairo_uint64_t I _cairo_uint64_rsa (cairo_uint64_t a, int shift);
+int I _cairo_uint64_lt (cairo_uint64_t a, cairo_uint64_t b);
+int I _cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b);
+cairo_uint64_t I _cairo_uint64_negate (cairo_uint64_t a);
#define _cairo_uint64_negative(a) (((int32_t) ((a).hi)) < 0)
-const cairo_uint64_t I _cairo_uint64_not (cairo_uint64_t a);
+cairo_uint64_t I _cairo_uint64_not (cairo_uint64_t a);
#define _cairo_uint64_to_int64(i) (i)
#define _cairo_int64_to_uint64(i) (i)
-const cairo_int64_t I _cairo_int32_to_int64(int32_t i);
+cairo_int64_t I _cairo_int32_to_int64(int32_t i);
#define _cairo_int64_to_int32(a) ((int32_t) _cairo_uint64_to_uint32(a))
#define _cairo_int64_add(a,b) _cairo_uint64_add (a,b)
#define _cairo_int64_sub(a,b) _cairo_uint64_sub (a,b)
#define _cairo_int64_mul(a,b) _cairo_uint64_mul (a,b)
-#define _cairo_int32x32_64_mul(a,b) _cairo_uint32x32_64_mul ((uint32_t) (a), (uint32_t) (b)))
-const int _cairo_int64_lt (cairo_uint64_t a, cairo_uint64_t b);
+int I _cairo_int32x32_64_mul (int32_t a, int32_t b);
+int I _cairo_int64_lt (cairo_uint64_t a, cairo_uint64_t b);
#define _cairo_int64_eq(a,b) _cairo_uint64_eq (a,b)
#define _cairo_int64_lsl(a,b) _cairo_uint64_lsl (a,b)
#define _cairo_int64_rsl(a,b) _cairo_uint64_rsl (a,b)
@@ -142,10 +155,10 @@ typedef struct _cairo_quorem64 {
cairo_int64_t rem;
} cairo_quorem64_t;
-const cairo_uquorem64_t I
+cairo_uquorem64_t I
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den);
-const cairo_quorem64_t I
+cairo_quorem64_t I
_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den);
/*
@@ -160,38 +173,38 @@ typedef struct cairo_uint128 {
cairo_uint64_t lo, hi;
} cairo_uint128_t, cairo_int128_t;
-const cairo_uint128_t I _cairo_uint32_to_uint128 (uint32_t i);
-const cairo_uint128_t I _cairo_uint64_to_uint128 (cairo_uint64_t i);
+cairo_uint128_t I _cairo_uint32_to_uint128 (uint32_t i);
+cairo_uint128_t I _cairo_uint64_to_uint128 (cairo_uint64_t i);
#define _cairo_uint128_to_uint64(a) ((a).lo)
#define _cairo_uint128_to_uint32(a) _cairo_uint64_to_uint32(_cairo_uint128_to_uint64(a))
-const cairo_uint128_t I _cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b);
-const cairo_uint128_t I _cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b);
-const cairo_uint128_t I _cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b);
-const cairo_uint128_t I _cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b);
-const cairo_uint128_t I _cairo_uint128_lsl (cairo_uint128_t a, int shift);
-const cairo_uint128_t I _cairo_uint128_rsl (cairo_uint128_t a, int shift);
-const cairo_uint128_t I _cairo_uint128_rsa (cairo_uint128_t a, int shift);
-const int _cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b);
-const int _cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b);
-const cairo_uint128_t I _cairo_uint128_negate (cairo_uint128_t a);
+cairo_uint128_t I _cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b);
+cairo_uint128_t I _cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b);
+cairo_uint128_t I _cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b);
+cairo_uint128_t I _cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b);
+cairo_uint128_t I _cairo_uint128_lsl (cairo_uint128_t a, int shift);
+cairo_uint128_t I _cairo_uint128_rsl (cairo_uint128_t a, int shift);
+cairo_uint128_t I _cairo_uint128_rsa (cairo_uint128_t a, int shift);
+int I _cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b);
+int I _cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b);
+cairo_uint128_t I _cairo_uint128_negate (cairo_uint128_t a);
#define _cairo_uint128_negative(a) (_cairo_uint64_negative(a.hi))
-const cairo_uint128_t I _cairo_uint128_not (cairo_uint128_t a);
+cairo_uint128_t I _cairo_uint128_not (cairo_uint128_t a);
#define _cairo_uint128_to_int128_(i) (i)
#define _cairo_int128_to_uint128(i) (i)
-const cairo_int128_t I _cairo_int32_to_int128 (int32_t i);
-const cairo_int128_t I _cairo_int64_to_int128 (cairo_int64_t i);
-#define _cairo_int128_to_int64(a) ((cairo_int64_t) (a).lo);
+cairo_int128_t I _cairo_int32_to_int128 (int32_t i);
+cairo_int128_t I _cairo_int64_to_int128 (cairo_int64_t i);
+#define _cairo_int128_to_int64(a) ((cairo_int64_t) (a).lo)
#define _cairo_int128_to_int32(a) _cairo_int64_to_int32(_cairo_int128_to_int64(a))
#define _cairo_int128_add(a,b) _cairo_uint128_add(a,b)
#define _cairo_int128_sub(a,b) _cairo_uint128_sub(a,b)
#define _cairo_int128_mul(a,b) _cairo_uint128_mul(a,b)
-#define _cairo_int64x64_128_mul(a,b) _cairo_uint64x64_128_mul ((cairo_uint64_t) (a), (cairo_uint64_t) (b))
+cairo_uint128_t I _cairo_int64x64_128_mul (cairo_int64_t a, cairo_int64_t b);
#define _cairo_int128_lsl(a,b) _cairo_uint128_lsl(a,b)
#define _cairo_int128_rsl(a,b) _cairo_uint128_rsl(a,b)
#define _cairo_int128_rsa(a,b) _cairo_uint128_rsa(a,b)
-const int _cairo_int128_lt (cairo_int128_t a, cairo_int128_t b);
+int I _cairo_int128_lt (cairo_int128_t a, cairo_int128_t b);
#define _cairo_int128_eq(a,b) _cairo_uint128_eq (a,b)
#define _cairo_int128_negate(a) _cairo_uint128_negate(a)
#define _cairo_int128_negative(a) (_cairo_uint128_negative(a))
@@ -251,10 +264,10 @@ typedef struct _cairo_quorem128 {
cairo_int128_t rem;
} cairo_quorem128_t;
-const cairo_uquorem128_t I
+cairo_uquorem128_t I
_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den);
-const cairo_quorem128_t I
+cairo_quorem128_t I
_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den);
#define _cairo_uint128_le(a,b) (!_cairo_uint128_gt(a,b))
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 21760d764..758cf26de 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -730,7 +730,7 @@ _cairo_xcb_surface_create_pattern (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static const struct cairo_surface_backend cairo_xcb_surface_backend = {
+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,
diff --git a/src/cairo-xcb.h b/src/cairo-xcb.h
new file mode 100644
index 000000000..27ebad523
--- /dev/null
+++ b/src/cairo-xcb.h
@@ -0,0 +1,54 @@
+/* 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@isi.edu>
+ */
+
+#include <cairo.h>
+
+#ifndef CAIRO_XCB_H
+#define CAIRO_XCB_H
+#ifdef CAIRO_HAS_XCB_SURFACE
+
+#include <X11/XCB/xcb.h>
+#include <X11/XCB/render.h>
+
+void
+cairo_set_target_xcb (cairo_t *cr,
+ XCBConnection *dpy,
+ XCBDRAWABLE drawable,
+ XCBVISUALTYPE *visual,
+ cairo_format_t format);
+
+#endif /* CAIRO_HAS_XCB_SURFACE */
+#endif /* CAIRO_XCB_H */
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index dda7995bd..d9d74f583 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -35,6 +35,7 @@
*/
#include "cairoint.h"
+#include "cairo-xlib.h"
void
cairo_set_target_drawable (cairo_t *cr,
@@ -61,7 +62,7 @@ cairo_set_target_drawable (cairo_t *cr,
cairo_surface_destroy (surface);
}
-typedef struct cairo_xlib_surface {
+typedef struct _cairo_xlib_surface {
cairo_surface_t base;
Display *dpy;
@@ -118,6 +119,16 @@ _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 cairo_surface_t *
_cairo_xlib_surface_create_similar (void *abstract_src,
cairo_format_t format,
int drawable,
@@ -149,7 +160,9 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
_CAIRO_FORMAT_DEPTH (format));
surface = (cairo_xlib_surface_t *)
- cairo_xlib_surface_create (dpy, pix, NULL, format, DefaultColormap (dpy, scr));
+ _cairo_xlib_surface_create_with_size (dpy, pix, NULL, format,
+ DefaultColormap (dpy, scr),
+ width, height);
surface->owns_pixmap = 1;
surface->width = width;
@@ -199,6 +212,7 @@ _cairo_xlib_surface_get_image (void *abstract_surface)
&surface->width, &surface->height,
&bwidth_ignore, &depth_ignore);
+ /* XXX: This should try to use the XShm extension if availible */
ximage = XGetImage (surface->dpy,
surface->drawable,
0, 0,
@@ -684,13 +698,13 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
cairo_font_scale_t *scale,
cairo_operator_t operator,
cairo_surface_t *source,
- cairo_surface_t *surface,
+ void *abstract_surface,
int source_x,
int source_y,
const cairo_glyph_t *glyphs,
int num_glyphs);
-static const struct cairo_surface_backend cairo_xlib_surface_backend = {
+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,
@@ -709,17 +723,17 @@ static const struct cairo_surface_backend cairo_xlib_surface_backend = {
_cairo_xlib_surface_show_glyphs
};
-cairo_surface_t *
-cairo_xlib_surface_create (Display *dpy,
- Drawable drawable,
- Visual *visual,
- cairo_format_t format,
- Colormap colormap)
+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;
- Window w;
- unsigned int ignore;
surface = malloc (sizeof (cairo_xlib_surface_t));
if (surface == NULL)
@@ -736,7 +750,9 @@ cairo_xlib_surface_create (Display *dpy,
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;
@@ -758,12 +774,6 @@ cairo_xlib_surface_create (Display *dpy,
break;
}
- XGetGeometry(dpy, drawable,
- &w, &ignore, &ignore,
- &surface->width,
- &surface->height,
- &ignore, &ignore);
-
/* XXX: I'm currently ignoring the colormap. Is that bad? */
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
surface->picture = XRenderCreatePicture (dpy, drawable,
@@ -776,8 +786,31 @@ cairo_xlib_surface_create (Display *dpy,
return (cairo_surface_t *) surface;
}
-DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create);
+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 */
@@ -839,8 +872,45 @@ _xlib_glyphset_cache_create_entry (void *cache,
v->info.width = im->image ? im->image->stride : im->size.width;
v->info.height = im->size.height;
- v->info.x = - im->extents.x_bearing;
- v->info.y = im->extents.y_bearing;
+
+ /*
+ * 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;
@@ -875,7 +945,7 @@ _xlib_glyphset_cache_destroy_entry (void *cache, void *entry)
free (v);
}
-const cairo_cache_backend_t _xlib_glyphset_cache_backend = {
+static const cairo_cache_backend_t _xlib_glyphset_cache_backend = {
_cairo_glyph_cache_hash,
_cairo_glyph_cache_keys_equal,
_xlib_glyphset_cache_create_entry,
@@ -964,6 +1034,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font,
unsigned int stack_chars [N_STACK_BUF];
int i;
+ int thisX, thisY;
int lastX = 0, lastY = 0;
/* Acquire arrays of suitable sizes. */
@@ -987,10 +1058,12 @@ _cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font,
elts[i].chars = &(chars[i]);
elts[i].nchars = 1;
elts[i].glyphset = g->glyphset;
- elts[i].xOff = glyphs[i].x - lastX;
- elts[i].yOff = glyphs[i].y - lastY;
- lastX = glyphs[i].x;
- lastY = glyphs[i].y;
+ 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,
@@ -1039,6 +1112,7 @@ _cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font,
unsigned short stack_chars [N_STACK_BUF];
int i;
+ int thisX, thisY;
int lastX = 0, lastY = 0;
/* Acquire arrays of suitable sizes. */
@@ -1062,10 +1136,12 @@ _cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font,
elts[i].chars = &(chars[i]);
elts[i].nchars = 1;
elts[i].glyphset = g->glyphset;
- elts[i].xOff = glyphs[i].x - lastX;
- elts[i].yOff = glyphs[i].y - lastY;
- lastX = glyphs[i].x;
- lastY = glyphs[i].y;
+ 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,
@@ -1113,6 +1189,7 @@ _cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font,
char stack_chars [N_STACK_BUF];
int i;
+ int thisX, thisY;
int lastX = 0, lastY = 0;
/* Acquire arrays of suitable sizes. */
@@ -1136,10 +1213,12 @@ _cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font,
elts[i].chars = &(chars[i]);
elts[i].nchars = 1;
elts[i].glyphset = g->glyphset;
- elts[i].xOff = glyphs[i].x - lastX;
- elts[i].yOff = glyphs[i].y - lastY;
- lastX = glyphs[i].x;
- lastY = glyphs[i].y;
+ 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,
@@ -1172,14 +1251,14 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
cairo_font_scale_t *scale,
cairo_operator_t operator,
cairo_surface_t *source,
- cairo_surface_t *surface,
+ void *abstract_surface,
int source_x,
int source_y,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
unsigned int elt_size;
- cairo_xlib_surface_t *self = (cairo_xlib_surface_t *) surface;
+ cairo_xlib_surface_t *self = abstract_surface;
cairo_image_surface_t *tmp = NULL;
cairo_xlib_surface_t *src = NULL;
glyphset_cache_t *g;
@@ -1200,7 +1279,7 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
}
/* prep the source surface. */
- if (source->backend == surface->backend) {
+ if (source->backend == self->base.backend) {
src = (cairo_xlib_surface_t *) source;
} else {
@@ -1209,7 +1288,7 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
goto FREE_ENTRIES;
src = (cairo_xlib_surface_t *)
- _cairo_surface_create_similar_scratch (surface, self->format, 1,
+ _cairo_surface_create_similar_scratch (&self->base, self->format, 1,
tmp->width, tmp->height);
if (src == NULL)
diff --git a/src/cairo-xlib.h b/src/cairo-xlib.h
new file mode 100644
index 000000000..4f241b034
--- /dev/null
+++ b/src/cairo-xlib.h
@@ -0,0 +1,71 @@
+/* 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@isi.edu>
+ */
+
+#include <cairo.h>
+
+#ifndef CAIRO_XLIB_H
+#define CAIRO_XLIB_H
+#ifdef CAIRO_HAS_XLIB_SURFACE
+
+#include <X11/extensions/Xrender.h>
+
+/* 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);
+
+/* 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);
+*/
+
+#endif /* CAIRO_HAS_XLIB_SURFACE */
+#endif /* CAIRO_XLIB_H */
+
diff --git a/src/cairo.c b/src/cairo.c
index 7e6f1d7b4..20d94938c 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -39,12 +39,14 @@
#define CAIRO_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */
-
#ifdef CAIRO_DO_SANITY_CHECKING
#include <assert.h>
static int
cairo_sane_state (cairo_t *cr)
{
+ if (cr == NULL)
+ return 0;
+
switch (cr->status) {
case CAIRO_STATUS_SUCCESS:
case CAIRO_STATUS_NO_MEMORY:
@@ -56,7 +58,6 @@ cairo_sane_state (cairo_t *cr)
case CAIRO_STATUS_NULL_POINTER:
break;
default:
- printf ("cairo status is bad: %d\n", cr->status);
return 0;
}
return 1;
@@ -159,6 +160,12 @@ cairo_restore (cairo_t *cr)
if (cr->gstate == NULL)
cr->status = CAIRO_STATUS_INVALID_RESTORE;
+
+ if (cr->status)
+ return;
+
+ cr->status = _cairo_gstate_restore_external_state (cr->gstate);
+
CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_restore);
diff --git a/src/cairo.h b/src/cairo.h
index 25dfd4d6b..b7bcc1dbb 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -34,18 +34,16 @@
* Carl D. Worth <cworth@isi.edu>
*/
-#ifndef _CAIRO_H_
-#define _CAIRO_H_
+#ifndef CAIRO_H
+#define CAIRO_H
#include <cairo-features.h>
-
#include <pixman.h>
-#include <stdio.h>
-typedef struct cairo cairo_t;
-typedef struct cairo_surface cairo_surface_t;
-typedef struct cairo_matrix cairo_matrix_t;
-typedef struct cairo_pattern cairo_pattern_t;
+typedef struct _cairo cairo_t;
+typedef struct _cairo_surface cairo_surface_t;
+typedef struct _cairo_matrix cairo_matrix_t;
+typedef struct _cairo_pattern cairo_pattern_t;
#ifdef __cplusplus
extern "C" {
@@ -98,67 +96,6 @@ cairo_set_target_image (cairo_t *cr,
int height,
int stride);
-#ifdef CAIRO_HAS_PS_SURFACE
-
-#include <stdio.h>
-
-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);
-
-#endif /* CAIRO_HAS_PS_SURFACE */
-
-#ifdef CAIRO_HAS_PNG_SURFACE
-
-#include <stdio.h>
-
-void
-cairo_set_target_png (cairo_t *cr,
- FILE *file,
- cairo_format_t format,
- int width,
- int height);
-
-#endif /* CAIRO_HAS_PNG_SURFACE */
-
-#ifdef CAIRO_HAS_XLIB_SURFACE
-
-#include <X11/extensions/Xrender.h>
-
-/* 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);
-#endif /* CAIRO_HAS_XLIB_SURFACE */
-
-#ifdef CAIRO_HAS_XCB_SURFACE
-
-#include <X11/XCB/xcb.h>
-#include <X11/XCB/render.h>
-
-void
-cairo_set_target_xcb (cairo_t *cr,
- XCBConnection *dpy,
- XCBDRAWABLE drawable,
- XCBVISUALTYPE *visual,
- cairo_format_t format);
-#endif /* CAIRO_HAS_XCB_SURFACE */
-
-#ifdef CAIRO_HAS_GLITZ_SURFACE
-
-#include <glitz.h>
-
-void
-cairo_set_target_glitz (cairo_t *cr,
- glitz_surface_t *surface);
-#endif /* CAIRO_HAS_GLITZ_SURFACE */
-
typedef enum cairo_operator {
CAIRO_OPERATOR_CLEAR,
CAIRO_OPERATOR_SRC,
@@ -393,7 +330,7 @@ cairo_clip (cairo_t *cr);
/* Font/Text functions */
-typedef struct cairo_font cairo_font_t;
+typedef struct _cairo_font cairo_font_t;
typedef struct {
unsigned long index;
@@ -493,27 +430,6 @@ void
cairo_font_current_transform (cairo_font_t *font,
cairo_matrix_t *matrix);
-/* Fontconfig/Freetype platform-specific font interface */
-
-#include <fontconfig/fontconfig.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
-cairo_font_t *
-cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern);
-
-cairo_font_t *
-cairo_ft_font_create_for_ft_face (FT_Face face);
-
-void
-cairo_ft_font_destroy (cairo_font_t *ft_font);
-
-FT_Face
-cairo_ft_font_face (cairo_font_t *ft_font);
-
-FcPattern *
-cairo_ft_font_pattern (cairo_font_t *ft_font);
-
/* Image functions */
/* XXX: Eliminate width/height here */
@@ -738,59 +654,6 @@ cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter);
cairo_filter_t
cairo_pattern_get_filter (cairo_pattern_t *pattern);
-#ifdef CAIRO_HAS_PS_SURFACE
-
-/* 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);
-
-#endif /* CAIRO_HAS_PS_SURFACE */
-
-#ifdef CAIRO_HAS_PNG_SURFACE
-
-/* PNG-surface functions */
-
-cairo_surface_t *
-cairo_png_surface_create (FILE *file,
- cairo_format_t format,
- int width,
- int height);
-
-#endif /* CAIRO_HAS_PNG_SURFACE */
-
-#ifdef CAIRO_HAS_XLIB_SURFACE
-
-/* 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);
-*/
-
-#endif /* CAIRO_HAS_XLIB_SURFACE */
-
-#ifdef CAIRO_HAS_GLITZ_SURFACE
-
-cairo_surface_t *
-cairo_glitz_surface_create (glitz_surface_t *surface);
-
-#endif /* CAIRO_HAS_GLITZ_SURFACE */
-
/* Matrix functions */
/* XXX: Rename all of these to cairo_transform_t */
@@ -865,4 +728,4 @@ cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y);
}
#endif
-#endif
+#endif /* CAIRO_H */
diff --git a/src/cairo_array.c b/src/cairo_array.c
new file mode 100644
index 000000000..2b1cf9d61
--- /dev/null
+++ b/src/cairo_array.c
@@ -0,0 +1,134 @@
+/* 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
new file mode 100644
index 000000000..52cfc6bd8
--- /dev/null
+++ b/src/cairo_atsui_font.c
@@ -0,0 +1,807 @@
+/* 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
index a33d69a04..b097b609b 100644
--- a/src/cairo_cache.c
+++ b/src/cairo_cache.c
@@ -43,7 +43,7 @@
* Packard.
*/
-static cairo_cache_arrangement_t cache_arrangements [] = {
+static const cairo_cache_arrangement_t cache_arrangements [] = {
{ 16, 43, 41 },
{ 32, 73, 71 },
{ 64, 151, 149 },
@@ -114,7 +114,6 @@ static cairo_cache_arrangement_t cache_arrangements [] = {
(!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i)))))
#ifdef CAIRO_DO_SANITY_CHECKING
-#include <assert.h>
static void
_cache_sane_state (cairo_cache_t *cache)
{
@@ -122,13 +121,12 @@ _cache_sane_state (cairo_cache_t *cache)
assert (cache->entries != NULL);
assert (cache->backend != NULL);
assert (cache->arrangement != NULL);
- assert (cache->refcount > 0);
- assert (cache->used_memory <= cache->max_memory);
+ /* 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)
-#define assert(x)
#endif
static void
@@ -140,7 +138,7 @@ _entry_destroy (cairo_cache_t *cache, unsigned long i)
{
cairo_cache_entry_base_t *entry = cache->entries[i];
assert(cache->live_entries > 0);
- assert(cache->used_memory > entry->memory);
+ assert(cache->used_memory >= entry->memory);
cache->live_entries--;
cache->used_memory -= entry->memory;
@@ -183,10 +181,12 @@ _cache_lookup (cairo_cache_t *cache,
if (predicate != NULL)
{
/* We are looking up an exact entry. */
- if (*probe != NULL
- && *probe != DEAD_ENTRY
- && (*probe)->hashcode == hash
- && predicate (cache, key, *probe))
+ 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
@@ -230,8 +230,7 @@ _find_exact_live_entry_for (cairo_cache_t *cache,
return _cache_lookup (cache, key, cache->backend->keys_equal);
}
-
-static cairo_cache_arrangement_t *
+static const cairo_cache_arrangement_t *
_find_cache_arrangement (unsigned long proposed_size)
{
unsigned long idx;
@@ -302,7 +301,7 @@ _cairo_cache_init (cairo_cache_t *cache,
const cairo_cache_backend_t *backend,
unsigned long max_memory)
{
- assert(backend != NULL);
+ assert (backend != NULL);
if (cache != NULL){
cache->arrangement = &cache_arrangements[0];
@@ -342,7 +341,7 @@ _cairo_cache_destroy (cairo_cache_t *cache)
_cache_sane_state (cache);
- if (cache->refcount-- > 0)
+ if (--cache->refcount > 0)
return;
for (i = 0; i < cache->arrangement->size; ++i) {
@@ -419,7 +418,8 @@ _cairo_cache_lookup (cairo_cache_t *cache,
_entry_destroy (cache, idx);
}
- assert(cache->max_memory >= (cache->used_memory + new_entry->memory));
+ /* 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);
diff --git a/src/cairo_color.c b/src/cairo_color.c
index 2fe793ac8..899b1e3d5 100644
--- a/src/cairo_color.c
+++ b/src/cairo_color.c
@@ -36,7 +36,7 @@
#include "cairoint.h"
-static cairo_color_t const CAIRO_COLOR_DEFAULT = {
+static cairo_color_t const CAIRO_COLOR_WHITE = {
1.0, 1.0, 1.0, 1.0,
0xffff, 0xffff, 0xffff, 0xffff
};
@@ -47,7 +47,7 @@ _cairo_color_compute_shorts (cairo_color_t *color);
void
_cairo_color_init (cairo_color_t *color)
{
- *color = CAIRO_COLOR_DEFAULT;
+ *color = CAIRO_COLOR_WHITE;
}
void
@@ -69,9 +69,12 @@ _cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blu
void
_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue)
{
- *red = color->red;
- *green = color->green;
- *blue = color->blue;
+ if (red)
+ *red = color->red;
+ if (green)
+ *green = color->green;
+ if (blue)
+ *blue = color->blue;
}
void
diff --git a/src/cairo_fixed.c b/src/cairo_fixed.c
index 32368d7fc..ee31718ef 100644
--- a/src/cairo_fixed.c
+++ b/src/cairo_fixed.c
@@ -71,3 +71,21 @@ _cairo_fixed_integer_part (cairo_fixed_t f)
{
return f >> 16;
}
+
+int
+_cairo_fixed_integer_floor (cairo_fixed_t f)
+{
+ if (f >= 0)
+ return f >> 16;
+ else
+ return -((-f - 1) >> 16) - 1;
+}
+
+int
+_cairo_fixed_integer_ceil (cairo_fixed_t f)
+{
+ if (f >= 0)
+ return ((f - 1)>>16) + 1;
+ else
+ return - (-f >> 16);
+}
diff --git a/src/cairo_font.c b/src/cairo_font.c
index 5ad9f0417..f5fc0e981 100644
--- a/src/cairo_font.c
+++ b/src/cairo_font.c
@@ -36,7 +36,6 @@
#include "cairoint.h"
-
/* First we implement a global font cache for named fonts. */
typedef struct {
@@ -54,9 +53,9 @@ typedef struct {
static unsigned long
_font_cache_hash (void *cache, void *key)
{
+ unsigned long hash;
cairo_font_cache_key_t *in;
in = (cairo_font_cache_key_t *) key;
- unsigned long hash;
/* 1607 and 1451 are just a couple random primes. */
hash = _cairo_hash_string (in->family);
@@ -86,12 +85,11 @@ _font_cache_create_entry (void *cache,
void *key,
void **return_value)
{
+ const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
cairo_font_cache_key_t *k;
cairo_font_cache_entry_t *entry;
k = (cairo_font_cache_key_t *) key;
- const struct cairo_font_backend *backend = CAIRO_FONT_BACKEND_DEFAULT;
-
/* XXX: The current freetype backend may return NULL, (for example
* if no fonts are installed), but I would like to guarantee that
* the toy API always returns at least *some* font, so I would
@@ -145,7 +143,7 @@ _font_cache_destroy_cache (void *cache)
free (cache);
}
-const struct cairo_cache_backend cairo_font_cache_backend = {
+static const cairo_cache_backend_t cairo_font_cache_backend = {
_font_cache_hash,
_font_cache_keys_equal,
_font_cache_create_entry,
@@ -153,7 +151,6 @@ const struct cairo_cache_backend cairo_font_cache_backend = {
_font_cache_destroy_cache
};
-
static void
_lock_global_font_cache (void)
{
@@ -239,8 +236,8 @@ _cairo_font_init (cairo_font_t *scaled,
}
cairo_status_t
-_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_font_backend_t *backend)
{
font->refcount = 1;
font->backend = backend;
@@ -476,7 +473,7 @@ _image_glyph_cache_destroy_cache (void *cache)
free (cache);
}
-const cairo_cache_backend_t cairo_image_cache_backend = {
+static const cairo_cache_backend_t cairo_image_cache_backend = {
_cairo_glyph_cache_hash,
_cairo_glyph_cache_keys_equal,
_image_glyph_cache_create_entry,
@@ -484,7 +481,6 @@ const cairo_cache_backend_t cairo_image_cache_backend = {
_image_glyph_cache_destroy_cache
};
-
void
_cairo_lock_global_image_glyph_cache()
{
diff --git a/src/cairo_ft_font.c b/src/cairo_ft_font.c
index f757db09c..b928b04fc 100644
--- a/src/cairo_ft_font.c
+++ b/src/cairo_ft_font.c
@@ -23,6 +23,8 @@
*/
#include "cairoint.h"
+#include "cairo-ft.h"
+
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
@@ -50,6 +52,16 @@ typedef struct {
} ft_font_val_t;
+/*
+ * 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;
+
static ft_font_val_t *
_create_from_face (FT_Face face, int owns_face)
{
@@ -246,7 +258,7 @@ _ft_font_cache_destroy_cache (void *cache)
free (fc);
}
-const struct cairo_cache_backend _ft_font_cache_backend = {
+static const cairo_cache_backend_t _ft_font_cache_backend = {
_ft_font_cache_hash,
_ft_font_cache_keys_equal,
_ft_font_cache_create_entry,
@@ -254,7 +266,6 @@ const struct cairo_cache_backend _ft_font_cache_backend = {
_ft_font_cache_destroy_cache
};
-
static ft_cache_t *_global_ft_cache = NULL;
static void
@@ -297,7 +308,7 @@ _get_global_ft_cache (void)
/* implement the backend interface */
-const struct cairo_font_backend cairo_ft_font_backend;
+const cairo_font_backend_t cairo_ft_font_backend;
static cairo_unscaled_font_t *
_cairo_ft_font_create (const char *family,
@@ -402,10 +413,10 @@ _cairo_ft_font_destroy (void *abstract_font)
static void
_utf8_to_ucs4 (char const *utf8,
FT_ULong **ucs4,
- size_t *nchars)
+ int *nchars)
{
int len = 0, step = 0;
- size_t n = 0, alloc = 0;
+ int n = 0, alloc = 0;
FcChar32 u = 0;
if (utf8 == NULL || ucs4 == NULL || nchars == NULL)
@@ -433,11 +444,67 @@ _utf8_to_ucs4 (char const *utf8,
*nchars = n;
}
+/*
+ * Split a matrix into the component pieces of scale and shape
+ */
+
+static void
+_cairo_ft_font_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);
+}
+
+/*
+ * Set the font transformation
+ */
+
+static void
+_cairo_ft_font_install_transform (ft_font_transform_t *sf, FT_Face face)
+{
+ FT_Matrix mat;
+
+ 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(face, &mat, NULL);
+
+ FT_Set_Char_Size(face,
+ (FT_F26Dot6) (sf->x_scale * 64.0),
+ (FT_F26Dot6) (sf->y_scale * 64.0),
+ 0, 0);
+}
+
static void
_install_font_scale (cairo_font_scale_t *sc, FT_Face face)
{
cairo_matrix_t normalized;
- double scale_x, scale_y;
+ double x_scale, y_scale;
double xx, xy, yx, yy, tx, ty;
FT_Matrix mat;
@@ -455,8 +522,9 @@ _install_font_scale (cairo_font_scale_t *sc, FT_Face face)
sc->matrix[1][1],
0, 0);
- _cairo_matrix_compute_scale_factors (&normalized, &scale_x, &scale_y);
- cairo_matrix_scale (&normalized, 1.0 / scale_x, 1.0 / scale_y);
+ _cairo_matrix_compute_scale_factors (&normalized, &x_scale, &y_scale,
+ /* XXX */ 1);
+ cairo_matrix_scale (&normalized, 1.0 / x_scale, 1.0 / y_scale);
cairo_matrix_get_affine (&normalized,
&xx /* 00 */ , &yx /* 01 */,
&xy /* 10 */, &yy /* 11 */,
@@ -470,8 +538,8 @@ _install_font_scale (cairo_font_scale_t *sc, FT_Face face)
FT_Set_Transform(face, &mat, NULL);
FT_Set_Pixel_Sizes(face,
- (FT_UInt) scale_x,
- (FT_UInt) scale_y);
+ (FT_UInt) x_scale,
+ (FT_UInt) y_scale);
}
static cairo_status_t
@@ -481,6 +549,9 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
cairo_glyph_t **glyphs,
int *nglyphs)
{
+ double x = 0., y = 0.;
+ size_t i;
+ FT_ULong *ucs4 = NULL;
cairo_ft_font_t *font = abstract_font;
FT_Face face = font->val->face;
cairo_glyph_cache_key_t key;
@@ -490,10 +561,6 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
key.unscaled = &font->base;
key.scale = *sc;
- double x = 0., y = 0.;
- size_t i;
- FT_ULong *ucs4 = NULL;
-
_utf8_to_ucs4 (utf8, &ucs4, nglyphs);
if (ucs4 == NULL)
@@ -527,7 +594,7 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
continue;
x += val->extents.x_advance;
- y -= val->extents.y_advance;
+ y += val->extents.y_advance;
}
_cairo_unlock_global_image_glyph_cache ();
@@ -544,13 +611,19 @@ _cairo_ft_font_font_extents (void *abstract_font,
cairo_ft_font_t *font = abstract_font;
FT_Face face = font->val->face;
FT_Size_Metrics *metrics = &face->size->metrics;
+ ft_font_transform_t sf;
- _install_font_scale (sc, face);
+ _cairo_ft_font_compute_transform (&sf, sc);
+ _cairo_ft_font_install_transform (&sf, face);
- extents->ascent = DOUBLE_FROM_26_6(metrics->ascender);
- extents->descent = DOUBLE_FROM_26_6(metrics->descender);
- extents->height = DOUBLE_FROM_26_6(metrics->height);
- extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance);
+ /*
+ * Get to unscaled metrics so that the upper level can get back to
+ * user space
+ */
+ extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / sf.y_scale;
+ extents->descent = DOUBLE_FROM_26_6(metrics->descender) / sf.y_scale;
+ extents->height = DOUBLE_FROM_26_6(metrics->height) / sf.y_scale;
+ extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / sf.x_scale;
/* FIXME: this doesn't do vertical layout atm. */
extents->max_y_advance = 0.0;
@@ -614,7 +687,7 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
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_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;
@@ -635,12 +708,12 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
}
_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_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 + 0 - origin.y;
+ extents->y_advance = glyphs[i-1].y + (img == NULL ? 0 : img->extents.y_advance) - origin.y;
return CAIRO_STATUS_SUCCESS;
}
@@ -688,7 +761,7 @@ _cairo_ft_font_glyph_bbox (void *abstract_font,
continue;
x1 = _cairo_fixed_from_double (glyphs[i].x + img->size.x);
- y1 = _cairo_fixed_from_double (glyphs[i].y - img->size.y);
+ 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);
@@ -763,10 +836,10 @@ _cairo_ft_font_show_glyphs (void *abstract_font,
&(img->image->base),
surface,
source_x + x + img->size.x,
- source_y + y - img->size.y,
+ source_y + y + img->size.y,
0, 0,
x + img->size.x,
- y - img->size.y,
+ y + img->size.y,
(double) img->size.width,
(double) img->size.height);
@@ -919,21 +992,39 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
FT_BBox cbox;
FT_Bitmap bitmap;
FT_Glyph_Metrics *metrics;
+ ft_font_transform_t sf;
glyphslot = font->val->face->glyph;
metrics = &glyphslot->metrics;
- _install_font_scale (&val->key.scale, font->val->face);
+ _cairo_ft_font_compute_transform (&sf, &val->key.scale);
+ _cairo_ft_font_install_transform (&sf, font->val->face);
if (FT_Load_Glyph (font->val->face, val->key.index, FT_LOAD_DEFAULT) != 0)
return CAIRO_STATUS_NO_MEMORY;
- val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX);
- val->extents.y_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingY);
- val->extents.width = DOUBLE_FROM_26_6 (metrics->width);
- val->extents.height = DOUBLE_FROM_26_6 (metrics->height);
- val->extents.x_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->advance.x);
- val->extents.y_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->advance.y);
+ /*
+ * 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) / sf.x_scale;
+ val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / sf.y_scale;
+
+ val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / sf.x_scale;
+ val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / sf.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 (font->val->face->glyph->metrics.horiAdvance) / sf.x_scale;
+ val->extents.y_advance = 0 / sf.y_scale;
outline = &glyphslot->outline;
@@ -982,16 +1073,21 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
_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);
+ val->size.x = (short) (cbox.xMin >> 6);
+ val->size.y = - (short) (cbox.yMax >> 6);
return CAIRO_STATUS_SUCCESS;
}
-const struct cairo_font_backend cairo_ft_font_backend = {
+const cairo_font_backend_t cairo_ft_font_backend = {
_cairo_ft_font_create,
_cairo_ft_font_destroy,
_cairo_ft_font_font_extents,
diff --git a/src/cairo_gdip_font.cpp b/src/cairo_gdip_font.cpp
new file mode 100644
index 000000000..e932e3bac
--- /dev/null
+++ b/src/cairo_gdip_font.cpp
@@ -0,0 +1,665 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 Stuart Parmenter
+ *
+ * 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 Stuart Parmenter.
+ *
+ * Contributor(s):
+ * Stuart Parmenter <pavlov@pavlov.net>
+ */
+
+extern "C" {
+#include "cairoint.h"
+}
+
+#include <windows.h>
+
+#include <gdiplus.h>
+using namespace Gdiplus;
+
+#if 0
+#include <fontconfig/fontconfig.h>
+#include <fontconfig/fcfreetype.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+#include FT_IMAGE_H
+#endif
+
+typedef struct {
+ cairo_font_t base;
+ HDC hdc;
+ HFONT hfont;
+} cairo_win32_font_t;
+
+
+
+static int
+_utf8_to_glyphs (cairo_win32_font_t *font,
+ const unsigned char *utf8,
+ double x0,
+ double y0,
+ cairo_glyph_t **glyphs,
+ size_t *nglyphs)
+{
+ /* XXX implement me */
+ *glyphs = NULL;
+ *nglyphs = 0;
+
+ return 0;
+}
+
+/* implement the platform-specific interface */
+
+cairo_font_t *
+cairo_win32_font_create (HFONT hfont)
+{
+ cairo_win32_font_t *f = (cairo_win32_font_t*)malloc(sizeof(cairo_win32_font_t));
+ if (f == NULL)
+ return NULL;
+
+ f->hfont = hfont;
+
+ _cairo_font_init (&f->base, &cairo_win32_font_backend);
+
+ return (cairo_font_t *) f;
+}
+
+#if 0
+FT_Face
+cairo_win32_font_face (cairo_font_t *abstract_font)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t *) abstract_font;
+
+ if (font == NULL)
+ return NULL;
+
+ return font->face;
+}
+
+FcPattern *
+cairo_win32_font_pattern (cairo_font_t *abstract_font)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t *) abstract_font;
+
+ if (font == NULL)
+ return NULL;
+
+ return font->pattern;
+}
+#endif
+
+/* implement the backend interface */
+
+static cairo_font_t *
+_cairo_win32_font_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight)
+{
+ int fontHeight = 60; // in Pixels in this case
+ int fontWidth = 0;
+ int italic = 0;
+ int bold = FW_REGULAR;
+
+ switch (slant) {
+ case CAIRO_FONT_SLANT_ITALIC:
+ italic = 1;
+ case CAIRO_FONT_SLANT_OBLIQUE:
+ case CAIRO_FONT_SLANT_NORMAL:
+ default:
+ break;
+ }
+
+ if (weight == CAIRO_FONT_WEIGHT_BOLD)
+ bold = FW_BOLD;
+
+ HFONT hfont = CreateFont(fontHeight, // height of font
+ fontWidth, // average character width
+ 0, // angle of escapement
+ 0, // base-line orientation angle
+ bold, // font weight
+ italic, // italic attribute option
+ FALSE, // underline attribute option
+ FALSE, // strikeout attribute option
+ ANSI_CHARSET, // character set identifier
+ OUT_DEFAULT_PRECIS, // output precision
+ CLIP_DEFAULT_PRECIS, // clipping precision
+ ANTIALIASED_QUALITY, // output quality
+ FF_DONTCARE, // pitch and family
+ family); // typeface name
+
+ return cairo_win32_font_create(hfont);
+}
+
+static cairo_font_t *
+_cairo_win32_font_copy (void *abstract_font)
+{
+ cairo_win32_font_t *font_new = NULL;
+ cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
+
+ if (font->base.backend != &cairo_win32_font_backend)
+ return NULL;
+
+ font_new = (cairo_win32_font_t *) cairo_win32_font_create(font->hfont);
+ if (font_new == NULL)
+ return NULL;
+
+ return (cairo_font_t *) font_new;
+}
+
+static void
+_cairo_win32_font_destroy (void *abstract_font)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
+
+ //delete font->font;
+
+ free (font);
+}
+
+static cairo_status_t
+_cairo_win32_font_font_extents (void *abstract_font,
+ cairo_font_extents_t *extents)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
+
+ TEXTMETRIC metrics;
+ GetTextMetrics(font->hdc, &metrics);
+
+ extents->ascent = metrics.tmAscent;
+ extents->descent = metrics.tmDescent;
+ extents->height = metrics.tmHeight;
+ extents->max_x_advance = 0; /* XXX */
+ extents->max_y_advance = 0; /* XXX */
+
+
+#if 0
+ FT_Face face = font->face;
+ double scale_x, scale_y;
+
+ double upm = face->units_per_EM;
+
+ _cairo_matrix_compute_scale_factors (&font->base.matrix, &scale_x, &scale_y);
+
+ extents->ascent = face->ascender / upm * scale_y;
+ extents->descent = face->descender / upm * scale_y;
+ extents->height = face->height / upm * scale_y;
+ extents->max_x_advance = face->max_advance_width / upm * scale_x;
+ extents->max_y_advance = face->max_advance_height / upm * scale_y;
+#endif
+ 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 = (cairo_win32_font_t*)abstract_font;
+
+ int i;
+ for (i = 0; i < num_glyphs; ++i) {
+ GLYPHMETRICS metrics;
+ GetGlyphOutline(font->hdc, 'a', GGO_METRICS, &metrics, 0, NULL, NULL);
+
+ extents->width += metrics.gmBlackBoxX;
+ extents->height += metrics.gmBlackBoxY;
+ /* metrics has:
+ UINT gmBlackBoxX;
+ UINT gmBlackBoxY;
+ POINT gmptGlyphOrigin;
+ short gmCellIncX;
+ short gmCellIncY;
+
+ extents has:
+ double x_bearing;
+ double y_bearing;
+ double width;
+ double height;
+ double x_advance;
+ double y_advance;
+ */
+ }
+
+#if 0
+ int i;
+ cairo_win32_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;
+ FT_Error error;
+ FT_Face face = font->face;
+ FT_GlyphSlot glyph = face->glyph;
+ FT_Glyph_Metrics *metrics = &glyph->metrics;
+
+ 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;
+
+ _install_font_matrix (&font->base.matrix, face);
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ error = FT_Load_Glyph (face, glyphs[i].index, FT_LOAD_DEFAULT);
+ /* XXX: What to do in this error case? */
+ if (error)
+ 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_win32_font_create_for_ft_face accept an
+ FcPattern. */
+ glyph_min.x = glyphs[i].x + DOUBLE_FROM_26_6 (metrics->horiBearingX);
+ glyph_min.y = glyphs[i].y - DOUBLE_FROM_26_6 (metrics->horiBearingY);
+ glyph_max.x = glyph_min.x + DOUBLE_FROM_26_6 (metrics->width);
+ glyph_max.y = glyph_min.y + DOUBLE_FROM_26_6 (metrics->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;
+ }
+ }
+
+ 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 + DOUBLE_FROM_26_6 (metrics->horiAdvance) - origin.x;
+ extents->y_advance = glyphs[i-1].y + 0 - origin.y;
+#endif
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+static cairo_status_t
+_cairo_win32_font_text_extents (void *abstract_font,
+ const unsigned char *utf8,
+ cairo_text_extents_t *extents)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
+
+ cairo_glyph_t *glyphs;
+ size_t nglyphs;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ if (_utf8_to_glyphs (font, utf8, 0, 0, &glyphs, &nglyphs))
+ {
+ status = _cairo_win32_font_glyph_extents (font, glyphs, nglyphs,
+ extents);
+ free (glyphs);
+ }
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_win32_font_glyph_bbox (void *abstract_font,
+ cairo_surface_t *surface,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
+#if 0
+ cairo_surface_t *mask = NULL;
+ cairo_glyph_size_t size;
+
+ 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;
+
+ if (font == NULL
+ || surface == NULL
+ || glyphs == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ mask = _cairo_font_lookup_glyph (&font->base, surface,
+ &glyphs[i], &size);
+ if (mask == NULL)
+ continue;
+
+ x1 = _cairo_fixed_from_double (glyphs[i].x + size.x);
+ y1 = _cairo_fixed_from_double (glyphs[i].y - size.y);
+ x2 = x1 + _cairo_fixed_from_double (size.width);
+ y2 = y1 + _cairo_fixed_from_double (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;
+
+ if (mask)
+ cairo_surface_destroy (mask);
+ }
+#endif
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_font_text_bbox (void *abstract_font,
+ cairo_surface_t *surface,
+ double x0,
+ double y0,
+ const unsigned char *utf8,
+ cairo_box_t *bbox)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
+
+ cairo_glyph_t *glyphs;
+ size_t num_glyphs;
+
+ if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs))
+ {
+ cairo_status_t res;
+ res = _cairo_win32_font_glyph_bbox (font, surface,
+ glyphs, num_glyphs, bbox);
+ free (glyphs);
+ return res;
+ }
+ else
+ return CAIRO_STATUS_NO_MEMORY;
+}
+
+static cairo_status_t
+_cairo_win32_font_show_glyphs (void *abstract_font,
+ cairo_operator_t op,
+ cairo_surface_t *source,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
+#if 0
+ cairo_status_t status;
+ cairo_surface_t *mask = NULL;
+ cairo_glyph_size_t size;
+
+ double x, y;
+ int i;
+
+ if (font == NULL
+ || source == NULL
+ || surface == NULL
+ || glyphs == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ mask = _cairo_font_lookup_glyph (&font->base, surface,
+ &glyphs[i], &size);
+ if (mask == NULL)
+ continue;
+
+ x = glyphs[i].x;
+ y = glyphs[i].y;
+
+ status = _cairo_surface_composite (operator, source, mask, surface,
+ source_x + x + size.x,
+ source_y + y - size.y,
+ 0, 0,
+ x + size.x,
+ y - size.y,
+ (double) size.width,
+ (double) size.height);
+
+ cairo_surface_destroy (mask);
+
+ if (status)
+ return status;
+ }
+#endif
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_font_show_text (void *abstract_font,
+ cairo_operator_t op,
+ cairo_surface_t *source,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ double x0,
+ double y0,
+ const unsigned char *utf8)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
+
+ cairo_glyph_t *glyphs;
+ size_t num_glyphs;
+
+ if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs))
+ {
+ cairo_status_t res;
+ res = _cairo_win32_font_show_glyphs (font, op,
+ source, surface,
+ source_x, source_y,
+ glyphs, num_glyphs);
+ free (glyphs);
+ return res;
+ }
+ else
+ return CAIRO_STATUS_NO_MEMORY;
+}
+
+static cairo_status_t
+_cairo_win32_font_glyph_path (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_t *path)
+{
+#if 0
+ int i;
+ cairo_win32_font_t *font = abstract_font;
+ FT_GlyphSlot glyph;
+ FT_Error error;
+ FT_Outline_Funcs outline_funcs = {
+ _move_to,
+ _line_to,
+ _conic_to,
+ _cubic_to,
+ 0, /* shift */
+ 0, /* delta */
+ };
+
+ glyph = font->face->glyph;
+ _install_font_matrix (&font->base.matrix, font->face);
+
+ 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->face, glyphs[i].index, FT_LOAD_DEFAULT);
+ /* 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);
+#endif
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_font_text_path (void *abstract_font,
+ double x,
+ double y,
+ const unsigned char *utf8,
+ cairo_path_t *path)
+{
+#if 0
+ cairo_win32_font_t *font = abstract_font;
+ cairo_glyph_t *glyphs;
+ size_t nglyphs;
+
+ if (_utf8_to_glyphs (font, utf8, x, y, &glyphs, &nglyphs))
+ {
+ cairo_status_t res;
+ res = _cairo_win32_font_glyph_path (font, glyphs, nglyphs, path);
+ free (glyphs);
+ return res;
+ }
+ else
+#endif
+ return CAIRO_STATUS_NO_MEMORY;
+}
+
+static cairo_surface_t *
+_cairo_win32_font_create_glyph (void *abstract_font,
+ const cairo_glyph_t *glyph,
+ cairo_glyph_size_t *return_size)
+{
+#if 0
+ cairo_win32_font_t *font = abstract_font;
+ cairo_image_surface_t *image;
+ FT_GlyphSlot glyphslot;
+ unsigned int width, height, stride;
+ FT_Outline *outline;s
+ FT_BBox cbox;
+ FT_Bitmap bitmap;
+
+ glyphslot = font->face->glyph;
+ _install_font_matrix (&font->base.matrix, font->face);
+
+ FT_Load_Glyph (font->face, glyph->index, FT_LOAD_DEFAULT);
+
+ 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;
+
+ bitmap.pixel_mode = ft_pixel_mode_grays;
+ bitmap.num_grays = 256;
+ bitmap.width = width;
+ bitmap.rows = height;
+ bitmap.pitch = stride;
+
+ if (width * height == 0)
+ return NULL;
+
+ bitmap.buffer = malloc (stride * height);
+ if (bitmap.buffer == NULL)
+ return NULL;
+
+ memset (bitmap.buffer, 0x0, stride * height);
+
+ FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin);
+ FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap);
+
+ image = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data ((char *) bitmap.buffer,
+ CAIRO_FORMAT_A8,
+ width, height, stride);
+ if (image == NULL) {
+ free (bitmap.buffer);
+ return NULL;
+ }
+
+ _cairo_image_surface_assume_ownership_of_data (image);
+
+ return_size->width = (unsigned short) width;
+ return_size->height = (unsigned short) height;
+ return_size->x = (short) (cbox.xMin >> 6);
+ return_size->y = (short) (cbox.yMax >> 6);
+
+ return &image->base;
+#endif
+ return NULL;
+}
+
+const struct cairo_font_backend cairo_win32_font_backend = {
+ _cairo_win32_font_create,
+ _cairo_win32_font_copy,
+ _cairo_win32_font_destroy,
+ _cairo_win32_font_font_extents,
+ _cairo_win32_font_text_extents,
+ _cairo_win32_font_glyph_extents,
+ _cairo_win32_font_text_bbox,
+ _cairo_win32_font_glyph_bbox,
+ _cairo_win32_font_show_text,
+ _cairo_win32_font_show_glyphs,
+ _cairo_win32_font_text_path,
+ _cairo_win32_font_glyph_path,
+ _cairo_win32_font_create_glyph
+};
diff --git a/src/cairo_gdip_surface.cpp b/src/cairo_gdip_surface.cpp
new file mode 100644
index 000000000..ec1982b55
--- /dev/null
+++ b/src/cairo_gdip_surface.cpp
@@ -0,0 +1,727 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 Stuart Parmenter
+ *
+ * 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 Stuart Parmenter.
+ *
+ * Contributor(s):
+ * Stuart Parmenter <pavlov@pavlov.net>
+ */
+
+extern "C" {
+#include "cairoint.h"
+}
+
+/* export symbols, for cairo.dll only */
+
+#pragma comment(linker, "/EXPORT:_cairo_create")
+#pragma comment(linker, "/EXPORT:_cairo_reference")
+#pragma comment(linker, "/EXPORT:_cairo_destroy")
+#pragma comment(linker, "/EXPORT:_cairo_save")
+#pragma comment(linker, "/EXPORT:_cairo_restore")
+#pragma comment(linker, "/EXPORT:_cairo_copy")
+#pragma comment(linker, "/EXPORT:_cairo_set_target_surface")
+#pragma comment(linker, "/EXPORT:_cairo_set_target_image")
+
+#ifdef CAIRO_HAS_PS_SURFACE
+#pragma comment(linker, "/EXPORT:_cairo_set_target_ps")
+#endif
+
+#ifdef CAIRO_HAS_PS_SURFACE
+#pragma comment(linker, "/EXPORT:_cairo_set_target_pdf")
+#endif
+
+#ifdef CAIRO_HAS_PNG_SURFACE
+#pragma comment(linker, "/EXPORT:_cairo_set_target_png")
+#endif
+
+#ifdef CAIRO_HAS_GL_SURFACE
+#pragma comment(linker, "/EXPORT:_cairo_set_target_gl")
+#endif
+
+#ifdef CAIRO_HAS_WIN32_SURFACE
+#pragma comment(linker, "/EXPORT:_cairo_set_target_win32")
+#endif
+
+#pragma comment(linker, "/EXPORT:_cairo_set_operator")
+#pragma comment(linker, "/EXPORT:_cairo_set_rgb_color")
+#pragma comment(linker, "/EXPORT:_cairo_set_pattern")
+#pragma comment(linker, "/EXPORT:_cairo_set_alpha")
+#pragma comment(linker, "/EXPORT:_cairo_set_tolerance")
+#pragma comment(linker, "/EXPORT:_cairo_set_fill_rule")
+#pragma comment(linker, "/EXPORT:_cairo_set_line_width")
+#pragma comment(linker, "/EXPORT:_cairo_set_line_cap")
+#pragma comment(linker, "/EXPORT:_cairo_set_line_join")
+#pragma comment(linker, "/EXPORT:_cairo_set_dash")
+#pragma comment(linker, "/EXPORT:_cairo_set_miter_limit")
+#pragma comment(linker, "/EXPORT:_cairo_set_line_cap")
+
+#pragma comment(linker, "/EXPORT:_cairo_translate")
+#pragma comment(linker, "/EXPORT:_cairo_scale")
+#pragma comment(linker, "/EXPORT:_cairo_rotate")
+
+#pragma comment(linker, "/EXPORT:_cairo_concat_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_set_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_default_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_identity_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_transform_point")
+#pragma comment(linker, "/EXPORT:_cairo_transform_distance")
+#pragma comment(linker, "/EXPORT:_cairo_inverse_transform_point")
+#pragma comment(linker, "/EXPORT:_cairo_inverse_transform_distance")
+
+#pragma comment(linker, "/EXPORT:_cairo_new_path")
+#pragma comment(linker, "/EXPORT:_cairo_move_to")
+#pragma comment(linker, "/EXPORT:_cairo_line_to")
+#pragma comment(linker, "/EXPORT:_cairo_curve_to")
+#pragma comment(linker, "/EXPORT:_cairo_arc")
+#pragma comment(linker, "/EXPORT:_cairo_arc_negative")
+#pragma comment(linker, "/EXPORT:_cairo_rel_move_to")
+#pragma comment(linker, "/EXPORT:_cairo_rel_line_to")
+#pragma comment(linker, "/EXPORT:_cairo_rel_curve_to")
+#pragma comment(linker, "/EXPORT:_cairo_rectangle")
+#pragma comment(linker, "/EXPORT:_cairo_close_path")
+
+#pragma comment(linker, "/EXPORT:_cairo_stroke")
+#pragma comment(linker, "/EXPORT:_cairo_fill")
+#pragma comment(linker, "/EXPORT:_cairo_copy_page")
+#pragma comment(linker, "/EXPORT:_cairo_show_page")
+#pragma comment(linker, "/EXPORT:_cairo_in_stroke")
+#pragma comment(linker, "/EXPORT:_cairo_in_fill")
+#pragma comment(linker, "/EXPORT:_cairo_stroke_extents")
+#pragma comment(linker, "/EXPORT:_cairo_fill_extents")
+
+#pragma comment(linker, "/EXPORT:_cairo_init_clip")
+#pragma comment(linker, "/EXPORT:_cairo_clip")
+#pragma comment(linker, "/EXPORT:_cairo_select_font")
+#pragma comment(linker, "/EXPORT:_cairo_scale_font")
+#pragma comment(linker, "/EXPORT:_cairo_transform_font")
+#pragma comment(linker, "/EXPORT:_cairo_show_text")
+#pragma comment(linker, "/EXPORT:_cairo_show_glyphs")
+#pragma comment(linker, "/EXPORT:_cairo_current_font")
+#pragma comment(linker, "/EXPORT:_cairo_current_font_extents")
+#pragma comment(linker, "/EXPORT:_cairo_set_font")
+#pragma comment(linker, "/EXPORT:_cairo_text_extents")
+#pragma comment(linker, "/EXPORT:_cairo_glyph_extents")
+#pragma comment(linker, "/EXPORT:_cairo_text_path")
+#pragma comment(linker, "/EXPORT:_cairo_glyph_path")
+#pragma comment(linker, "/EXPORT:_cairo_font_reference")
+#pragma comment(linker, "/EXPORT:_cairo_font_destroy")
+#pragma comment(linker, "/EXPORT:_cairo_font_set_transform")
+#pragma comment(linker, "/EXPORT:_cairo_font_current_transform")
+
+/*#pragma comment(linker, "/EXPORT:_cairo_ft_font_create")
+#pragma comment(linker, "/EXPORT:_cairo_ft_font_create_for_ft_face")
+*/
+#if 0
+/* hmm, this function doesn't exist, but __cairo_ft_font_destroy does */
+#pragma comment(linker, "/EXPORT:_cairo_ft_font_destroy")
+#endif
+/*
+#pragma comment(linker, "/EXPORT:_cairo_ft_font_face")
+#pragma comment(linker, "/EXPORT:_cairo_ft_font_pattern")
+*/
+#pragma comment(linker, "/EXPORT:_cairo_show_surface")
+#pragma comment(linker, "/EXPORT:_cairo_current_operator")
+#pragma comment(linker, "/EXPORT:_cairo_current_rgb_color")
+#pragma comment(linker, "/EXPORT:_cairo_current_pattern")
+#pragma comment(linker, "/EXPORT:_cairo_current_alpha")
+#pragma comment(linker, "/EXPORT:_cairo_current_tolerance")
+#pragma comment(linker, "/EXPORT:_cairo_current_point")
+#pragma comment(linker, "/EXPORT:_cairo_current_fill_rule")
+#pragma comment(linker, "/EXPORT:_cairo_current_line_width")
+#pragma comment(linker, "/EXPORT:_cairo_current_line_cap")
+#pragma comment(linker, "/EXPORT:_cairo_current_line_join")
+#pragma comment(linker, "/EXPORT:_cairo_current_rgb_color")
+#pragma comment(linker, "/EXPORT:_cairo_current_miter_limit")
+#pragma comment(linker, "/EXPORT:_cairo_current_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_current_target_surface")
+#pragma comment(linker, "/EXPORT:_cairo_current_path")
+#pragma comment(linker, "/EXPORT:_cairo_current_path_flat")
+
+#pragma comment(linker, "/EXPORT:_cairo_status")
+#pragma comment(linker, "/EXPORT:_cairo_status_string")
+
+#pragma comment(linker, "/EXPORT:_cairo_surface_create_for_image")
+#pragma comment(linker, "/EXPORT:_cairo_surface_create_similar")
+#pragma comment(linker, "/EXPORT:_cairo_surface_reference")
+#pragma comment(linker, "/EXPORT:_cairo_surface_destroy")
+#pragma comment(linker, "/EXPORT:_cairo_surface_set_repeat")
+#pragma comment(linker, "/EXPORT:_cairo_surface_set_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_surface_get_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_surface_set_filter")
+#pragma comment(linker, "/EXPORT:_cairo_surface_get_filter")
+
+#pragma comment(linker, "/EXPORT:_cairo_image_surface_create")
+#pragma comment(linker, "/EXPORT:_cairo_image_surface_create_for_data")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_create_for_surface")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_create_linear")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_create_radial")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_reference")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_destroy")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_add_color_stop")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_set_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_get_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_set_extend")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_get_extend")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_set_filter")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_get_filter")
+
+#ifdef CAIRO_HAS_PS_SURFACE
+#pragma comment(linker, "/EXPORT:_cairo_ps_surface_create")
+#endif
+
+#ifdef CAIRO_HAS_PNG_SURFACE
+#pragma comment(linker, "/EXPORT:_cairo_png_surface_create")
+#endif
+
+#ifdef CAIRO_HAS_GL_SURFACE
+#pragma comment(linker, "/EXPORT:_cairo_gl_surface_create")
+#endif
+
+#pragma comment(linker, "/EXPORT:_cairo_matrix_create")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_destroy")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_copy")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_set_identity")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_set_affine")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_get_affine")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_translate")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_scale")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_rotate")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_invert")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_multiply")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_transform_distance")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_transform_point")
+
+#include <windows.h>
+
+#include <gdiplus.h>
+using namespace Gdiplus;
+
+extern const cairo_surface_backend_t cairo_win32_surface_backend;
+
+cairo_surface_t *_cairo_win32_surface_create (HDC dc);
+
+void
+cairo_set_target_win32(cairo_t *cr, HDC dc)
+{
+ cairo_surface_t *surface;
+
+ surface = _cairo_win32_surface_create(dc);
+ 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_win32_surface {
+ cairo_surface_t base;
+ Graphics *gr;
+
+ Brush *brush;
+} cairo_win32_surface_t;
+
+
+static void
+_cairo_win32_surface_erase(cairo_win32_surface_t *surface);
+
+cairo_surface_t *
+_cairo_win32_surface_create(HDC dc)
+{
+ cairo_win32_surface_t *surface;
+
+ surface = (cairo_win32_surface_t*)malloc(sizeof(cairo_win32_surface_t));
+ if (surface == NULL)
+ return NULL;
+
+ surface->gr = new Graphics(dc);
+ surface->brush = NULL;
+// surface->gr->TranslateTransform(-2000*2.5, -3000*2.2);
+// surface->gr->ScaleTransform(20, 20);
+
+ surface->gr->SetSmoothingMode(SmoothingModeAntiAlias);
+
+ /* do pixmap creation, etc */
+
+ _cairo_surface_init(&surface->base, &cairo_win32_surface_backend);
+
+ _cairo_win32_surface_erase(surface);
+
+ return &surface->base;
+}
+
+static cairo_surface_t *
+_cairo_win32_surface_create_similar(void *abstract_src,
+ cairo_format_t format,
+ int drawable,
+ int width,
+ int height)
+{
+ return NULL;
+}
+
+static void
+_cairo_win32_surface_destroy (void *abstract_surface)
+{
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
+
+ delete surface->gr;
+ delete surface->brush;
+
+ free(surface);
+}
+
+static void
+_cairo_win32_surface_erase(cairo_win32_surface_t *surface)
+{
+ surface->gr->Clear(Color(255, 0, 0, 0));
+}
+
+/* XXX: We should re-work this interface to return both X/Y ppi values. */
+static double
+_cairo_win32_surface_pixels_per_inch(void *abstract_surface)
+{
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
+
+ return surface->gr->GetDpiY();
+}
+
+static Image *
+make_image(cairo_image_surface_t *image)
+{
+ Rect r(0, 0, image->width, image->height);
+ Bitmap *b = new Bitmap(image->width, image->height, PixelFormat32bppPARGB);
+ BitmapData data;
+
+ b->LockBits(&r, ImageLockModeWrite, PixelFormat32bppPARGB, &data);
+
+ memcpy(data.Scan0, image->data, image->stride * image->height);
+
+ b->UnlockBits(&data);
+
+ return b;
+}
+
+static cairo_image_surface_t *
+_cairo_win32_surface_get_image(void *abstract_surface)
+{
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
+
+ /* need to figure out how to get the data from a Graphics and turn it in to an Image */
+ return NULL;
+}
+
+
+static cairo_status_t
+_cairo_win32_surface_set_image(void *abstract_surface,
+ cairo_image_surface_t *image)
+{
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
+
+ Image *img = make_image(image);
+ surface->gr->DrawImage(img, 0, 0);
+ delete img;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_surface_set_matrix(void *abstract_surface,
+ cairo_matrix_t *matrix)
+{
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
+
+ Matrix m((float)matrix->m[0][0], (float)matrix->m[1][0], (float)matrix->m[2][0],
+ (float)matrix->m[0][1], (float)matrix->m[1][1], (float)matrix->m[2][1]);
+
+
+ surface->gr->SetTransform(&m);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_surface_set_filter (void *abstract_surface,
+ cairo_filter_t filter)
+{
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
+ SmoothingMode mode;
+
+ switch (filter) {
+ case CAIRO_FILTER_FAST:
+ mode = SmoothingModeNone;
+ break;
+ case CAIRO_FILTER_GOOD:
+ case CAIRO_FILTER_BEST:
+ case CAIRO_FILTER_NEAREST:
+ case CAIRO_FILTER_BILINEAR:
+ case CAIRO_FILTER_GAUSSIAN:
+ default:
+ mode = SmoothingModeAntiAlias;
+ break;
+ }
+ surface->gr->SetSmoothingMode(mode);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_surface_set_repeat (void *abstract_surface,
+ int repeat)
+{
+ /* what is this function supposed to do? */
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
+
+ return (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_composite(cairo_operator_t op,
+ 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_win32_surface_fill_rectangles(void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_rectangle_t *rects,
+ int num_rects)
+{
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
+
+ SolidBrush brush(Color(color->alpha_short, color->red_short, color->green_short, color->blue_short));
+
+ RectF *r = new RectF[num_rects]; /* should really allocate a small number here on the stack and use those if possible */
+ for (int i = 0; i < num_rects; ++i) {
+ r[i].X = rects[i].x;
+ r[i].Y = rects[i].y;
+ r[i].Width = rects[i].width;
+ r[i].Height = rects[i].height;
+ }
+
+ surface->gr->FillRectangles(&brush, r, num_rects);
+
+ delete[] r;
+
+ return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
+}
+
+
+
+static int
+_cairo_win32_extract_rectangle (cairo_trapezoid_t *trap,
+ RectF *rect)
+{
+ if (trap->left.p1.x == trap->left.p2.x &&
+ trap->right.p1.x == trap->right.p2.x &&
+ trap->left.p1.y == trap->right.p1.y &&
+ trap->left.p2.y == trap->right.p2.y) {
+
+ double x = _cairo_fixed_to_double (trap->left.p1.x);
+ double y = _cairo_fixed_to_double (trap->left.p1.y);
+ rect->X = (float)x;
+ rect->Y = (float)y;
+ rect->Width = (float)(_cairo_fixed_to_double(trap->right.p1.x) - x);
+ rect->Height = (float)(_cairo_fixed_to_double(trap->left.p2.y) - y);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_composite_trapezoids (cairo_operator_t op,
+ cairo_surface_t *generic_src,
+ void *abstract_dst,
+ int x_src,
+ int y_src,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+{
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_dst;
+
+ static int zzz = 0;
+ zzz += num_traps;
+
+ Image *img = NULL;
+ Brush *brush = NULL; /* i'd really like to not allocate this on the heap.. */
+
+#define FIXED_TO_FLOAT(x) (float)_cairo_fixed_to_double((x))
+
+ /* ugh.. figure out if we're a "native" pattern or an image_surface pattern.. */
+ if (generic_src->backend == &cairo_win32_surface_backend) {
+ brush = ((cairo_win32_surface_t*)generic_src)->brush;
+ /* XXX move this outside so that TextureBrushes can take advantage of it */
+ /* Check to see if we can represent these traps as a rectangle. */
+ RectF rect;
+ if (num_traps == 1 && _cairo_win32_extract_rectangle(traps, &rect)) {
+ surface->gr->FillRectangle(brush, rect);
+ return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
+ }
+ } else {
+ /* I would really love to move this code in to create_pattern if possible */
+ img = make_image((cairo_image_surface_t*)generic_src);
+ brush = new TextureBrush(img);
+
+ // XXX this will probably break. Don't know why we have +1 and +2 offsets..
+ float xoff = (FIXED_TO_FLOAT(traps[0].left.p1.x) + 0.5f);
+ float yoff = (FIXED_TO_FLOAT(traps[0].left.p1.y) + 1.5f);
+ static_cast<TextureBrush*>(brush)->TranslateTransform((int)(-x_src + xoff),
+ (int)(-y_src + yoff));
+ }
+
+ CompositingMode mode;
+ switch (op) {
+ case CAIRO_OPERATOR_OVER:
+ mode = CompositingModeSourceOver;
+ break;
+ case CAIRO_OPERATOR_CLEAR:
+ mode = CompositingModeSourceCopy;
+ break;
+ case CAIRO_OPERATOR_SRC:
+ case CAIRO_OPERATOR_DST:
+ case CAIRO_OPERATOR_OVER_REVERSE:
+ case CAIRO_OPERATOR_IN:
+ case CAIRO_OPERATOR_IN_REVERSE:
+ case CAIRO_OPERATOR_OUT:
+ case CAIRO_OPERATOR_OUT_REVERSE:
+ case CAIRO_OPERATOR_ATOP:
+ case CAIRO_OPERATOR_ATOP_REVERSE:
+ case CAIRO_OPERATOR_XOR:
+ case CAIRO_OPERATOR_ADD:
+ case CAIRO_OPERATOR_SATURATE:
+ mode = CompositingModeSourceOver;
+ break;
+ }
+ surface->gr->SetCompositingMode(mode);
+
+ PointF points[4];
+ for (int i = 0; i < num_traps; ++i) {
+ float top = FIXED_TO_FLOAT(traps[i].top);
+ float bottom = FIXED_TO_FLOAT(traps[i].bottom);
+
+ /* left line */
+ points[0].X = FIXED_TO_FLOAT(traps[i].left.p1.x);
+ points[0].Y = FIXED_TO_FLOAT(traps[i].left.p1.y);
+ points[1].X = FIXED_TO_FLOAT(traps[i].left.p2.x);
+ points[1].Y = FIXED_TO_FLOAT(traps[i].left.p2.y);
+
+ /* right line */
+ points[2].X = FIXED_TO_FLOAT(traps[i].right.p2.x);
+ points[2].Y = FIXED_TO_FLOAT(traps[i].right.p2.y);
+ points[3].X = FIXED_TO_FLOAT(traps[i].right.p1.x);
+ points[3].Y = FIXED_TO_FLOAT(traps[i].right.p1.y);
+
+ surface->gr->FillPolygon(brush, points, 4);
+ //Pen p(Color(255,0,0,0), 1.0f/10.0f);
+ //surface->gr->DrawPolygon(&p, points, 4);
+ }
+
+#undef FIXED_TO_FLOAT
+
+ delete img;
+ return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
+}
+
+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 = (cairo_win32_surface_t *)abstract_surface;
+
+ pixman_box16_t *box;
+ int n = pixman_region_num_rects(region);
+
+ if (n == 0)
+ return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
+
+ box = pixman_region_rects(region);
+
+ surface->gr->ResetClip();
+ for (int i = 0; i < n; ++i) {
+ Rect r(box[i].x1, box[i].y1, box[i].x2 - box[i].x1, box[i].y2 - box[i].y1);
+ surface->gr->SetClip(r, CombineModeUnion); /* do I need to do replace once and then union? */
+ }
+
+ return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_create_pattern (void *abstract_surface,
+ cairo_pattern_t *pattern,
+ cairo_box_t *box)
+{
+ /* SOLID is easy -> SolidBrush
+ LINEAR we can only do a gradient from 1 color to another -> LinearGradientBrush
+ We should do this if thats all we need, otherwise use software.
+ RADIAL we can't really do it. Let it fall back to software I guess. */
+
+
+ /* in the case of PATTERN_SOLID, we really just want to create a brush and hand that back... */
+ if (pattern->type == CAIRO_PATTERN_SOLID) {
+
+ /* ugh, this surface creation code should _really_ live somewhere else */
+ cairo_win32_surface_t *src = (cairo_win32_surface_t*)malloc(sizeof(cairo_win32_surface_t));
+ if (src == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ _cairo_surface_init(&src->base, &cairo_win32_surface_backend);
+ pattern->source = &src->base;
+
+ src->gr = NULL;
+ src->brush = new SolidBrush(Color(pattern->color.alpha_short,
+ pattern->color.red_short,
+ pattern->color.green_short,
+ pattern->color.blue_short));
+
+
+ return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
+ }
+
+ else if (pattern->type == CAIRO_PATTERN_LINEAR && pattern->n_stops == 2) {
+
+ /* ugh, this surface creation code should _really_ live somewhere else */
+ cairo_win32_surface_t *src = (cairo_win32_surface_t*)malloc(sizeof(cairo_win32_surface_t));
+ if (src == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ _cairo_surface_init(&src->base, &cairo_win32_surface_backend);
+ pattern->source = &src->base;
+
+ src->gr = NULL;
+
+ RectF r((float)pattern->u.linear.point0.x,
+ (float)pattern->u.linear.point0.y,
+ ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16),
+ ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16));
+
+ src->brush = new LinearGradientBrush(r,
+ Color(pattern->stops[0].color_char[3],
+ pattern->stops[0].color_char[0],
+ pattern->stops[0].color_char[1],
+ pattern->stops[0].color_char[2]),
+ Color(pattern->stops[1].color_char[3],
+ pattern->stops[1].color_char[0],
+ pattern->stops[1].color_char[1],
+ pattern->stops[1].color_char[2]),
+ 90.0, FALSE);
+
+ static_cast<LinearGradientBrush*>(src->brush)->TranslateTransform((float)pattern->source_offset.x,
+ (float)pattern->source_offset.y);
+ return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
+ }
+
+ else if (pattern->type == CAIRO_PATTERN_RADIAL) {
+#if 0 /* XXX not sure this will work.. do we have to draw with FillPath() in order for this brush to work properly? */
+ /* use PathGradientBrush here */
+
+ /* ugh, this surface creation code should _really_ live somewhere else */
+ cairo_win32_surface_t *src = (cairo_win32_surface_t*)malloc(sizeof(cairo_win32_surface_t));
+ if (src == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ _cairo_surface_init(&src->base, &cairo_win32_surface_backend);
+ pattern->source = &src->base;
+
+ src->gr = NULL;
+
+ PointF center(pattern->u.radial.center1.x, pattern->u.radial.center1.y);
+
+ GraphicsPath path;
+ path.AddEllipse(0, 0, 140, 70);
+
+ // Use the path to construct a brush.
+ PathGradientBrush *brush = new PathGradientBrush(&path);
+ src->brush = brush;
+
+ // Set the color at the center of the path to blue.
+ brush->SetCenterColor(Color(50, 100, 0, 255));
+
+ // Set the color along the entire boundary of the path to aqua.
+ Color colors[] = {Color(255, 0, 255, 255)};
+ int count = 1;
+ brush->SetSurroundColors(colors, &count);
+
+ brush->SetCenterPoint(center);
+
+ return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
+#endif
+
+ }
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+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_get_image,
+ _cairo_win32_surface_set_image,
+ _cairo_win32_surface_set_matrix,
+ _cairo_win32_surface_set_filter,
+ _cairo_win32_surface_set_repeat,
+ _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_create_pattern,
+};
diff --git a/src/cairo_glitz_surface.c b/src/cairo_glitz_surface.c
index 21e889204..69fc82f2e 100644
--- a/src/cairo_glitz_surface.c
+++ b/src/cairo_glitz_surface.c
@@ -25,6 +25,7 @@
*/
#include "cairoint.h"
+#include "cairo-glitz.h"
#define GLITZ_FIXED_TO_FLOAT(f) \
(((glitz_float_t) (f)) / 65536)
@@ -52,8 +53,6 @@ cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface)
if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
return;
- glitz_surface_reference (surface);
-
crsurface = cairo_glitz_surface_create (surface);
if (crsurface == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
@@ -65,10 +64,9 @@ cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface)
cairo_surface_destroy (crsurface);
}
-typedef struct cairo_glitz_surface {
+typedef struct _cairo_glitz_surface {
cairo_surface_t base;
- unsigned long features;
glitz_surface_t *surface;
glitz_format_t *format;
@@ -119,21 +117,29 @@ _cairo_glitz_surface_get_image (void *abstract_surface)
width = glitz_surface_get_width (surface->surface);
height = glitz_surface_get_height (surface->surface);
- if (surface->format->red_size > 0) {
+ 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;
-
- if (surface->format->alpha_size > 0)
- format.alpha_mask = 0xff000000;
- else
- format.alpha_mask = 0x0;
-
+ format.alpha_mask = 0xff000000;
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;
}
pf.masks.bpp = format.bpp;
@@ -306,8 +312,6 @@ _glitz_operator (cairo_operator_t op)
return GLITZ_OPERATOR_XOR;
case CAIRO_OPERATOR_ADD:
return GLITZ_OPERATOR_ADD;
- case CAIRO_OPERATOR_SATURATE:
- return GLITZ_OPERATOR_SATURATE;
case CAIRO_OPERATOR_OVER:
default:
return GLITZ_OPERATOR_OVER;
@@ -319,14 +323,17 @@ _glitz_surface_create_solid (glitz_surface_t *other,
glitz_format_name_t format_name,
glitz_color_t *color)
{
- glitz_surface_t *surface;
+ glitz_drawable_t *drawable;
glitz_format_t *format;
+ glitz_surface_t *surface;
+
+ drawable = glitz_surface_get_drawable (other);
- format = glitz_surface_find_similar_standard_format (other, format_name);
+ format = glitz_find_standard_format (drawable, format_name);
if (format == NULL)
return NULL;
- surface = glitz_surface_create_similar (other, format, 1, 1);
+ surface = glitz_surface_create (drawable, format, 1, 1);
if (surface == NULL)
return NULL;
@@ -337,70 +344,126 @@ _glitz_surface_create_solid (glitz_surface_t *other,
return surface;
}
+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;
+ glitz_pbuffer_attributes_t attributes;
+ 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;
+
+ attributes.width = glitz_surface_get_width (surface);
+ attributes.height = glitz_surface_get_height (surface);
+ mask = GLITZ_PBUFFER_WIDTH_MASK | GLITZ_PBUFFER_HEIGHT_MASK;
+
+ pbuffer = glitz_create_pbuffer_drawable (drawable, dformat,
+ &attributes, mask);
+ if (!pbuffer)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (glitz_drawable_get_width (pbuffer) < attributes.width ||
+ glitz_drawable_get_height (pbuffer) < attributes.height) {
+ glitz_drawable_destroy (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;
+}
+
+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 drawable,
+ int draw,
int width,
int height)
{
cairo_glitz_surface_t *src = abstract_src;
- glitz_surface_t *surface;
cairo_surface_t *crsurface;
- glitz_format_t *glitz_format;
- glitz_format_t templ;
- unsigned long mask;
+ glitz_drawable_t *drawable;
+ glitz_surface_t *surface;
+ glitz_format_t *gformat;
+
+ drawable = glitz_surface_get_drawable (src->surface);
- templ.read.offscreen = 1;
- mask = GLITZ_FORMAT_READ_OFFSCREEN_MASK;
+ gformat = glitz_find_standard_format (drawable, _glitz_format (format));
+ if (gformat == NULL)
+ return NULL;
- if (drawable) {
- templ.draw.offscreen = 1;
- if (src->features & GLITZ_FEATURE_OFFSCREEN_MULTISAMPLE_MASK) {
- templ.multisample.samples = src->format->multisample.samples;
- mask |= GLITZ_FORMAT_MULTISAMPLE_SAMPLES_MASK;
- }
- } else
- templ.draw.offscreen = 0;
-
- mask |= GLITZ_FORMAT_DRAW_OFFSCREEN_MASK;
-
- switch (format) {
- case CAIRO_FORMAT_A1:
- case CAIRO_FORMAT_A8:
- templ.alpha_size = 8;
- mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
- break;
- case CAIRO_FORMAT_RGB24:
- templ.red_size = 8;
- mask |= GLITZ_FORMAT_RED_SIZE_MASK;
- break;
- case CAIRO_FORMAT_ARGB32:
- default:
- templ.alpha_size = templ.red_size = 8;
- mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
- mask |= GLITZ_FORMAT_RED_SIZE_MASK;
- break;
- }
-
- glitz_format =
- glitz_surface_find_similar_format (src->surface, mask, &templ, 0);
- if (glitz_format == NULL) {
- mask &= ~GLITZ_FORMAT_DRAW_OFFSCREEN_MASK;
- glitz_format =
- glitz_surface_find_similar_format (src->surface, mask, &templ, 0);
- if (glitz_format == NULL)
- return NULL;
- }
-
- surface = glitz_surface_create_similar (src->surface, glitz_format,
- width, height);
+ surface = glitz_surface_create (drawable, gformat, width, height);
if (surface == NULL)
return NULL;
crsurface = cairo_glitz_surface_create (surface);
- if (crsurface == NULL)
- glitz_surface_destroy (surface);
+
+ glitz_surface_destroy (surface);
return crsurface;
}
@@ -449,6 +512,9 @@ _glitz_composite (glitz_operator_t op,
glitz_buffer_t *geometry,
glitz_geometry_format_t *format)
{
+ if (_glitz_ensure_target (dst))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (glitz_surface_get_status (dst))
return CAIRO_STATUS_NO_TARGET_SURFACE;
@@ -494,6 +560,9 @@ _cairo_glitz_surface_composite (cairo_operator_t op,
cairo_glitz_surface_t *mask_clone = NULL;
cairo_int_status_t status;
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (generic_src->backend != dst->base.backend) {
src_clone = _cairo_glitz_surface_clone_similar (dst, generic_src,
CAIRO_FORMAT_ARGB32);
@@ -540,6 +609,9 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
{
cairo_glitz_surface_t *dst = abstract_dst;
glitz_color_t glitz_color;
+
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
glitz_color.red = color->red_short;
glitz_color.green = color->green_short;
@@ -613,9 +685,16 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
free (data);
return status;
- } else
+ } else {
+ if (glitz_surface_get_width (dst->surface) != 1 ||
+ glitz_surface_get_height (dst->surface) != 1) {
+ if (_glitz_ensure_target (dst->surface))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
glitz_set_rectangles (dst->surface, &glitz_color,
(glitz_rectangle_t *) rects, n_rects);
+ }
return CAIRO_STATUS_SUCCESS;
}
@@ -639,6 +718,9 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
int x_dst, y_dst, x_rel, y_rel, width, height;
void *data;
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (generic_src->backend != dst->base.backend)
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -764,10 +846,13 @@ _cairo_glitz_surface_create_pattern (void *abstract_dst,
break;
/* fall-through */
case CAIRO_PATTERN_LINEAR: {
+ glitz_drawable_t *drawable;
glitz_fixed16_16_t *params;
int i, n_params;
- if (!(dst->features & GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK))
+ 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)
@@ -885,7 +970,7 @@ _cairo_glitz_surface_set_clip_region (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static const struct cairo_surface_backend cairo_glitz_surface_backend = {
+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,
@@ -918,8 +1003,8 @@ cairo_glitz_surface_create (glitz_surface_t *surface)
_cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend);
+ glitz_surface_reference (surface);
crsurface->surface = surface;
- crsurface->features = glitz_surface_get_features (surface);
crsurface->format = glitz_surface_get_format (surface);
_cairo_pattern_init (&crsurface->pattern);
diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c
index 9f9de69e1..e855a7a66 100644
--- a/src/cairo_gstate.c
+++ b/src/cairo_gstate.c
@@ -86,7 +86,7 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
gstate->clip.region = NULL;
gstate->clip.surface = NULL;
- gstate->pattern = _cairo_pattern_create_solid (1.0, 1.0, 1.0);
+ gstate->pattern = _cairo_pattern_create_solid (0.0, 0.0, 0.0);
gstate->alpha = 1.0;
gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT;
@@ -1096,8 +1096,10 @@ _cairo_gstate_current_point (cairo_gstate_t *gstate, double *x_ret, double *y_re
cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y);
}
- *x_ret = x;
- *y_ret = y;
+ if (x_ret)
+ *x_ret = x;
+ if (y_ret)
+ *y_ret = y;
return CAIRO_STATUS_SUCCESS;
}
@@ -1363,6 +1365,54 @@ BAIL:
return status;
}
+static cairo_status_t
+_calculate_region_for_intermediate_clip_surface (pixman_region16_t *out,
+ cairo_box_t *extents,
+ cairo_clip_rec_t *clip_rect)
+{
+ cairo_status_t status;
+ pixman_region16_t *extents_region, *clip_region;
+ pixman_box16_t clip_box, pixman_extents;
+
+ pixman_extents.x1 = _cairo_fixed_integer_floor (extents->p1.x);
+ pixman_extents.y1 = _cairo_fixed_integer_floor (extents->p1.y);
+ pixman_extents.x2 = _cairo_fixed_integer_ceil (extents->p2.x);
+ pixman_extents.y2 = _cairo_fixed_integer_ceil (extents->p2.y);
+ extents_region = pixman_region_create_simple (&pixman_extents);
+ if (extents_region == NULL)
+ {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL0;
+ }
+
+ clip_box.x1 = clip_rect->x;
+ clip_box.y1 = clip_rect->y;
+ clip_box.x2 = clip_rect->x + clip_rect->width;
+ clip_box.y2 = clip_rect->y + clip_rect->height;
+ clip_region = pixman_region_create_simple (&clip_box);
+ if (clip_region == NULL)
+ {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL1;
+ }
+
+ if (pixman_region_intersect (out,
+ extents_region,
+ clip_region)
+ == PIXMAN_REGION_STATUS_FAILURE)
+ status = CAIRO_STATUS_NO_MEMORY;
+ else
+ status = CAIRO_STATUS_SUCCESS;
+
+ pixman_region_destroy (extents_region);
+ BAIL1:
+ pixman_region_destroy (clip_region);
+
+ BAIL0:
+ return status;
+}
+
+
/* Warning: This call modifies the coordinates of traps */
static cairo_status_t
_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
@@ -1385,25 +1435,38 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
int i;
cairo_surface_t *intermediate;
cairo_color_t empty_color;
+ pixman_box16_t *draw_extents;
+ pixman_region16_t *draw_region;
- _cairo_color_init (&empty_color);
- _cairo_color_set_alpha (&empty_color, 0.);
- intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
- CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
- &empty_color);
- if (intermediate == NULL) {
+ draw_region = pixman_region_create ();
+ if (draw_region == NULL)
+ {
status = CAIRO_STATUS_NO_MEMORY;
goto BAIL0;
}
+
+ _cairo_traps_extents (traps, &extents);
+
+ status = _calculate_region_for_intermediate_clip_surface (draw_region,
+ &extents,
+ &gstate->clip);
+ if (status)
+ goto BAIL1;
+
+ /* Shortcut if empty */
+ if (!pixman_region_not_empty (draw_region)) {
+ status = CAIRO_STATUS_SUCCESS;
+ goto BAIL1;
+ }
+
+ draw_extents = pixman_region_extents (draw_region);
/* 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 clip
- surface. */
- xoff = _cairo_fixed_from_double (gstate->clip.x);
- yoff = _cairo_fixed_from_double (gstate->clip.y);
+ the coordinates to align with the offset origin of the
+ intermediate surface. */
+ xoff = _cairo_fixed_from_int (draw_extents->x1);
+ yoff = _cairo_fixed_from_int (draw_extents->y1);
for (i=0, t=traps->traps; i < traps->num_traps; i++, t++) {
t->top -= yoff;
t->bottom -= yoff;
@@ -1428,11 +1491,22 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
_cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0);
_cairo_pattern_set_alpha (&pattern, 1.0);
- _cairo_traps_extents (traps, &extents);
status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
if (status)
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,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1,
+ &empty_color);
+ if (intermediate == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL2;
+ }
+
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
pattern.source, intermediate,
x_src,
@@ -1440,30 +1514,32 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
traps->traps,
traps->num_traps);
if (status)
- goto BAIL2;
+ goto BAIL3;
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
gstate->clip.surface,
NULL,
intermediate,
- 0, 0, 0, 0, 0, 0,
- gstate->clip.width, gstate->clip.height);
+ draw_extents->x1 - gstate->clip.x,
+ draw_extents->y1 - gstate->clip.y,
+ 0, 0,
+ 0, 0,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
if (status)
- goto BAIL2;
+ goto BAIL3;
_cairo_pattern_fini (&pattern);
_cairo_pattern_init_copy (&pattern, src);
- extents.p1.x = _cairo_fixed_from_int (gstate->clip.x);
- extents.p1.y = _cairo_fixed_from_int (gstate->clip.y);
- extents.p2.x =
- _cairo_fixed_from_int (gstate->clip.x + gstate->clip.width);
- extents.p2.y =
- _cairo_fixed_from_int (gstate->clip.y + gstate->clip.height);
+ extents.p1.x = _cairo_fixed_from_int (draw_extents->x1);
+ extents.p1.y = _cairo_fixed_from_int (draw_extents->y1);
+ extents.p2.x = _cairo_fixed_from_int (draw_extents->x2);
+ extents.p2.y = _cairo_fixed_from_int (draw_extents->y2);
status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
if (status)
- goto BAIL2;
+ goto BAIL3;
if (dst == gstate->clip.surface)
xoff = yoff = 0;
@@ -1474,13 +1550,16 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
0, 0,
xoff >> 16,
yoff >> 16,
- gstate->clip.width,
- gstate->clip.height);
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
+
- BAIL2:
+ BAIL3:
cairo_surface_destroy (intermediate);
- BAIL1:
+ BAIL2:
_cairo_pattern_fini (&pattern);
+ BAIL1:
+ pixman_region_destroy (draw_region);
BAIL0:
if (status)
@@ -1705,6 +1784,25 @@ extract_transformed_rectangle(cairo_matrix_t *mat,
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)
{
@@ -1762,6 +1860,10 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
_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. */
@@ -1799,7 +1901,7 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
_cairo_traps_fini (&traps);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
@@ -1809,7 +1911,7 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
int height)
{
- /* We are dealing with 5 coordinate spaces in this function. this makes
+ /* 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.
@@ -1833,12 +1935,16 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
* 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 6th space in here, which is the space of the
+ * (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
@@ -1897,15 +2003,16 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
_cairo_pattern_init (&pattern);
+ 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);
+
if ((gstate->pattern->type != CAIRO_PATTERN_SOLID) ||
(gstate->alpha != 1.0)) {
/* I'm allowing any type of pattern for the mask right now.
Maybe this is bad. Will allow for some cool effects though. */
_cairo_pattern_init_copy (&pattern, gstate->pattern);
- 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);
status = _cairo_gstate_create_pattern (gstate, &pattern, &pattern_extents);
if (status)
return status;
@@ -1915,13 +2022,36 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
{
cairo_surface_t *intermediate;
cairo_color_t empty_color;
+ pixman_box16_t *draw_extents;
+ pixman_region16_t *draw_region;
+ draw_region = pixman_region_create ();
+ if (draw_region == NULL)
+ {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL0;
+ }
+
+ status = _calculate_region_for_intermediate_clip_surface (draw_region,
+ &pattern_extents,
+ &gstate->clip);
+ if (status)
+ goto BAIL1;
+
+ /* Shortcut if empty */
+ if (!pixman_region_not_empty (draw_region)) {
+ status = CAIRO_STATUS_SUCCESS;
+ goto BAIL1;
+ }
+
+ draw_extents = pixman_region_extents (draw_region);
+
_cairo_color_init (&empty_color);
_cairo_color_set_alpha (&empty_color, .0);
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1,
&empty_color);
/* it is not completely clear what the "right" way to combine the
@@ -1935,27 +2065,33 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
gstate->clip.surface,
pattern.source,
intermediate,
- 0, 0,
+ draw_extents->x1 - gstate->clip.x,
+ draw_extents->y1 - gstate->clip.y,
0, 0,
0, 0,
- gstate->clip.width,
- gstate->clip.height);
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
+
if (status)
- goto BAIL;
+ goto BAIL2;
status = _cairo_surface_composite (gstate->operator,
surface,
intermediate,
gstate->surface,
- gstate->clip.x, gstate->clip.y,
+ draw_extents->x1, draw_extents->y1,
0, 0,
- gstate->clip.x, gstate->clip.y,
- gstate->clip.width,
- gstate->clip.height);
+ draw_extents->x1, draw_extents->y1,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
- BAIL:
+ BAIL2:
cairo_surface_destroy (intermediate);
+ BAIL1:
+ pixman_region_destroy (draw_region);
+ BAIL0:
+ ;
}
else
{
@@ -1992,21 +2128,14 @@ _cairo_gstate_select_font (cairo_gstate_t *gstate,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
- cairo_unscaled_font_t *tmp;
-
- tmp = _cairo_unscaled_font_create (family, slant, weight);
+ if (gstate->font)
+ _cairo_unscaled_font_destroy (gstate->font);
- if (tmp == NULL)
+ gstate->font = _cairo_unscaled_font_create (family, slant, weight);
+ if (gstate->font == NULL)
return CAIRO_STATUS_NO_MEMORY;
- if (gstate->font != tmp)
- {
- if (gstate->font != NULL)
- _cairo_unscaled_font_destroy (gstate->font);
-
- cairo_matrix_set_identity (&gstate->font_matrix);
- gstate->font = tmp;
- }
+ cairo_matrix_set_identity (&gstate->font_matrix);
return CAIRO_STATUS_SUCCESS;
}
@@ -2171,30 +2300,27 @@ _cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
{
cairo_int_status_t status;
cairo_font_scale_t sc;
- double dummy = 0.0;
+ double font_scale_x, font_scale_y;
_build_font_scale (gstate, &sc);
status = _cairo_unscaled_font_font_extents (gstate->font, &sc, extents);
- /* The font responded in device space; convert to user space. */
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &dummy,
- &extents->ascent);
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &dummy,
- &extents->descent);
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &dummy,
- &extents->height);
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &extents->max_x_advance,
- &extents->max_y_advance);
-
+ _cairo_matrix_compute_scale_factors (&gstate->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;
}
@@ -2208,18 +2334,20 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
cairo_font_scale_t sc;
cairo_point_t point;
- double dev_x, dev_y;
+ double origin_x, origin_y;
int i;
_build_font_scale (gstate, &sc);
status = _cairo_path_current_point (&gstate->path, &point);
if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
- dev_x = 0.0;
- dev_y = 0.0;
+ origin_x = 0.0;
+ origin_y = 0.0;
} else {
- dev_x = _cairo_fixed_to_double (point.x);
- dev_y = _cairo_fixed_to_double (point.y);
+ 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_unscaled_font_text_to_glyphs (gstate->font,
@@ -2228,15 +2356,16 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs))
return status;
- /* The font responded in device space, starting from (0,0); add any
- current point offset in device space, and convert to user space. */
+ /* 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) {
- (*glyphs)[i].x += dev_x;
- (*glyphs)[i].y += dev_y;
- cairo_matrix_transform_point (&gstate->ctm_inverse,
- &((*glyphs)[i].x),
- &((*glyphs)[i].y));
+ 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;
@@ -2265,44 +2394,88 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
int num_glyphs,
cairo_text_extents_t *extents)
{
- cairo_status_t status;
- cairo_glyph_t *transformed_glyphs;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_glyph_t origin_glyph;
+ cairo_text_extents_t origin_extents;
cairo_font_scale_t sc;
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;
- _build_font_scale (gstate, &sc);
-
- 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)
+ if (!num_glyphs)
{
- transformed_glyphs[i] = glyphs[i];
- cairo_matrix_transform_point (&gstate->ctm,
- &transformed_glyphs[i].x,
- &transformed_glyphs[i].y);
+ 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;
}
- status = _cairo_unscaled_font_glyph_extents (gstate->font, &sc,
- transformed_glyphs, num_glyphs,
- extents);
-
- /* The font responded in device space; convert to user space. */
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &extents->x_bearing,
- &extents->y_bearing);
+ _build_font_scale (gstate, &sc);
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &extents->width,
- &extents->height);
+ 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_unscaled_font_glyph_extents (gstate->font, &sc,
+ &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 (&gstate->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 (&gstate->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;
+ }
+ }
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &extents->x_advance,
- &extents->y_advance);
+ x = origin_extents.x_advance;
+ y = origin_extents.y_advance;
+ cairo_matrix_transform_point (&gstate->font_matrix,
+ &x, &y);
+ x_pos = glyphs[i].x + x;
+ y_pos = glyphs[i].y + y;
+ }
- free (transformed_glyphs);
+ 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;
return status;
}
@@ -2338,55 +2511,84 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
transformed_glyphs, num_glyphs,
&bbox);
if (status)
- return status;
+ goto CLEANUP_GLYPHS;
status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox);
if (status)
- return status;
+ goto CLEANUP_GLYPHS;
if (gstate->clip.surface)
{
cairo_surface_t *intermediate;
cairo_color_t empty_color;
+ pixman_box16_t *draw_extents;
+ pixman_region16_t *draw_region;
+
+ draw_region = pixman_region_create ();
+ if (draw_region == NULL)
+ {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL0;
+ }
+
+ status = _calculate_region_for_intermediate_clip_surface (draw_region,
+ &bbox,
+ &gstate->clip);
+ if (status) {
+ goto BAIL1;
+ }
+ /* Shortcut if empty */
+ if (!pixman_region_not_empty (draw_region)) {
+ status = CAIRO_STATUS_SUCCESS;
+ goto BAIL1;
+ }
+
+ draw_extents = pixman_region_extents (draw_region);
+
_cairo_color_init (&empty_color);
_cairo_color_set_alpha (&empty_color, .0);
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1,
&empty_color);
+ if (intermediate == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL1;
+ }
- /* move the glyphs again, from dev space to clip space */
+ /* move the glyphs again, from dev space to intermediate space */
for (i = 0; i < num_glyphs; ++i)
{
- transformed_glyphs[i].x -= gstate->clip.x;
- transformed_glyphs[i].y -= gstate->clip.y;
+ transformed_glyphs[i].x -= draw_extents->x1;
+ transformed_glyphs[i].y -= draw_extents->y1;
}
status = _cairo_unscaled_font_show_glyphs (gstate->font,
&sc,
CAIRO_OPERATOR_ADD,
pattern.source, intermediate,
- gstate->clip.x - pattern.source_offset.x,
- gstate->clip.y - pattern.source_offset.y,
+ draw_extents->x1 - pattern.source_offset.x,
+ draw_extents->y1 - pattern.source_offset.y,
transformed_glyphs, num_glyphs);
if (status)
- goto BAIL;
+ goto BAIL2;
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
gstate->clip.surface,
NULL,
intermediate,
- 0, 0,
+ draw_extents->x1 - gstate->clip.x,
+ draw_extents->y1 - gstate->clip.y,
0, 0,
0, 0,
- gstate->clip.width,
- gstate->clip.height);
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
if (status)
- goto BAIL;
+ goto BAIL2;
status = _cairo_surface_composite (gstate->operator,
pattern.source,
@@ -2394,14 +2596,17 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
gstate->surface,
0, 0,
0, 0,
- gstate->clip.x,
- gstate->clip.y,
- gstate->clip.width,
- gstate->clip.height);
-
- BAIL:
- cairo_surface_destroy (intermediate);
+ draw_extents->x1,
+ draw_extents->y1,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
+ BAIL2:
+ cairo_surface_destroy (intermediate);
+ BAIL1:
+ pixman_region_destroy (draw_region);
+ BAIL0:
+ ;
}
else
{
@@ -2416,6 +2621,7 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
_cairo_pattern_fini (&pattern);
+ CLEANUP_GLYPHS:
free (transformed_glyphs);
return status;
diff --git a/src/cairo_image_surface.c b/src/cairo_image_surface.c
index cbdc018a1..14e30f695 100644
--- a/src/cairo_image_surface.c
+++ b/src/cairo_image_surface.c
@@ -169,7 +169,7 @@ cairo_image_surface_create_for_data (char *data,
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),
@@ -199,7 +199,7 @@ 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);
@@ -490,7 +490,7 @@ _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
+static cairo_int_status_t
_cairo_image_abstract_surface_create_pattern (void *abstract_surface,
cairo_pattern_t *pattern,
cairo_box_t *box)
diff --git a/src/cairo_matrix.c b/src/cairo_matrix.c
index 7fc2694f3..b964b688c 100644
--- a/src/cairo_matrix.c
+++ b/src/cairo_matrix.c
@@ -34,6 +34,7 @@
* Carl D. Worth <cworth@isi.edu>
*/
+#define _GNU_SOURCE
#include <stdlib.h>
#include <math.h>
@@ -124,9 +125,20 @@ cairo_matrix_get_affine (cairo_matrix_t *matrix,
double *c, double *d,
double *tx, double *ty)
{
- *a = matrix->m[0][0]; *b = matrix->m[0][1];
- *c = matrix->m[1][0]; *d = matrix->m[1][1];
- *tx = matrix->m[2][0]; *ty = matrix->m[2][1];
+ 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;
}
@@ -176,9 +188,17 @@ 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,
- cos (radians), sin (radians),
- -sin (radians), cos (radians),
+ c, s,
+ -s, c,
0, 0);
}
@@ -398,19 +418,42 @@ _cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, dou
/* 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)
+_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy, int x_major)
{
- double x, y;
+ double det;
- x = 1.0;
- y = 0.0;
- cairo_matrix_transform_distance (matrix, &x, &y);
- *sx = sqrt(x*x + y*y);
+ _cairo_matrix_compute_determinant (matrix, &det);
- x = 0.0;
- y = 1.0;
- cairo_matrix_transform_distance (matrix, &x, &y);
- *sy = sqrt(x*x + y*y);
+ 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;
}
diff --git a/src/cairo_pdf_surface.c b/src/cairo_pdf_surface.c
new file mode 100644
index 000000000..23230aa74
--- /dev/null
+++ b/src/cairo_pdf_surface.c
@@ -0,0 +1,2208 @@
+/* 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: This seems broken to me. What about users without freetype
+ * that want to use a cairo PDF surface? */
+#include "cairo-ft.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?
+ *
+ * - Why isn't the pattern passed to composite traps instead of
+ * pattern->source? If composite traps needs an image or a surface it
+ * can call create_pattern().
+ *
+ * - 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;
+
+ /* HACK: Non-null if this surface was created for a pattern. */
+ cairo_pattern_t *pattern;
+
+ 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
+#define OFFSET_TABLE_SIZE 12
+#define TABLE_DIRECTORY_ENTRY_SIZE 16
+
+#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,
+ cairo_font_scale_t *scale)
+{
+ cairo_font_t scaled_font;
+ FT_Face face;
+ cairo_pdf_ft_font_t *font;
+ unsigned long size;
+ int i, j;
+
+ /* FIXME: Why do I have to pass a scaled font to get the FT_Face? */
+ _cairo_font_init (&scaled_font, scale, unscaled_font);
+ face = cairo_ft_font_face (&scaled_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->face = face;
+ 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;
+
+ 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, 0);
+ 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;
+
+ if (cairo_pdf_ft_font_write_offset_table (font))
+ return font->status;
+
+ start = cairo_pdf_ft_font_align_output (font);
+ end = start;
+
+ 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:
+ 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;
+
+ surface->pattern = NULL;
+ _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_font_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_image_surface_t *
+_cairo_pdf_surface_get_image (void *abstract_surface)
+{
+ return NULL;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_set_image (void *abstract_surface,
+ cairo_image_surface_t *image)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_set_matrix (void *abstract_surface,
+ cairo_matrix_t *matrix)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_set_filter (void *abstract_surface,
+ cairo_filter_t filter)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_set_repeat (void *abstract_surface,
+ int repeat)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+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_image_surface_t *image)
+{
+ cairo_pdf_document_t *document = dst->document;
+ FILE *file = document->file;
+ unsigned id;
+ cairo_matrix_t i2u;
+
+ id = emit_image_data (dst->document, image);
+ if (id == 0)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ _cairo_pdf_surface_add_xobject (dst, id);
+
+ _cairo_pdf_surface_ensure_stream (dst);
+
+ cairo_matrix_copy (&i2u, &image->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);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* 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_pdf_surface_t *src,
+ int width, int height)
+{
+ cairo_pdf_document_t *document = dst->document;
+ FILE *file = document->file;
+ cairo_matrix_t i2u;
+ cairo_pdf_stream_t *stream;
+ int num_streams, i;
+
+ if (src->pattern != NULL)
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_pdf_surface_ensure_stream (dst);
+
+ 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_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)
+{
+ cairo_pdf_surface_t *dst = abstract_dst;
+ cairo_pdf_surface_t *src;
+ cairo_image_surface_t *image;
+
+ if (generic_src->backend == &cairo_pdf_surface_backend) {
+ src = (cairo_pdf_surface_t *) generic_src;
+ return _cairo_pdf_surface_composite_pdf (dst, src, width, height);
+ }
+ else {
+ image = _cairo_surface_get_image (generic_src);
+ return _cairo_pdf_surface_composite_image (dst, image);
+ }
+}
+
+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;
+
+ if (surface->pattern != NULL)
+ return CAIRO_STATUS_SUCCESS;
+
+ _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_tiling_pattern (cairo_operator_t operator,
+ cairo_pdf_surface_t *dst,
+ cairo_pattern_t *pattern)
+{
+ cairo_pdf_document_t *document = dst->document;
+ FILE *file = document->file;
+ cairo_pdf_stream_t *stream;
+ cairo_image_surface_t *image;
+ char entries[250];
+ unsigned int id, alpha;
+ cairo_matrix_t pm;
+
+ if (pattern->u.surface.surface->backend == &cairo_pdf_surface_backend) {
+ return;
+ }
+
+ image = _cairo_surface_get_image (pattern->u.surface.surface);
+
+ _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->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);
+
+ _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);
+}
+
+static unsigned int
+emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_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_char[0], file);
+ fputc (pattern->stops[0].color_char[1], file);
+ fputc (pattern->stops[0].color_char[2], file);
+ fputc (pattern->stops[1].color_char[0], file);
+ fputc (pattern->stops[1].color_char[1], file);
+ fputc (pattern->stops[1].color_char[2], 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_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);
+
+ cairo_matrix_copy (&p2u, &pattern->matrix);
+ cairo_matrix_invert (&p2u);
+
+ x0 = pattern->u.linear.point0.x;
+ y0 = pattern->u.linear.point0.y;
+ cairo_matrix_transform_point (&p2u, &x0, &y0);
+ x1 = pattern->u.linear.point1.x;
+ y1 = pattern->u.linear.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 [ %s %s ]\r\n"
+ " >>\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ pattern_id,
+ document->height_inches * document->y_ppi,
+ x0, y0, x1, y1,
+ function_id,
+ (1 || pattern->extend) ? "true" : "false",
+ (1 || pattern->extend) ? "true" : "false");
+
+ _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_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);
+
+ cairo_matrix_copy (&p2u, &pattern->matrix);
+ cairo_matrix_invert (&p2u);
+
+ x0 = pattern->u.radial.center0.x;
+ y0 = pattern->u.radial.center0.y;
+ r0 = pattern->u.radial.radius0;
+ cairo_matrix_transform_point (&p2u, &x0, &y0);
+ x1 = pattern->u.radial.center1.x;
+ y1 = pattern->u.radial.center1.y;
+ r1 = pattern->u.radial.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);
+
+ 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 [ %s %s ]\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,
+ (1 || pattern->extend) ? "true" : "false",
+ (1 || pattern->extend) ? "true" : "false");
+
+ _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 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_surface_t *generic_src,
+ void *abstract_dst,
+ int x_src,
+ int y_src,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+{
+ cairo_pdf_surface_t *surface = abstract_dst;
+ cairo_pdf_surface_t *source = (cairo_pdf_surface_t *) generic_src;
+ cairo_pdf_document_t *document = surface->document;
+ cairo_pattern_t *pattern;
+ FILE *file = document->file;
+ int i;
+ unsigned int alpha;
+
+ /* FIXME: we really just want the original pattern here, not a
+ * source surface. */
+ pattern = source->pattern;
+
+ if (source->base.backend != &cairo_pdf_surface_backend) {
+ printf ("_cairo_pdf_surface_composite_trapezoids: not a pdf source\r");
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (pattern == NULL) {
+ printf ("_cairo_pdf_surface_composite_trapezoids: "
+ "non-pattern pdf source\r");
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_SOLID:
+ 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->color.red,
+ pattern->color.green,
+ pattern->color.blue,
+ alpha);
+ break;
+
+ case CAIRO_PATTERN_SURFACE:
+ emit_tiling_pattern (operator, surface, pattern);
+ break;
+
+ case CAIRO_PATTERN_LINEAR:
+ emit_linear_pattern (surface, pattern);
+ break;
+
+ case CAIRO_PATTERN_RADIAL:
+ emit_radial_pattern (surface, pattern );
+ break;
+ }
+
+ /* 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_int_status_t
+_cairo_pdf_surface_create_pattern (void *abstract_surface,
+ cairo_pattern_t *pattern,
+ cairo_box_t *extents)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_pdf_surface_t *source;
+
+ source = (cairo_pdf_surface_t *)
+ _cairo_pdf_surface_create_for_document (surface->document, 0, 0);
+ source->pattern = pattern;
+ pattern->source = &source->base;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_pdf_font_t *
+_cairo_pdf_document_get_font (cairo_pdf_document_t *document,
+ cairo_unscaled_font_t *unscaled_font,
+ cairo_font_scale_t *scale)
+{
+ cairo_pdf_font_t *font;
+ unsigned int num_fonts, i;
+
+ num_fonts = _cairo_array_num_elements (&document->fonts);
+ for (i = 0; i < num_fonts; i++) {
+ _cairo_array_copy_element (&document->fonts, i, &font);
+ if (font->unscaled_font == unscaled_font)
+ return font;
+ }
+
+ /* FIXME: Figure out here which font backend is in use and call
+ * the appropriate constructor. */
+ font = cairo_pdf_ft_font_create (document, unscaled_font, scale);
+ if (font == NULL)
+ return NULL;
+
+ if (_cairo_array_append (&document->fonts, &font, 1) == NULL) {
+ cairo_pdf_font_destroy (font);
+ return NULL;
+ }
+
+ return font;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_show_glyphs (cairo_unscaled_font_t *font,
+ cairo_font_scale_t *scale,
+ cairo_operator_t operator,
+ cairo_surface_t *source,
+ void *abstract_surface,
+ int source_x,
+ int source_y,
+ 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, scale);
+ if (pdf_font == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ _cairo_pdf_surface_ensure_stream (surface);
+
+ fprintf (file, "0 0 0 rg 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 (%c) Tj",
+ scale->matrix[0][0],
+ scale->matrix[0][1],
+ scale->matrix[1][0],
+ -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_get_image,
+ _cairo_pdf_surface_set_image,
+ _cairo_pdf_surface_set_matrix,
+ _cairo_pdf_surface_set_filter,
+ _cairo_pdf_surface_set_repeat,
+ _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_create_pattern,
+ _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 /%s\r\n"
+ " /Flags 32\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_png_surface.c b/src/cairo_png_surface.c
index 4c689d599..2279b07a9 100644
--- a/src/cairo_png_surface.c
+++ b/src/cairo_png_surface.c
@@ -38,6 +38,7 @@
#include <png.h>
#include "cairoint.h"
+#include "cairo-png.h"
static const cairo_surface_backend_t cairo_png_surface_backend;
diff --git a/src/cairo_polygon.c b/src/cairo_polygon.c
index 8fa32f9f6..e85858033 100644
--- a/src/cairo_polygon.c
+++ b/src/cairo_polygon.c
@@ -37,8 +37,6 @@
#include <stdlib.h>
#include "cairoint.h"
-#define CAIRO_POLYGON_GROWTH_INC 10
-
/* private functions */
static cairo_status_t
@@ -104,7 +102,8 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_poin
}
if (polygon->num_edges >= polygon->edges_size) {
- status = _cairo_polygon_grow_by (polygon, CAIRO_POLYGON_GROWTH_INC);
+ int additional = polygon->edges_size ? polygon->edges_size : 16;
+ status = _cairo_polygon_grow_by (polygon, additional);
if (status) {
return status;
}
diff --git a/src/cairo_ps_surface.c b/src/cairo_ps_surface.c
index bfdfada38..4da8162c7 100644
--- a/src/cairo_ps_surface.c
+++ b/src/cairo_ps_surface.c
@@ -35,6 +35,7 @@
*/
#include "cairoint.h"
+#include "cairo-ps.h"
#include <time.h>
#include <zlib.h>
@@ -130,8 +131,6 @@ cairo_ps_surface_create (FILE *file,
"%%%%CreationDate: %s",
ctime (&now));
fprintf (file,
- "%%%%Copyright: 2003 Carl Worth and Keith Packard\n");
- 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 */
diff --git a/src/cairo_quartz_surface.c b/src/cairo_quartz_surface.c
new file mode 100644
index 000000000..b7103b051
--- /dev/null
+++ b/src/cairo_quartz_surface.c
@@ -0,0 +1,392 @@
+/* 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_spline.c b/src/cairo_spline.c
index bed351ef4..ff290d9dd 100644
--- a/src/cairo_spline.c
+++ b/src/cairo_spline.c
@@ -54,8 +54,6 @@ _cairo_spline_error_squared (cairo_spline_t *spline);
static cairo_status_t
_cairo_spline_decompose_into (cairo_spline_t *spline, double tolerance_squared, cairo_spline_t *result);
-#define CAIRO_SPLINE_GROWTH_INC 100
-
cairo_int_status_t
_cairo_spline_init (cairo_spline_t *spline,
cairo_point_t *a, cairo_point_t *b,
@@ -136,7 +134,8 @@ _cairo_spline_add_point (cairo_spline_t *spline, cairo_point_t *point)
}
if (spline->num_points >= spline->points_size) {
- status = _cairo_spline_grow_by (spline, CAIRO_SPLINE_GROWTH_INC);
+ int additional = spline->points_size ? spline->points_size : 32;
+ status = _cairo_spline_grow_by (spline, additional);
if (status)
return status;
}
diff --git a/src/cairo_wideint.c b/src/cairo_wideint.c
index 45682c1cb..b636dface 100644
--- a/src/cairo_wideint.c
+++ b/src/cairo_wideint.c
@@ -1,25 +1,37 @@
/*
- * $Id: cairo_wideint.c,v 1.1 2004-05-28 19:37:15 keithp Exp $
+ * $Id: cairo_wideint.c,v 1.4 2005-01-19 15:07:00 cworth Exp $
*
* Copyright © 2004 Keith Packard
*
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
+ * 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.
*
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
+ * 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"
@@ -44,7 +56,7 @@ static const unsigned char top_bit[256] =
#define _cairo_uint32s_to_uint64(h,l) ((uint64_t) (h) << 32 | (l))
-const cairo_uquorem64_t
+cairo_uquorem64_t
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
{
cairo_uquorem64_t qr;
@@ -56,7 +68,7 @@ _cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
#else
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint32_to_uint64 (uint32_t i)
{
cairo_uint64_t q;
@@ -66,7 +78,7 @@ _cairo_uint32_to_uint64 (uint32_t i)
return q;
}
-const cairo_int64_t
+cairo_int64_t
_cairo_int32_to_int64 (int32_t i)
{
cairo_uint64_t q;
@@ -86,7 +98,7 @@ _cairo_uint32s_to_uint64 (uint32_t h, uint32_t l)
return q;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint64_t s;
@@ -98,7 +110,7 @@ _cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b)
return s;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint64_t s;
@@ -114,7 +126,7 @@ _cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b)
#define uint32_hi(i) ((i) >> 16)
#define uint32_carry16 ((1) << 16)
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint32x32_64_mul (uint32_t a, uint32_t b)
{
cairo_uint64_t s;
@@ -142,7 +154,18 @@ _cairo_uint32x32_64_mul (uint32_t a, uint32_t b)
return s;
}
-const cairo_uint64_t
+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;
@@ -152,7 +175,7 @@ _cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b)
return s;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_lsl (cairo_uint64_t a, int shift)
{
if (shift >= 32)
@@ -169,7 +192,7 @@ _cairo_uint64_lsl (cairo_uint64_t a, int shift)
return a;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_rsl (cairo_uint64_t a, int shift)
{
if (shift >= 32)
@@ -188,7 +211,7 @@ _cairo_uint64_rsl (cairo_uint64_t a, int shift)
#define _cairo_uint32_rsa(a,n) ((uint32_t) (((int32_t) (a)) >> (n)))
-const cairo_int64_t
+cairo_int64_t
_cairo_uint64_rsa (cairo_int64_t a, int shift)
{
if (shift >= 32)
@@ -205,20 +228,20 @@ _cairo_uint64_rsa (cairo_int64_t a, int shift)
return a;
}
-const int
+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));
}
-const int
+int
_cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b)
{
return a.hi == b.hi && a.lo == b.lo;
}
-const int
+int
_cairo_int64_lt (cairo_int64_t a, cairo_int64_t b)
{
if (_cairo_int64_negative (a) && !_cairo_int64_negative (b))
@@ -228,7 +251,7 @@ _cairo_int64_lt (cairo_int64_t a, cairo_int64_t b)
return _cairo_uint64_lt (a, b);
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_not (cairo_uint64_t a)
{
a.lo = ~a.lo;
@@ -236,7 +259,7 @@ _cairo_uint64_not (cairo_uint64_t a)
return a;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_negate (cairo_uint64_t a)
{
a.lo = ~a.lo;
@@ -325,7 +348,7 @@ _cairo_uint64x32_normalized_divrem (cairo_uint64_t num, uint32_t den)
return qr;
}
-const cairo_uquorem64_t
+cairo_uquorem64_t
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
{
cairo_uquorem32_t qr32;
@@ -444,7 +467,7 @@ _cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
#endif /* !HAVE_UINT64_T */
-const cairo_quorem64_t
+cairo_quorem64_t
_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den)
{
int num_neg = _cairo_int64_negative (num);
@@ -470,7 +493,7 @@ _cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den)
#if HAVE_UINT128_T
-const cairo_uquorem128_t
+cairo_uquorem128_t
_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
{
cairo_uquorem128_t qr;
@@ -482,7 +505,7 @@ _cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
#else
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint32_to_uint128 (uint32_t i)
{
cairo_uint128_t q;
@@ -492,7 +515,7 @@ _cairo_uint32_to_uint128 (uint32_t i)
return q;
}
-const cairo_int128_t
+cairo_int128_t
_cairo_int32_to_int128 (int32_t i)
{
cairo_int128_t q;
@@ -502,7 +525,7 @@ _cairo_int32_to_int128 (int32_t i)
return q;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint64_to_uint128 (cairo_uint64_t i)
{
cairo_uint128_t q;
@@ -512,7 +535,7 @@ _cairo_uint64_to_uint128 (cairo_uint64_t i)
return q;
}
-const cairo_int128_t
+cairo_int128_t
_cairo_int64_to_int128 (cairo_int64_t i)
{
cairo_int128_t q;
@@ -522,7 +545,7 @@ _cairo_int64_to_int128 (cairo_int64_t i)
return q;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b)
{
cairo_uint128_t s;
@@ -534,7 +557,7 @@ _cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b)
return s;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b)
{
cairo_uint128_t s;
@@ -594,7 +617,7 @@ static const cairo_uint64_t uint64_carry32 = { 0, 1 };
#endif
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint128_t s;
@@ -622,7 +645,22 @@ _cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b)
return s;
}
-const cairo_uint128_t
+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;
@@ -635,7 +673,7 @@ _cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b)
return s;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_lsl (cairo_uint128_t a, int shift)
{
if (shift >= 64)
@@ -653,7 +691,7 @@ _cairo_uint128_lsl (cairo_uint128_t a, int shift)
return a;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_rsl (cairo_uint128_t a, int shift)
{
if (shift >= 64)
@@ -671,7 +709,7 @@ _cairo_uint128_rsl (cairo_uint128_t a, int shift)
return a;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_rsa (cairo_int128_t a, int shift)
{
if (shift >= 64)
@@ -689,7 +727,7 @@ _cairo_uint128_rsa (cairo_int128_t a, int shift)
return a;
}
-const int
+int
_cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b)
{
return (_cairo_uint64_lt (a.hi, b.hi) ||
@@ -697,7 +735,7 @@ _cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b)
_cairo_uint64_lt (a.lo, b.lo)));
}
-const int
+int
_cairo_int128_lt (cairo_int128_t a, cairo_int128_t b)
{
if (_cairo_int128_negative (a) && !_cairo_int128_negative (b))
@@ -707,7 +745,7 @@ _cairo_int128_lt (cairo_int128_t a, cairo_int128_t b)
return _cairo_uint128_lt (a, b);
}
-const int
+int
_cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b)
{
return (_cairo_uint64_eq (a.hi, b.hi) &&
@@ -722,7 +760,7 @@ _cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b)
/*
* den >= num.hi
*/
-static const cairo_uquorem64_t
+static cairo_uquorem64_t
_cairo_uint128x64_normalized_divrem (cairo_uint128_t num, cairo_uint64_t den)
{
cairo_uquorem64_t qr64;
@@ -786,7 +824,7 @@ _cairo_uint128x64_normalized_divrem (cairo_uint128_t num, cairo_uint64_t den)
#if HAVE_UINT64_T
-static const int
+static int
_cairo_leading_zeros64 (cairo_uint64_t q)
{
int top = 0;
@@ -823,7 +861,7 @@ _cairo_leading_zeros64 (cairo_uint64_t d)
#endif
-const cairo_uquorem128_t
+cairo_uquorem128_t
_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
{
cairo_uquorem64_t qr64;
@@ -943,7 +981,7 @@ _cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
return qr;
}
-const cairo_int128_t
+cairo_int128_t
_cairo_int128_negate (cairo_int128_t a)
{
a.lo = _cairo_uint64_not (a.lo);
@@ -951,7 +989,7 @@ _cairo_int128_negate (cairo_int128_t a)
return _cairo_uint128_add (a, _cairo_uint32_to_uint128 (1));
}
-const cairo_int128_t
+cairo_int128_t
_cairo_int128_not (cairo_int128_t a)
{
a.lo = _cairo_uint64_not (a.lo);
@@ -961,7 +999,7 @@ _cairo_int128_not (cairo_int128_t a)
#endif /* !HAVE_UINT128_T */
-const cairo_quorem128_t
+cairo_quorem128_t
_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den)
{
int num_neg = _cairo_int128_negative (num);
diff --git a/src/cairo_wideint.h b/src/cairo_wideint.h
deleted file mode 100644
index c634ce081..000000000
--- a/src/cairo_wideint.h
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * $Id: cairo_wideint.h,v 1.1 2004-05-28 19:37:15 keithp Exp $
- *
- * Copyright © 2004 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef CAIRO_WIDEINT_H
-#define CAIRO_WIDEINT_H
-
-#include <stdint.h>
-
-/*
- * 64-bit datatypes. Two separate implementations, one using
- * built-in 64-bit signed/unsigned types another implemented
- * as a pair of 32-bit ints
- */
-
-#define I __internal_linkage
-
-#if !HAVE_UINT64_T
-
-typedef struct _cairo_uint64 {
- uint32_t lo, hi;
-} cairo_uint64_t, cairo_int64_t;
-
-const cairo_uint64_t I _cairo_uint32_to_uint64 (uint32_t i);
-#define _cairo_uint64_to_uint32(a) ((a).lo)
-const cairo_uint64_t I _cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b);
-const cairo_uint64_t I _cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b);
-const cairo_uint64_t I _cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b);
-const cairo_uint64_t I _cairo_uint32x32_64_mul (uint32_t a, uint32_t b);
-const cairo_uint64_t I _cairo_uint64_lsl (cairo_uint64_t a, int shift);
-const cairo_uint64_t I _cairo_uint64_rsl (cairo_uint64_t a, int shift);
-const cairo_uint64_t I _cairo_uint64_rsa (cairo_uint64_t a, int shift);
-const int _cairo_uint64_lt (cairo_uint64_t a, cairo_uint64_t b);
-const int _cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b);
-const cairo_uint64_t I _cairo_uint64_negate (cairo_uint64_t a);
-#define _cairo_uint64_negative(a) (((int32_t) ((a).hi)) < 0)
-const cairo_uint64_t I _cairo_uint64_not (cairo_uint64_t a);
-
-#define _cairo_uint64_to_int64(i) (i)
-#define _cairo_int64_to_uint64(i) (i)
-
-const cairo_int64_t I _cairo_int32_to_int64(int32_t i);
-#define _cairo_int64_to_int32(a) ((int32_t) _cairo_uint64_to_uint32(a))
-#define _cairo_int64_add(a,b) _cairo_uint64_add (a,b)
-#define _cairo_int64_sub(a,b) _cairo_uint64_sub (a,b)
-#define _cairo_int64_mul(a,b) _cairo_uint64_mul (a,b)
-#define _cairo_int32x32_64_mul(a,b) _cairo_uint32x32_64_mul ((uint32_t) (a), (uint32_t) (b)))
-const int _cairo_int64_lt (cairo_uint64_t a, cairo_uint64_t b);
-#define _cairo_int64_eq(a,b) _cairo_uint64_eq (a,b)
-#define _cairo_int64_lsl(a,b) _cairo_uint64_lsl (a,b)
-#define _cairo_int64_rsl(a,b) _cairo_uint64_rsl (a,b)
-#define _cairo_int64_rsa(a,b) _cairo_uint64_rsa (a,b)
-#define _cairo_int64_negate(a) _cairo_uint64_negate(a)
-#define _cairo_int64_negative(a) (((int32_t) ((a).hi)) < 0)
-#define _cairo_int64_not(a) _cairo_uint64_not(a)
-
-#else
-
-typedef uint64_t cairo_uint64_t;
-typedef int64_t cairo_int64_t;
-
-#define _cairo_uint32_to_uint64(i) ((uint64_t) (i))
-#define _cairo_uint64_to_uint32(i) ((uint32_t) (i))
-#define _cairo_uint64_add(a,b) ((a) + (b))
-#define _cairo_uint64_sub(a,b) ((a) - (b))
-#define _cairo_uint64_mul(a,b) ((a) * (b))
-#define _cairo_uint32x32_64_mul(a,b) ((uint64_t) (a) * (b))
-#define _cairo_uint64_lsl(a,b) ((a) << (b))
-#define _cairo_uint64_rsl(a,b) ((uint64_t) (a) >> (b))
-#define _cairo_uint64_rsa(a,b) ((uint64_t) ((int64_t) (a) >> (b)))
-#define _cairo_uint64_lt(a,b) ((a) < (b))
-#define _cairo_uint64_eq(a,b) ((a) == (b))
-#define _cairo_uint64_negate(a) ((uint64_t) -((int64_t) (a)))
-#define _cairo_uint64_negative(a) ((int64_t) (a) < 0)
-#define _cairo_uint64_not(a) (~(a))
-
-#define _cairo_uint64_to_int64(i) ((int64_t) (i))
-#define _cairo_int64_to_uint64(i) ((uint64_t) (i))
-
-#define _cairo_int32_to_int64(i) ((int64_t) (i))
-#define _cairo_int64_to_int32(i) ((int32_t) (i))
-#define _cairo_int64_add(a,b) ((a) + (b))
-#define _cairo_int64_sub(a,b) ((a) - (b))
-#define _cairo_int64_mul(a,b) ((a) * (b))
-#define _cairo_int32x32_64_mul(a,b) ((int64_t) (a) * (b))
-#define _cairo_int64_lt(a,b) ((a) < (b))
-#define _cairo_int64_eq(a,b) ((a) == (b))
-#define _cairo_int64_lsl(a,b) ((a) << (b))
-#define _cairo_int64_rsl(a,b) ((int64_t) ((uint64_t) (a) >> (b)))
-#define _cairo_int64_rsa(a,b) ((int64_t) (a) >> (b))
-#define _cairo_int64_negate(a) (-(a))
-#define _cairo_int64_negative(a) ((a) < 0)
-#define _cairo_int64_not(a) (~(a))
-
-#endif
-
-/*
- * 64-bit comparisions derived from lt or eq
- */
-#define _cairo_uint64_le(a,b) (!_cairo_uint64_gt(a,b))
-#define _cairo_uint64_ne(a,b) (!_cairo_uint64_eq(a,b))
-#define _cairo_uint64_ge(a,b) (!_cairo_uint64_lt(a,b))
-#define _cairo_uint64_gt(a,b) _cairo_uint64_lt(b,a)
-
-#define _cairo_int64_le(a,b) (!_cairo_int64_gt(a,b))
-#define _cairo_int64_ne(a,b) (!_cairo_int64_eq(a,b))
-#define _cairo_int64_ge(a,b) (!_cairo_int64_lt(a,b))
-#define _cairo_int64_gt(a,b) _cairo_int64_lt(b,a)
-
-/*
- * As the C implementation always computes both, create
- * a function which returns both for the 'native' type as well
- */
-
-typedef struct _cairo_uquorem64 {
- cairo_uint64_t quo;
- cairo_uint64_t rem;
-} cairo_uquorem64_t;
-
-typedef struct _cairo_quorem64 {
- cairo_int64_t quo;
- cairo_int64_t rem;
-} cairo_quorem64_t;
-
-const cairo_uquorem64_t I
-_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den);
-
-const cairo_quorem64_t I
-_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den);
-
-/*
- * 128-bit datatypes. Again, provide two implementations in
- * case the machine has a native 128-bit datatype. GCC supports int128_t
- * on ia64
- */
-
-#if !HAVE_UINT128_T
-
-typedef struct cairo_uint128 {
- cairo_uint64_t lo, hi;
-} cairo_uint128_t, cairo_int128_t;
-
-const cairo_uint128_t I _cairo_uint32_to_uint128 (uint32_t i);
-const cairo_uint128_t I _cairo_uint64_to_uint128 (cairo_uint64_t i);
-#define _cairo_uint128_to_uint64(a) ((a).lo)
-#define _cairo_uint128_to_uint32(a) _cairo_uint64_to_uint32(_cairo_uint128_to_uint64(a))
-const cairo_uint128_t I _cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b);
-const cairo_uint128_t I _cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b);
-const cairo_uint128_t I _cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b);
-const cairo_uint128_t I _cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b);
-const cairo_uint128_t I _cairo_uint128_lsl (cairo_uint128_t a, int shift);
-const cairo_uint128_t I _cairo_uint128_rsl (cairo_uint128_t a, int shift);
-const cairo_uint128_t I _cairo_uint128_rsa (cairo_uint128_t a, int shift);
-const int _cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b);
-const int _cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b);
-const cairo_uint128_t I _cairo_uint128_negate (cairo_uint128_t a);
-#define _cairo_uint128_negative(a) (_cairo_uint64_negative(a.hi))
-const cairo_uint128_t I _cairo_uint128_not (cairo_uint128_t a);
-
-#define _cairo_uint128_to_int128_(i) (i)
-#define _cairo_int128_to_uint128(i) (i)
-
-const cairo_int128_t I _cairo_int32_to_int128 (int32_t i);
-const cairo_int128_t I _cairo_int64_to_int128 (cairo_int64_t i);
-#define _cairo_int128_to_int64(a) ((cairo_int64_t) (a).lo);
-#define _cairo_int128_to_int32(a) _cairo_int64_to_int32(_cairo_int128_to_int64(a))
-#define _cairo_int128_add(a,b) _cairo_uint128_add(a,b)
-#define _cairo_int128_sub(a,b) _cairo_uint128_sub(a,b)
-#define _cairo_int128_mul(a,b) _cairo_uint128_mul(a,b)
-#define _cairo_int64x64_128_mul(a,b) _cairo_uint64x64_128_mul ((cairo_uint64_t) (a), (cairo_uint64_t) (b))
-#define _cairo_int128_lsl(a,b) _cairo_uint128_lsl(a,b)
-#define _cairo_int128_rsl(a,b) _cairo_uint128_rsl(a,b)
-#define _cairo_int128_rsa(a,b) _cairo_uint128_rsa(a,b)
-const int _cairo_int128_lt (cairo_int128_t a, cairo_int128_t b);
-#define _cairo_int128_eq(a,b) _cairo_uint128_eq (a,b)
-#define _cairo_int128_negate(a) _cairo_uint128_negate(a)
-#define _cairo_int128_negative(a) (_cairo_uint128_negative(a))
-#define _cairo_int128_not(a) _cairo_uint128_not(a)
-
-#else /* !HAVE_UINT128_T */
-
-typedef uint128_t cairo_uint128_t;
-typedef int128_t cairo_int128_t;
-
-#define _cairo_uint32_to_uint128(i) ((uint128_t) (i))
-#define _cairo_uint64_to_uint128(i) ((uint128_t) (i))
-#define _cairo_uint128_to_uint64(i) ((uint64_t) (i))
-#define _cairo_uint128_to_uint32(i) ((uint32_t) (i))
-#define _cairo_uint128_add(a,b) ((a) + (b))
-#define _cairo_uint128_sub(a,b) ((a) - (b))
-#define _cairo_uint128_mul(a,b) ((a) * (b))
-#define _cairo_uint64x64_128_mul(a,b) ((uint128_t) (a) * (b))
-#define _cairo_uint128_lsl(a,b) ((a) << (b))
-#define _cairo_uint128_rsl(a,b) ((uint128_t) (a) >> (b))
-#define _cairo_uint128_rsa(a,b) ((uint128_t) ((int128_t) (a) >> (b)))
-#define _cairo_uint128_lt(a,b) ((a) < (b))
-#define _cairo_uint128_eq(a,b) ((a) == (b))
-#define _cairo_uint128_negate(a) ((uint128_t) -((int128_t) (a)))
-#define _cairo_uint128_negative(a) ((int128_t) (a) < 0)
-#define _cairo_uint128_not(a) (~(a))
-
-#define _cairo_uint128_to_int128(i) ((int128_t) (i))
-#define _cairo_int128_to_uint128(i) ((uint128_t) (i))
-
-#define _cairo_int32_to_int128(i) ((int128_t) (i))
-#define _cairo_int64_to_int128(i) ((int128_t) (i))
-#define _cairo_int128_to_int64(i) ((int64_t) (i))
-#define _cairo_int128_to_int32(i) ((int32_t) (i))
-#define _cairo_int128_add(a,b) ((a) + (b))
-#define _cairo_int128_sub(a,b) ((a) - (b))
-#define _cairo_int128_mul(a,b) ((a) * (b))
-#define _cairo_int64x64_128_mul(a,b) ((int128_t) (a) * (b))
-#define _cairo_int128_lt(a,b) ((a) < (b))
-#define _cairo_int128_eq(a,b) ((a) == (b))
-#define _cairo_int128_lsl(a,b) ((a) << (b))
-#define _cairo_int128_rsl(a,b) ((int128_t) ((uint128_t) (a) >> (b)))
-#define _cairo_int128_rsa(a,b) ((int128_t) (a) >> (b))
-#define _cairo_int128_negate(a) (-(a))
-#define _cairo_int128_negative(a) ((a) < 0)
-#define _cairo_int128_not(a) (~(a))
-
-#endif /* HAVE_UINT128_T */
-
-typedef struct _cairo_uquorem128 {
- cairo_uint128_t quo;
- cairo_uint128_t rem;
-} cairo_uquorem128_t;
-
-typedef struct _cairo_quorem128 {
- cairo_int128_t quo;
- cairo_int128_t rem;
-} cairo_quorem128_t;
-
-const cairo_uquorem128_t I
-_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den);
-
-const cairo_quorem128_t I
-_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den);
-
-#define _cairo_uint128_le(a,b) (!_cairo_uint128_gt(a,b))
-#define _cairo_uint128_ne(a,b) (!_cairo_uint128_eq(a,b))
-#define _cairo_uint128_ge(a,b) (!_cairo_uint128_lt(a,b))
-#define _cairo_uint128_gt(a,b) _cairo_uint128_lt(b,a)
-
-#define _cairo_int128_le(a,b) (!_cairo_int128_gt(a,b))
-#define _cairo_int128_ne(a,b) (!_cairo_int128_eq(a,b))
-#define _cairo_int128_ge(a,b) (!_cairo_int128_lt(a,b))
-#define _cairo_int128_gt(a,b) _cairo_int128_lt(b,a)
-
-#undef I
-
-#endif /* CAIRO_WIDEINT_H */
diff --git a/src/cairo_xcb_surface.c b/src/cairo_xcb_surface.c
index 21760d764..758cf26de 100644
--- a/src/cairo_xcb_surface.c
+++ b/src/cairo_xcb_surface.c
@@ -730,7 +730,7 @@ _cairo_xcb_surface_create_pattern (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static const struct cairo_surface_backend cairo_xcb_surface_backend = {
+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,
diff --git a/src/cairo_xlib_surface.c b/src/cairo_xlib_surface.c
index dda7995bd..d9d74f583 100644
--- a/src/cairo_xlib_surface.c
+++ b/src/cairo_xlib_surface.c
@@ -35,6 +35,7 @@
*/
#include "cairoint.h"
+#include "cairo-xlib.h"
void
cairo_set_target_drawable (cairo_t *cr,
@@ -61,7 +62,7 @@ cairo_set_target_drawable (cairo_t *cr,
cairo_surface_destroy (surface);
}
-typedef struct cairo_xlib_surface {
+typedef struct _cairo_xlib_surface {
cairo_surface_t base;
Display *dpy;
@@ -118,6 +119,16 @@ _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 cairo_surface_t *
_cairo_xlib_surface_create_similar (void *abstract_src,
cairo_format_t format,
int drawable,
@@ -149,7 +160,9 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
_CAIRO_FORMAT_DEPTH (format));
surface = (cairo_xlib_surface_t *)
- cairo_xlib_surface_create (dpy, pix, NULL, format, DefaultColormap (dpy, scr));
+ _cairo_xlib_surface_create_with_size (dpy, pix, NULL, format,
+ DefaultColormap (dpy, scr),
+ width, height);
surface->owns_pixmap = 1;
surface->width = width;
@@ -199,6 +212,7 @@ _cairo_xlib_surface_get_image (void *abstract_surface)
&surface->width, &surface->height,
&bwidth_ignore, &depth_ignore);
+ /* XXX: This should try to use the XShm extension if availible */
ximage = XGetImage (surface->dpy,
surface->drawable,
0, 0,
@@ -684,13 +698,13 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
cairo_font_scale_t *scale,
cairo_operator_t operator,
cairo_surface_t *source,
- cairo_surface_t *surface,
+ void *abstract_surface,
int source_x,
int source_y,
const cairo_glyph_t *glyphs,
int num_glyphs);
-static const struct cairo_surface_backend cairo_xlib_surface_backend = {
+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,
@@ -709,17 +723,17 @@ static const struct cairo_surface_backend cairo_xlib_surface_backend = {
_cairo_xlib_surface_show_glyphs
};
-cairo_surface_t *
-cairo_xlib_surface_create (Display *dpy,
- Drawable drawable,
- Visual *visual,
- cairo_format_t format,
- Colormap colormap)
+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;
- Window w;
- unsigned int ignore;
surface = malloc (sizeof (cairo_xlib_surface_t));
if (surface == NULL)
@@ -736,7 +750,9 @@ cairo_xlib_surface_create (Display *dpy,
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;
@@ -758,12 +774,6 @@ cairo_xlib_surface_create (Display *dpy,
break;
}
- XGetGeometry(dpy, drawable,
- &w, &ignore, &ignore,
- &surface->width,
- &surface->height,
- &ignore, &ignore);
-
/* XXX: I'm currently ignoring the colormap. Is that bad? */
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
surface->picture = XRenderCreatePicture (dpy, drawable,
@@ -776,8 +786,31 @@ cairo_xlib_surface_create (Display *dpy,
return (cairo_surface_t *) surface;
}
-DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create);
+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 */
@@ -839,8 +872,45 @@ _xlib_glyphset_cache_create_entry (void *cache,
v->info.width = im->image ? im->image->stride : im->size.width;
v->info.height = im->size.height;
- v->info.x = - im->extents.x_bearing;
- v->info.y = im->extents.y_bearing;
+
+ /*
+ * 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;
@@ -875,7 +945,7 @@ _xlib_glyphset_cache_destroy_entry (void *cache, void *entry)
free (v);
}
-const cairo_cache_backend_t _xlib_glyphset_cache_backend = {
+static const cairo_cache_backend_t _xlib_glyphset_cache_backend = {
_cairo_glyph_cache_hash,
_cairo_glyph_cache_keys_equal,
_xlib_glyphset_cache_create_entry,
@@ -964,6 +1034,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font,
unsigned int stack_chars [N_STACK_BUF];
int i;
+ int thisX, thisY;
int lastX = 0, lastY = 0;
/* Acquire arrays of suitable sizes. */
@@ -987,10 +1058,12 @@ _cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font,
elts[i].chars = &(chars[i]);
elts[i].nchars = 1;
elts[i].glyphset = g->glyphset;
- elts[i].xOff = glyphs[i].x - lastX;
- elts[i].yOff = glyphs[i].y - lastY;
- lastX = glyphs[i].x;
- lastY = glyphs[i].y;
+ 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,
@@ -1039,6 +1112,7 @@ _cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font,
unsigned short stack_chars [N_STACK_BUF];
int i;
+ int thisX, thisY;
int lastX = 0, lastY = 0;
/* Acquire arrays of suitable sizes. */
@@ -1062,10 +1136,12 @@ _cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font,
elts[i].chars = &(chars[i]);
elts[i].nchars = 1;
elts[i].glyphset = g->glyphset;
- elts[i].xOff = glyphs[i].x - lastX;
- elts[i].yOff = glyphs[i].y - lastY;
- lastX = glyphs[i].x;
- lastY = glyphs[i].y;
+ 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,
@@ -1113,6 +1189,7 @@ _cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font,
char stack_chars [N_STACK_BUF];
int i;
+ int thisX, thisY;
int lastX = 0, lastY = 0;
/* Acquire arrays of suitable sizes. */
@@ -1136,10 +1213,12 @@ _cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font,
elts[i].chars = &(chars[i]);
elts[i].nchars = 1;
elts[i].glyphset = g->glyphset;
- elts[i].xOff = glyphs[i].x - lastX;
- elts[i].yOff = glyphs[i].y - lastY;
- lastX = glyphs[i].x;
- lastY = glyphs[i].y;
+ 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,
@@ -1172,14 +1251,14 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
cairo_font_scale_t *scale,
cairo_operator_t operator,
cairo_surface_t *source,
- cairo_surface_t *surface,
+ void *abstract_surface,
int source_x,
int source_y,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
unsigned int elt_size;
- cairo_xlib_surface_t *self = (cairo_xlib_surface_t *) surface;
+ cairo_xlib_surface_t *self = abstract_surface;
cairo_image_surface_t *tmp = NULL;
cairo_xlib_surface_t *src = NULL;
glyphset_cache_t *g;
@@ -1200,7 +1279,7 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
}
/* prep the source surface. */
- if (source->backend == surface->backend) {
+ if (source->backend == self->base.backend) {
src = (cairo_xlib_surface_t *) source;
} else {
@@ -1209,7 +1288,7 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
goto FREE_ENTRIES;
src = (cairo_xlib_surface_t *)
- _cairo_surface_create_similar_scratch (surface, self->format, 1,
+ _cairo_surface_create_similar_scratch (&self->base, self->format, 1,
tmp->width, tmp->height);
if (src == NULL)
diff --git a/src/cairoint.h b/src/cairoint.h
index be0e54e78..6f9d50617 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -49,6 +49,7 @@
#include "config.h"
#endif
+#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
@@ -63,7 +64,7 @@
# define slim_hidden_proto1(name, internal) \
extern __typeof (name) name \
__asm__ (slim_hidden_asmname (internal)) \
- __internal_linkage;
+ cairo_private;
# define slim_hidden_def1(name, internal) \
extern __typeof (name) EXT_##name __asm__(slim_hidden_asmname(name)) \
__attribute__((__alias__(slim_hidden_asmname(internal))))
@@ -79,12 +80,11 @@
/* slim_internal.h */
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__)
-#define __internal_linkage __attribute__((__visibility__("hidden")))
+#define cairo_private __attribute__((__visibility__("hidden")))
#else
-#define __internal_linkage
+#define cairo_private
#endif
-
/* These macros 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
@@ -108,7 +108,7 @@
#define __attribute__(x)
#endif
-#include "cairo_wideint.h"
+#include "cairo-wideint.h"
typedef int32_t cairo_fixed_16_16_t;
typedef cairo_int64_t cairo_fixed_32_32_t;
@@ -122,38 +122,38 @@ typedef cairo_fixed_16_16_t cairo_fixed_t;
#define CAIRO_MAXSHORT SHRT_MAX
#define CAIRO_MINSHORT SHRT_MIN
-typedef struct cairo_point {
+typedef struct _cairo_point {
cairo_fixed_t x;
cairo_fixed_t y;
} cairo_point_t;
-typedef struct cairo_slope
+typedef struct _cairo_slope
{
cairo_fixed_t dx;
cairo_fixed_t dy;
} cairo_slope_t, cairo_distance_t;
-typedef struct cairo_point_double {
+typedef struct _cairo_point_double {
double x;
double y;
} cairo_point_double_t;
-typedef struct cairo_distance_double {
+typedef struct _cairo_distance_double {
double dx;
double dy;
} cairo_distance_double_t;
-typedef struct cairo_line {
+typedef struct _cairo_line {
cairo_point_t p1;
cairo_point_t p2;
} cairo_line_t, cairo_box_t;
-typedef struct cairo_trapezoid {
+typedef struct _cairo_trapezoid {
cairo_fixed_t top, bottom;
cairo_line_t left, right;
} cairo_trapezoid_t;
-typedef struct cairo_rectangle_int {
+typedef struct _cairo_rectangle_int {
short x, y;
unsigned short width, height;
} cairo_rectangle_t, cairo_glyph_size_t;
@@ -180,21 +180,21 @@ typedef enum cairo_direction {
#define CAIRO_PATH_BUF_SZ 64
-typedef struct cairo_path_op_buf {
+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;
+ struct _cairo_path_op_buf *next, *prev;
} cairo_path_op_buf_t;
-typedef struct cairo_path_arg_buf {
+typedef struct _cairo_path_arg_buf {
int num_points;
cairo_point_t points[CAIRO_PATH_BUF_SZ];
- struct cairo_path_arg_buf *next, *prev;
+ struct _cairo_path_arg_buf *next, *prev;
} cairo_path_arg_buf_t;
-typedef struct cairo_path {
+typedef struct _cairo_path {
cairo_path_op_buf_t *op_head;
cairo_path_op_buf_t *op_tail;
@@ -206,14 +206,14 @@ typedef struct cairo_path {
int has_current_point;
} cairo_path_t;
-typedef struct cairo_edge {
+typedef struct _cairo_edge {
cairo_line_t edge;
int clockWise;
cairo_fixed_16_16_t current_x;
} cairo_edge_t;
-typedef struct cairo_polygon {
+typedef struct _cairo_polygon {
int num_edges;
int edges_size;
cairo_edge_t *edges;
@@ -225,7 +225,7 @@ typedef struct cairo_polygon {
int closed;
} cairo_polygon_t;
-typedef struct cairo_spline {
+typedef struct _cairo_spline {
cairo_point_t a, b, c, d;
cairo_slope_t initial_slope;
@@ -243,7 +243,7 @@ typedef struct _cairo_pen_vertex {
cairo_slope_t slope_cw;
} cairo_pen_vertex_t;
-typedef struct cairo_pen {
+typedef struct _cairo_pen {
double radius;
double tolerance;
@@ -251,12 +251,47 @@ typedef struct cairo_pen {
int num_vertices;
} cairo_pen_t;
-typedef struct cairo_color cairo_color_t;
-typedef struct cairo_image_surface cairo_image_surface_t;
+typedef struct _cairo_color cairo_color_t;
+typedef struct _cairo_image_surface cairo_image_surface_t;
+
+/* cairo_array.c structures and functions */
+
+typedef struct _cairo_array cairo_array_t;
+struct _cairo_array {
+ int size;
+ int num_elements;
+ int element_size;
+ char *elements;
+};
+
+cairo_private void
+_cairo_array_init (cairo_array_t *array, int element_size);
+
+cairo_private void
+_cairo_array_fini (cairo_array_t *array);
+
+cairo_private cairo_status_t
+_cairo_array_grow_by (cairo_array_t *array, int additional);
+
+cairo_private void
+_cairo_array_truncate (cairo_array_t *array, int length);
+
+cairo_private void *
+_cairo_array_append (cairo_array_t *array,
+ const void *elements, int num_elements);
+
+cairo_private void *
+_cairo_array_index (cairo_array_t *array, int index);
+
+cairo_private void
+_cairo_array_copy_element (cairo_array_t *array, int index, void *dst);
+
+cairo_private int
+_cairo_array_num_elements (cairo_array_t *array);
/* cairo_cache.c structures and functions */
-typedef struct cairo_cache_backend {
+typedef struct _cairo_cache_backend {
unsigned long (*hash) (void *cache,
void *key);
@@ -276,7 +311,6 @@ typedef struct cairo_cache_backend {
} cairo_cache_backend_t;
-
/*
* The cairo_cache system makes the following assumptions about
* entries in its cache:
@@ -312,7 +346,7 @@ typedef struct {
typedef struct {
unsigned long refcount;
const cairo_cache_backend_t *backend;
- cairo_cache_arrangement_t *arrangement;
+ const cairo_cache_arrangement_t *arrangement;
cairo_cache_entry_base_t **entries;
unsigned long max_memory;
@@ -326,23 +360,23 @@ typedef struct {
#endif
} cairo_cache_t;
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_cache_init (cairo_cache_t *cache,
const cairo_cache_backend_t *backend,
unsigned long max_memory);
-extern void __internal_linkage
+cairo_private void
_cairo_cache_reference (cairo_cache_t *cache);
-extern void __internal_linkage
+cairo_private void
_cairo_cache_destroy (cairo_cache_t *cache);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_cache_lookup (cairo_cache_t *cache,
void *key,
void **entry_return);
-extern unsigned long __internal_linkage
+cairo_private unsigned long
_cairo_hash_string (const char *c);
#define CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
@@ -354,25 +388,24 @@ typedef struct {
double matrix[2][2];
} cairo_font_scale_t;
-struct cairo_font_backend;
+struct _cairo_font_backend;
typedef struct {
int refcount;
- const struct cairo_font_backend *backend;
+ const struct _cairo_font_backend *backend;
} cairo_unscaled_font_t;
/*
- * A cairo_font contains a pointer to a cairo_sizeless_font_t and a scale
+ * A cairo_font contains a pointer to a cairo_unscaled_font_t and a scale
* matrix. These are the things the user holds references to.
*/
-struct cairo_font {
+struct _cairo_font {
int refcount;
cairo_font_scale_t scale;
cairo_unscaled_font_t *unscaled;
};
-
/* cairo_font.c is responsible for two global caches:
*
* - font entries: [[[base], name, weight, slant], cairo_unscaled_font_t ]
@@ -397,29 +430,28 @@ typedef struct {
cairo_text_extents_t extents;
} cairo_image_glyph_cache_entry_t;
-extern void __internal_linkage
+cairo_private void
_cairo_lock_global_image_glyph_cache (void);
-extern void __internal_linkage
+cairo_private void
_cairo_unlock_global_image_glyph_cache (void);
-extern cairo_cache_t * __internal_linkage
+cairo_private cairo_cache_t *
_cairo_get_global_image_glyph_cache (void);
/* Some glyph cache functions you can reuse. */
-extern unsigned long __internal_linkage
+cairo_private unsigned long
_cairo_glyph_cache_hash (void *cache, void *key);
-extern int __internal_linkage
+cairo_private int
_cairo_glyph_cache_keys_equal (void *cache,
void *k1,
void *k2);
-
/* the font backend interface */
-typedef struct cairo_font_backend {
+typedef struct _cairo_font_backend {
cairo_unscaled_font_t *(*create) (const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight);
@@ -469,10 +501,19 @@ typedef struct cairo_font_backend {
} cairo_font_backend_t;
/* concrete font backends */
-extern const struct cairo_font_backend cairo_ft_font_backend;
+#ifdef CAIRO_HAS_FT_FONT
+
+extern const cairo_private struct _cairo_font_backend cairo_ft_font_backend;
+
+#endif
+
+#ifdef CAIRO_HAS_ATSUI_FONT
+extern const cairo_private struct _cairo_font_backend cairo_atsui_font_backend;
-typedef struct cairo_surface_backend {
+#endif
+
+typedef struct _cairo_surface_backend {
cairo_surface_t *
(*create_similar) (void *surface,
cairo_format_t format,
@@ -566,19 +607,18 @@ typedef struct cairo_surface_backend {
cairo_font_scale_t *scale,
cairo_operator_t operator,
cairo_surface_t *source,
- cairo_surface_t *surface,
+ void *surface,
int source_x,
int source_y,
const cairo_glyph_t *glyphs,
int num_glyphs);
-
} cairo_surface_backend_t;
-struct cairo_matrix {
+struct _cairo_matrix {
double m[3][2];
};
-typedef struct cairo_format_masks {
+typedef struct _cairo_format_masks {
int bpp;
unsigned long alpha_mask;
unsigned long red_mask;
@@ -586,7 +626,7 @@ typedef struct cairo_format_masks {
unsigned long blue_mask;
} cairo_format_masks_t;
-struct cairo_surface {
+struct _cairo_surface {
const cairo_surface_backend_t *backend;
unsigned int ref_count;
@@ -596,7 +636,7 @@ struct cairo_surface {
int repeat;
};
-struct cairo_image_surface {
+struct _cairo_image_surface {
cairo_surface_t base;
/* libic-specific fields */
@@ -617,7 +657,7 @@ struct cairo_image_surface {
madness). I'm still working on a cleaner API, but in the meantime,
at least this does prevent precision loss in color when changing
alpha. */
-struct cairo_color {
+struct _cairo_color {
double red;
double green;
double blue;
@@ -639,7 +679,7 @@ typedef enum {
CAIRO_PATTERN_RADIAL
} cairo_pattern_type_t;
-typedef struct cairo_color_stop {
+typedef struct _cairo_color_stop {
cairo_fixed_t offset;
cairo_fixed_48_16_t scale;
int id;
@@ -651,7 +691,7 @@ typedef void (*cairo_shader_function_t) (unsigned char *color0,
cairo_fixed_t factor,
int *pixel);
-typedef struct cairo_shader_op {
+typedef struct _cairo_shader_op {
cairo_color_stop_t *stops;
int n_stops;
cairo_fixed_t min_offset;
@@ -660,7 +700,7 @@ typedef struct cairo_shader_op {
cairo_shader_function_t shader_function;
} cairo_shader_op_t;
-struct cairo_pattern {
+struct _cairo_pattern {
unsigned int ref_count;
cairo_extend_t extend;
@@ -696,20 +736,30 @@ struct cairo_pattern {
} u;
};
-typedef struct cairo_traps {
+typedef struct _cairo_traps {
cairo_trapezoid_t *traps;
int num_traps;
int traps_size;
cairo_box_t extents;
} cairo_traps_t;
-#define CAIRO_FONT_FAMILY_DEFAULT "serif"
#define CAIRO_FONT_SLANT_DEFAULT CAIRO_FONT_SLANT_NORMAL
#define CAIRO_FONT_WEIGHT_DEFAULT CAIRO_FONT_WEIGHT_NORMAL
+#ifdef CAIRO_HAS_FT_FONT
+
+#define CAIRO_FONT_FAMILY_DEFAULT "serif"
+
/* XXX: Platform-specific. Other platforms may want a different default */
#define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_font_backend
+#elif defined(CAIRO_HAS_ATSUI_FONT)
+
+#define CAIRO_FONT_FAMILY_DEFAULT "Monaco"
+
+#define CAIRO_FONT_BACKEND_DEFAULT &cairo_atsui_font_backend
+
+#endif
#define CAIRO_GSTATE_OPERATOR_DEFAULT CAIRO_OPERATOR_OVER
#define CAIRO_GSTATE_TOLERANCE_DEFAULT 0.1
@@ -721,7 +771,7 @@ typedef struct cairo_traps {
#define CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT 96.0
/* Need a name distinct from the cairo_clip function */
-typedef struct cairo_clip_rec {
+typedef struct _cairo_clip_rec {
int x;
int y;
int width;
@@ -730,7 +780,7 @@ typedef struct cairo_clip_rec {
cairo_surface_t *surface;
} cairo_clip_rec_t;
-typedef struct cairo_gstate {
+typedef struct _cairo_gstate {
cairo_operator_t operator;
double tolerance;
@@ -767,16 +817,16 @@ typedef struct cairo_gstate {
cairo_pen_t pen_regular;
- struct cairo_gstate *next;
+ struct _cairo_gstate *next;
} cairo_gstate_t;
-struct cairo {
+struct _cairo {
unsigned int ref_count;
cairo_gstate_t *gstate;
cairo_status_t status;
};
-typedef struct cairo_stroke_face {
+typedef struct _cairo_stroke_face {
cairo_point_t ccw;
cairo_point_t point;
cairo_point_t cw;
@@ -785,217 +835,224 @@ typedef struct cairo_stroke_face {
} cairo_stroke_face_t;
/* cairo.c */
-extern void __internal_linkage
+cairo_private void
_cairo_restrict_value (double *value, double min, double max);
/* cairo_fixed.c */
-extern cairo_fixed_t __internal_linkage
+cairo_private cairo_fixed_t
_cairo_fixed_from_int (int i);
-extern cairo_fixed_t
+cairo_private cairo_fixed_t
_cairo_fixed_from_double (double d);
-cairo_fixed_t
+cairo_private cairo_fixed_t
_cairo_fixed_from_26_6 (uint32_t i);
-extern double
+cairo_private double
_cairo_fixed_to_double (cairo_fixed_t f);
-extern int __internal_linkage
+cairo_private int
_cairo_fixed_is_integer (cairo_fixed_t f);
-extern int __internal_linkage
+cairo_private int
_cairo_fixed_integer_part (cairo_fixed_t f);
+cairo_private int
+_cairo_fixed_integer_floor (cairo_fixed_t f);
+
+cairo_private int
+_cairo_fixed_integer_ceil (cairo_fixed_t f);
+
+
/* cairo_gstate.c */
-extern cairo_gstate_t * __internal_linkage
+cairo_private cairo_gstate_t *
_cairo_gstate_create (void);
-extern void __internal_linkage
+cairo_private void
_cairo_gstate_init (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other);
-extern void __internal_linkage
+cairo_private void
_cairo_gstate_fini (cairo_gstate_t *gstate);
-extern void __internal_linkage
+cairo_private void
_cairo_gstate_destroy (cairo_gstate_t *gstate);
-extern cairo_gstate_t * __internal_linkage
+cairo_private cairo_gstate_t *
_cairo_gstate_clone (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_copy (cairo_gstate_t *dest, cairo_gstate_t *src);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_begin_group (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_end_group (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface);
-extern cairo_surface_t * __internal_linkage
+cairo_private cairo_surface_t *
_cairo_gstate_current_target_surface (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern);
-extern cairo_pattern_t *__internal_linkage
+cairo_private cairo_pattern_t *
_cairo_gstate_current_pattern (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator);
-extern cairo_operator_t __internal_linkage
+cairo_private cairo_operator_t
_cairo_gstate_current_operator (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, double blue);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_current_rgb_color (cairo_gstate_t *gstate,
double *red,
double *green,
double *blue);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance);
-extern double __internal_linkage
+cairo_private double
_cairo_gstate_current_tolerance (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_alpha (cairo_gstate_t *gstate, double alpha);
-extern double __internal_linkage
+cairo_private double
_cairo_gstate_current_alpha (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule);
-extern cairo_fill_rule_t __internal_linkage
+cairo_private cairo_fill_rule_t
_cairo_gstate_current_fill_rule (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width);
-extern double __internal_linkage
+cairo_private double
_cairo_gstate_current_line_width (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap);
-extern cairo_line_cap_t __internal_linkage
+cairo_private cairo_line_cap_t
_cairo_gstate_current_line_cap (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join);
-extern cairo_line_join_t __internal_linkage
+cairo_private cairo_line_join_t
_cairo_gstate_current_line_join (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, double offset);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit);
-extern double __internal_linkage
+cairo_private double
_cairo_gstate_current_miter_limit (cairo_gstate_t *gstate);
-extern void __internal_linkage
+cairo_private void
_cairo_gstate_current_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_concat_matrix (cairo_gstate_t *gstate,
cairo_matrix_t *matrix);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
cairo_matrix_t *matrix);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_default_matrix (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_identity_matrix (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_transform_point (cairo_gstate_t *gstate, double *x, double *y);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_inverse_transform_point (cairo_gstate_t *gstate, double *x, double *y);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_new_path (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y);
-extern cairo_status_t __internal_linkage
+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);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_arc (cairo_gstate_t *gstate,
double xc, double yc,
double radius,
double angle1, double angle2);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_arc_negative (cairo_gstate_t *gstate,
double xc, double yc,
double radius,
double angle1, double angle2);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_rel_line_to (cairo_gstate_t *gstate, double dx, double dy);
-extern cairo_status_t __internal_linkage
+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
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_stroke_path (cairo_gstate_t *gstate);
*/
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_close_path (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_current_point (cairo_gstate_t *gstate, double *x, double *y);
-extern cairo_status_t __internal_linkage
+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,
@@ -1003,174 +1060,177 @@ _cairo_gstate_interpret_path (cairo_gstate_t *gstate,
cairo_close_path_func_t *close_path,
void *closure);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_stroke (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_fill (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_copy_page (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_show_page (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
double *x1, double *y1,
double *x2, double *y2);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
double *x1, double *y1,
double *x2, double *y2);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
double x,
double y,
int *inside_ret);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
double x,
double y,
int *inside_ret);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_init_clip (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_clip (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
+_cairo_gstate_restore_external_state (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);
-extern cairo_status_t __internal_linkage
+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);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_scale_font (cairo_gstate_t *gstate,
double scale);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_transform_font (cairo_gstate_t *gstate,
cairo_matrix_t *matrix);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_current_font (cairo_gstate_t *gstate,
cairo_font_t **font);
-extern void __internal_linkage
+cairo_private void
_cairo_gstate_set_font_transform (cairo_gstate_t *gstate,
cairo_matrix_t *matrix);
-extern void __internal_linkage
+cairo_private void
_cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
cairo_matrix_t *matrix);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
cairo_font_extents_t *extents);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_font (cairo_gstate_t *gstate,
cairo_font_t *font);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_text_to_glyphs (cairo_gstate_t *font,
const unsigned char *utf8,
cairo_glyph_t **glyphs,
int *num_glyphs);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
cairo_glyph_t *glyphs,
int num_glyphs);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
cairo_glyph_t *glyphs,
int num_glyphs);
/* cairo_color.c */
-extern void __internal_linkage
+cairo_private void
_cairo_color_init (cairo_color_t *color);
-extern void __internal_linkage
+cairo_private void
_cairo_color_fini (cairo_color_t *color);
-extern void __internal_linkage
+cairo_private void
_cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blue);
-extern void __internal_linkage
+cairo_private void
_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue);
-extern void __internal_linkage
+cairo_private void
_cairo_color_set_alpha (cairo_color_t *color, double alpha);
/* cairo_font.c */
-extern cairo_unscaled_font_t * __internal_linkage
+cairo_private cairo_unscaled_font_t *
_cairo_unscaled_font_create (const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight);
-extern void __internal_linkage
+cairo_private void
_cairo_font_init (cairo_font_t *scaled,
cairo_font_scale_t *scale,
cairo_unscaled_font_t *unscaled);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
- const struct cairo_font_backend *backend);
+ const struct _cairo_font_backend *backend);
-extern void __internal_linkage
+cairo_private void
_cairo_unscaled_font_reference (cairo_unscaled_font_t *font);
-extern void __internal_linkage
+cairo_private void
_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_unscaled_font_font_extents (cairo_unscaled_font_t *font,
cairo_font_scale_t *scale,
cairo_font_extents_t *extents);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_unscaled_font_text_to_glyphs (cairo_unscaled_font_t *font,
cairo_font_scale_t *scale,
const unsigned char *utf8,
cairo_glyph_t **glyphs,
int *num_glyphs);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_unscaled_font_glyph_extents (cairo_unscaled_font_t *font,
cairo_font_scale_t *scale,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_unscaled_font_glyph_bbox (cairo_unscaled_font_t *font,
cairo_font_scale_t *size,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_box_t *bbox);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t *font,
cairo_font_scale_t *size,
cairo_operator_t operator,
@@ -1181,7 +1241,7 @@ _cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t *font,
cairo_glyph_t *glyphs,
int num_glyphs);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_unscaled_font_glyph_path (cairo_unscaled_font_t *font,
cairo_font_scale_t *size,
cairo_glyph_t *glyphs,
@@ -1189,47 +1249,47 @@ _cairo_unscaled_font_glyph_path (cairo_unscaled_font_t *font,
cairo_path_t *path);
/* cairo_hull.c */
-extern cairo_status_t
+cairo_private cairo_status_t
_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices);
/* cairo_path.c */
-extern void __internal_linkage
+cairo_private void
_cairo_path_init (cairo_path_t *path);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other);
-extern void __internal_linkage
+cairo_private void
_cairo_path_fini (cairo_path_t *path);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_move_to (cairo_path_t *path, cairo_point_t *point);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_rel_move_to (cairo_path_t *path, cairo_slope_t *slope);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_line_to (cairo_path_t *path, cairo_point_t *point);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_rel_line_to (cairo_path_t *path, cairo_slope_t *slope);
-extern cairo_status_t __internal_linkage
+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);
-extern cairo_status_t __internal_linkage
+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);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_close_path (cairo_path_t *path);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_current_point (cairo_path_t *path, cairo_point_t *point);
typedef cairo_status_t (cairo_path_move_to_func_t) (void *closure,
@@ -1245,7 +1305,7 @@ typedef cairo_status_t (cairo_path_curve_to_func_t) (void *closure,
typedef cairo_status_t (cairo_path_close_path_func_t) (void *closure);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_interpret (cairo_path_t *path,
cairo_direction_t dir,
cairo_path_move_to_func_t *move_to,
@@ -1254,37 +1314,37 @@ _cairo_path_interpret (cairo_path_t *path,
cairo_path_close_path_func_t *close_path,
void *closure);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2);
/* cairo_path_fill.c */
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps);
/* cairo_path_stroke.c */
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps);
/* cairo_surface.c */
-extern cairo_surface_t * __internal_linkage
+cairo_private cairo_surface_t *
_cairo_surface_create_similar_scratch (cairo_surface_t *other,
cairo_format_t format,
int drawable,
int width,
int height);
-extern cairo_surface_t * __internal_linkage
+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);
-extern void __internal_linkage
+cairo_private void
_cairo_surface_init (cairo_surface_t *surface,
const cairo_surface_backend_t *backend);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_surface_fill_rectangle (cairo_surface_t *surface,
cairo_operator_t operator,
cairo_color_t *color,
@@ -1293,7 +1353,7 @@ _cairo_surface_fill_rectangle (cairo_surface_t *surface,
int width,
int height);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_surface_composite (cairo_operator_t operator,
cairo_surface_t *src,
cairo_surface_t *mask,
@@ -1307,14 +1367,14 @@ _cairo_surface_composite (cairo_operator_t operator,
unsigned int width,
unsigned int height);
-extern cairo_status_t __internal_linkage
+cairo_private 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);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_surface_composite_trapezoids (cairo_operator_t operator,
cairo_surface_t *src,
cairo_surface_t *dst,
@@ -1323,248 +1383,248 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator,
cairo_trapezoid_t *traps,
int ntraps);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_surface_copy_page (cairo_surface_t *surface);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_surface_show_page (cairo_surface_t *surface);
-extern double __internal_linkage
+cairo_private double
_cairo_surface_pixels_per_inch (cairo_surface_t *surface);
-extern cairo_image_surface_t * __internal_linkage
+cairo_private cairo_image_surface_t *
_cairo_surface_get_image (cairo_surface_t *surface);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_surface_set_image (cairo_surface_t *surface,
cairo_image_surface_t *image);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_surface_create_pattern (cairo_surface_t *surface,
cairo_pattern_t *pattern,
cairo_box_t *extents);
/* cairo_image_surface.c */
-extern cairo_image_surface_t * __internal_linkage
+cairo_private cairo_image_surface_t *
_cairo_image_surface_create_with_masks (char *data,
cairo_format_masks_t *format,
int width,
int height,
int stride);
-extern void __internal_linkage
+cairo_private void
_cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_image_surface_set_matrix (cairo_image_surface_t *surface,
cairo_matrix_t *matrix);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_image_surface_set_filter (cairo_image_surface_t *surface,
cairo_filter_t filter);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_image_surface_set_repeat (cairo_image_surface_t *surface,
int repeat);
-extern cairo_int_status_t __internal_linkage
+cairo_private cairo_int_status_t
_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
pixman_region16_t *region);
/* cairo_pen.c */
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pen_init_empty (cairo_pen_t *pen);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other);
-extern void __internal_linkage
+cairo_private void
_cairo_pen_fini (cairo_pen_t *pen);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pen_add_points_for_slopes (cairo_pen_t *pen,
cairo_point_t *a,
cairo_point_t *b,
cairo_point_t *c,
cairo_point_t *d);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
cairo_slope_t *slope,
int *active);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
cairo_slope_t *slope,
int *active);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pen_stroke_spline (cairo_pen_t *pen,
cairo_spline_t *spline,
double tolerance,
cairo_traps_t *traps);
/* cairo_polygon.c */
-extern void __internal_linkage
+cairo_private void
_cairo_polygon_init (cairo_polygon_t *polygon);
-extern void __internal_linkage
+cairo_private void
_cairo_polygon_fini (cairo_polygon_t *polygon);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_point_t *p2);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_polygon_move_to (cairo_polygon_t *polygon, cairo_point_t *point);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_polygon_line_to (cairo_polygon_t *polygon, cairo_point_t *point);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_polygon_close (cairo_polygon_t *polygon);
/* cairo_spline.c */
-extern cairo_int_status_t __internal_linkage
+cairo_private 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);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_spline_decompose (cairo_spline_t *spline, double tolerance);
-extern void __internal_linkage
+cairo_private void
_cairo_spline_fini (cairo_spline_t *spline);
/* cairo_matrix.c */
-extern void __internal_linkage
+cairo_private void
_cairo_matrix_init (cairo_matrix_t *matrix);
-extern void __internal_linkage
+cairo_private void
_cairo_matrix_fini (cairo_matrix_t *matrix);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_matrix_set_translate (cairo_matrix_t *matrix,
double tx, double ty);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_matrix_set_scale (cairo_matrix_t *matrix,
double sx, double sy);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_matrix_set_rotate (cairo_matrix_t *matrix,
double angle);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_matrix_transform_bounding_box (cairo_matrix_t *matrix,
double *x, double *y,
double *width, double *height);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, double *lambda2);
-extern cairo_status_t __internal_linkage
-_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy);
+cairo_private cairo_status_t
+_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy, int x_major);
-extern int __internal_linkage
+cairo_private int
_cairo_matrix_is_integer_translation(cairo_matrix_t *matrix, int *itx, int *ity);
/* cairo_traps.c */
-extern void __internal_linkage
+cairo_private void
_cairo_traps_init (cairo_traps_t *traps);
-extern void __internal_linkage
+cairo_private void
_cairo_traps_fini (cairo_traps_t *traps);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3]);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_traps_tessellate_rectangle (cairo_traps_t *traps, cairo_point_t q[4]);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_traps_tessellate_polygon (cairo_traps_t *traps,
cairo_polygon_t *poly,
cairo_fill_rule_t fill_rule);
-extern int __internal_linkage
+cairo_private int
_cairo_traps_contain (cairo_traps_t *traps, double x, double y);
-extern void __internal_linkage
+cairo_private void
_cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents);
/* cairo_slope.c */
-extern void __internal_linkage
+cairo_private void
_cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b);
-extern int __internal_linkage
+cairo_private int
_cairo_slope_compare (cairo_slope_t *a, cairo_slope_t *b);
-extern int __internal_linkage
+cairo_private int
_cairo_slope_clockwise (cairo_slope_t *a, cairo_slope_t *b);
-extern int __internal_linkage
+cairo_private int
_cairo_slope_counter_clockwise (cairo_slope_t *a, cairo_slope_t *b);
/* cairo_pattern.c */
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_init (cairo_pattern_t *pattern);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other);
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_fini (cairo_pattern_t *pattern);
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_init_solid (cairo_pattern_t *pattern,
double red, double green, double blue);
-extern cairo_pattern_t *__internal_linkage
+cairo_private cairo_pattern_t *
_cairo_pattern_create_solid (double red, double green, double blue);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pattern_get_rgb (cairo_pattern_t *pattern,
double *red, double *green, double *blue);
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha);
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_set_source_offset (cairo_pattern_t *pattern,
double x, double y);
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_transform (cairo_pattern_t *pattern,
cairo_matrix_t *ctm_inverse);
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_prepare_surface (cairo_pattern_t *pattern);
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_shader_init (cairo_pattern_t *pattern,
cairo_shader_op_t *op);
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
cairo_fixed_t factor,
int *pixel);
-extern cairo_image_surface_t *__internal_linkage
+cairo_private cairo_image_surface_t *
_cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box);
/* Avoid unnecessary PLT entries. */