diff options
Diffstat (limited to 'src')
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. */ |