diff options
author | Carl Worth <cworth@cworth.org> | 2006-02-13 16:47:23 -0800 |
---|---|---|
committer | Carl Worth <cworth@cworth.org> | 2006-02-13 16:47:23 -0800 |
commit | 6aff9afc22eb6c5c814992c5ca4b3bd437935d3a (patch) | |
tree | 5d153c0e66fdb2d637beeb3bbf671d319ba9a979 | |
parent | 5de154bcdb659618d723bcec14e0315630c62c7e (diff) | |
parent | 86869f02b9206eaeac331ff8945dacf4d840df98 (diff) |
Remove pixman from SNAPSHOT_0_5_1SNAPSHOT_0_5_1
64 files changed, 3955 insertions, 1671 deletions
diff --git a/CODING_STYLE b/CODING_STYLE new file mode 100644 index 000000000..04fc53c44 --- /dev/null +++ b/CODING_STYLE @@ -0,0 +1,212 @@ +Cairo coding style. + +This document is intended to be a short description of the preferred +coding style for the cairo source code. Good style requires good +taste, which means this can't all be reduced to automated rules, and +there are exceptions. + +We want the code to be easy to understand and maintain, and consistent +style plays an important part in that, even if some of the specific +details seem trivial. If nothing else, this document gives a place to +put consistent answers for issues that would otherwise be arbitrary. + +Most of the guidelines here are demonstrated by examples, (which means +this document is quicker to read than it might appear given its +length). Most of the examples are positive examples that you should +imitate. The few negative examples are clearly marked with a comment +of /* Yuck! */. Please don't submit code to cairo that looks like any +of these. + +Indentation +----------- +Each new level is indented 4 more spaces than the previous level: + + if (condition) + do_something (); + +Spaces or tabs (or a combination) can be used in indentation, but tabs +must always be interpreted as 8 spaces. Code using single tabs for all +indentation (expecting people to interpret tabs as 4 spaces) will not +be accepted in cairo. + +The rationale here is that tabs are used in the code for lining things +up other than indentation, (see the Whitespace section below), and +changing the interpretation of tab from 8 characters will break this. + +Braces +------ +Most of the code in cairo uses bracing in the style of K&R: + + if (condition) { + do_this (); + do_that (); + } else { + do_the_other (); + } + +but some of the code uses an alternate style: + + if (condition) + { + do_this (); + do_that (); + } + else + { + do_the_other (); + } + +and that seems just fine. We won't lay down any strict rule on this +point, (though there should be some local). If you came here hoping to +find some guidance, then use the first form above. + +If all of the substatements of an if statement are single statements, +the optional braces should not usually appear: + + if (condition) + do_this (); + else + do_that (); + +But the braces are mandatory when mixing single statement and compound +statements in the various clauses. For example, do not do this: + + if (condition) { + do_this (); + do_that (); + } else /* Yuck! */ + do_the_other (); + +And of course, there are exceptions for when the code just looks +better with the braces: + + if (condition) { + /* Note that we have to be careful here. */ + do_something_dangerous (with_care); + } + + if (condition && + other_condition && + yet_another) + { + do_something (); + } + +And note that this last example also shows a situation in which the +opening brace really needs to be on its own line. The following looks awful: + + if (condition && + other_condition && + yet_another) { /* Yuck! */ + do_something (); + } + +As we said above, legible code that is easy to understand and maintain +is the goal, not adherence to strict rules. + +Whitespace +---------- +Separate logically distinct chunks with a single newline. This +obviously applies between functions, but also applies within a +function or block and can even be used to good effect within a +structure definition: + + struct _cairo_gstate { + cairo_operator_t operator; + + double tolerance; + + /* stroke style */ + double line_width; + cairo_line_cap_t line_cap; + cairo_line_join_t line_join; + double miter_limit; + + cairo_fill_rule_t fill_rule; + + double *dash; + int num_dashes; + double dash_offset; + + ... + } + +Use a single space before a left parenthesis, except where the +standard will not allow it, (eg. when defining a parameterized macro). + +Don't eliminate whitespace just because things would still fit on one +line. This breaks the expected visual structure of the code making it +much harder to read and understand: + + if (condition) foo (); else bar (); /* Yuck! */ + +As a special case of the bracing and whitespace guidelines, function +definitions should always take the following form: + + void + my_function (argument) + { + do_my_things (); + } + +And function prototypes should similarly have the return type (and +associated specifiers and qualifiers) on a line above the function, so +that the function name is flush left. + +Break up long lines (> ~80 characters) and use whitespace to align +things nicely. For example the arguments in a long list to a function +call should all be aligned with each other: + + align_function_arguments (argument_the_first, + argument_the_second, + argument_the_third); + +And as a special rule, in a function prototype, (as well as in the +definition), whitespace should be inserted between the parameter types +and names so that the names are aligned: + + void + align_parameter_names_in_prototypes (const char *char_star_arg, + int int_arg, + double *double_star_arg, + double double_arg); + +Note that parameters with a * prefix are aligned one character to the +left so that the actual names are aligned. + +Managing nested blocks +---------------------- +Long blocks that are deeply nested make the code very hard to +read. Fortunately such blocks often indicate logically distinct chunks +of functionality that are begging to be split into their own +functions. Please listen to the blocks when they beg. + +In other cases, gratuitous nesting comes about because the primary +functionality gets buried in a nested block rather than living at the +primary level where it belongs. Consider the following: + + foo = malloc (sizeof (foo_t)); + if (foo) { /* Yuck! */ + ... + /* lots of code to initialize foo */ + ... + return SUCCESS; + } + return FAILURE; + +This kind of gratuitous nesting can be avoided by following a pattern +of handling exceptional cases early and returning: + + foo = malloc (sizeof (foo_t)); + if (foo == NULL) + return FAILURE; + + ... + /* lots of code to initialize foo */ + ... + return SUCCESS; + +The return statement is often the best thing to use in a pattern like +this. If it's not available due to additional nesting above which +require some cleanup after the current block, then consider splitting +the current block into a new function before using goto. @@ -1,3 +1,752 @@ +2005-06-20 Carl Worth <cworth@cworth.org> + + * Makefile.am: Force distcheck to enable gtk-doc. + +2005-06-20 Carl Worth <cworth@cworth.org> + + * NEWS: Added notes for snapshot 0.5.1 + + * configure.in: Increment CAIRO_VERSION to 0.5.1 + +2005-06-20 Owen Taylor <otaylor@redhat.com> + + Workaround for https://bugs.freedesktop.org/show_bug.cgi?id=3566 + + * src/cairo-xlib-surface.c: Detect servers with a bug in + repeating surfaces by checking vendor string and version. + + * src/cairo-xlib-surface.c: For such surfaces either fall back to + an implementation with the core protocol or fall back to the image + backend. + + * src/cairo-xlib-surface.c: Save clip rects when setting a + clip region on a surface so that we set the right clip for the + surface's GC if we create it later. + +2005-06-20 Carl Worth <cworth@cworth.org> + + * src/cairo-matrix.c: (_cairo_matrix_is_integer_translation): + Make out parameters optional. Style cleanup. + +2005-06-20 Carl Worth <cworth@cworth.org> + + * src/cairoint.h: + * src/cairo-pattern.c: (_cairo_pattern_is_opaque_solid): Abstract + CAIRO_ALPHA_IS_OPAQUE out for general internal use. + + * src/cairo.c: (cairo_paint_with_alpha): Optimize to defer to + cairo_paint if the alpha value is actually opaque. + +2005-06-20 Carl Worth <cworth@cworth.org> + + * src/cairo.h: + * src/cairo-private.h: + * src/cairo.c: (_cairo_error), (cairo_create): Rip out + cairo_set_error_notfiy function as it is clear that it is not the + right approach. + + * test/.cvsignore: + * test/Makefile.am: + * test/error-notify.c: Remove error-notify test. + +2005-06-17 Carl Worth <cworth@cworth.org> + + * src/cairo-xcb-surface.c (_get_image_surface): Remove references + to repeat and matrix fields that no longer exist. + +2005-06-17 Owen Taylor <otaylor@redhat.com> + + * src/cairo-xcb-surface.c (_get_image_surface) + * src/cairo-xlib-surface.c (_get_image_surface): Fix + width/height typo. + +2005-06-17 Kristian Høgsberg <krh@redhat.com> + + * src/cairo-glitz-surface.c: (_cairo_glitz_surface_get_image): + * src/cairo-pattern.c: (cairo_pattern_create_for_surface): + * src/cairo-pdf-surface.c: (_cairo_pdf_surface_composite_pdf): + * src/cairo-surface.c: (_cairo_surface_init): + * src/cairo-xlib-surface.c: (_get_image_surface): + * src/cairoint.h: Remove matrix, filter and repeat from the + cairo_surface_t struct. + +2005-06-17 Carl Worth <cworth@cworth.org> + + * src/cairo.c: (cairo_reference), (cairo_destroy): cairo_reference + and cairo_destroy shouldn't behave differently when cr->status + indicates an error. Fix this bug that just slipped back in. + + * src/cairo.c: (cairo_restore): Remove useless conditional return + at the end of a void function. + + * src/cairo.c: (cairo_get_source), (cairo_get_font_face), + (cairo_text_extents), (cairo_show_text), (cairo_text_path): + Fix so that after calling _cairo_error the most that any cairo + entry function ever does is return a previously computed value. + +2005-06-17 Kristian Høgsberg <krh@redhat.com> + + * TODO: Remove the path clipping entry from the list. + +2005-06-16 Carl Worth <cworth@cworth.org> + + * src/cairo-private.h: Reorder fields of cairo_private_t to match + initialization order. + + * src/cairo.c: (_cairo_error): Call error_notify callback if set. + (cairo_create): Initialize error_notify callback to NULL. + (cairo_set_error_notify): New function to allow the user to set + an error notify callback. + + * src/cairo.h: New cairo_set_error_notify prototye. + + * test/.cvsignore: + * test/Makefile.am: + * test/error-notify.c: (toggle_status), (do_test), (main): New + test for cairo_set_error_notify. + +2005-06-15 Carl Worth <cworth@cworth.org> + + * TODO: Add CAIRO_STATUS_DESTROYED to TODO list. + + * ROADMAP: Note progress on consistent error handling. + + * src/cairo-surface.c: Fix typo in documentation comment for + _cairo_surface_get_current_clip_serial. + +2005-06-15 Owen Taylor <otaylor@redhat.com> + + * doc/public/Makefile.am (MKTMPL_OPTIONS): Remove --only-section-tmpl; + it doesn't really work currently :-(. + +2005-06-15 Owen Taylor <otaylor@redhat.com> + + * src/cairo-gstate.c (_cairo_gstate_clip_and_composite_trapezoids): + Use a clip region when rendering a non-solid pattern through + a rectangular path ... trapezoid rasterization is just too slow + to use that path when we aren't forced to do so. + +2005-06-15 Carl Worth <cworth@cworth.org> + + * test/cairo-test.c: Track removal of cairo_status_string. + (cairo_test_for_target): And add missing parenthesis. + +2005-06-15 Carl Worth <cworth@cworth.org> + + * TODO: Add cairo_finish to TODO list. Note that + cairo_satus_string has now been removed. + +2005-06-15 Carl Worth <cworth@cworth.org> + + * src/cairo.h: + * src/cairo.c: Remove cairo_status_string function which can now + be replaced by: + + cairo_status_to_string (cairo_status (cr)); + + This allows consistent handling of status values for things like + cairo_pattern_status where there is now + cairo_pattern_status_string function. + +2005-06-13 Carl Worth <cworth@cworth.org> + + * src/cairo.c: (_cairo_error): Add _cairo_error so we have a + single function which all errors can pass through. This allows the + user to set a breakpoint on error and will allow us to augment + error handling later as necessary. + + * src/cairo.c: (cairo_create), (cairo_reference), + (cairo_destroy), (cairo_save), (cairo_restore), + (cairo_set_operator), (cairo_set_source_rgb), + (cairo_set_source_rgba), (cairo_set_source_surface), + (cairo_set_source), (cairo_get_source), (cairo_set_tolerance), + (cairo_set_fill_rule), (cairo_set_line_width), + (cairo_set_line_cap), (cairo_set_line_join), (cairo_set_dash), + (cairo_set_miter_limit), (cairo_translate), (cairo_scale), + (cairo_rotate), (cairo_transform), (cairo_set_matrix), + (cairo_identity_matrix), (cairo_user_to_device), + (cairo_user_to_device_distance), (cairo_device_to_user), + (cairo_device_to_user_distance), (cairo_new_path), (cairo_move_to), + (cairo_line_to), (cairo_curve_to), (cairo_arc), + (cairo_arc_negative), (cairo_rel_move_to), (cairo_rel_line_to), + (cairo_rel_curve_to), (cairo_rectangle), (cairo_close_path), + (cairo_paint), (cairo_paint_with_alpha), (cairo_mask), + (cairo_mask_surface), (cairo_stroke_preserve), + (cairo_fill_preserve), (cairo_copy_page), (cairo_show_page), + (cairo_in_stroke), (cairo_in_fill), (cairo_stroke_extents), + (cairo_fill_extents), (cairo_clip_preserve), (cairo_reset_clip), + (cairo_select_font_face), (cairo_get_font_face), + (cairo_font_extents), (cairo_set_font_face), (cairo_set_font_size), + (cairo_set_font_matrix), (cairo_get_font_matrix), + (cairo_text_extents), (cairo_glyph_extents), (cairo_show_text), + (cairo_show_glyphs), (cairo_text_path), (cairo_glyph_path), + (cairo_get_operator), (cairo_get_tolerance), + (cairo_get_current_point), (cairo_get_fill_rule), + (cairo_get_line_width), (cairo_get_line_cap), + (cairo_get_line_join), (cairo_get_miter_limit), (cairo_get_matrix), + (cairo_get_target), (cairo_copy_path), (cairo_copy_path_flat), + (cairo_append_path), (cairo_status): Make all assignements to + cr->status go through the new _cairo_error function. Remove + CAIRO_CHECK_SANITY macro. + +2005-06-15 Carl Worth <cworth@cworth.org> + + * doc/public/cairo-sections.txt: Remove cairo-atsui section since + cairo-atsui.h is currently empty. + Add cairo_path_data_type_t and cairo_path_data_t. + + * test/.cvsignore: Add pdf-clip and pdf-clip.pdf. + +2005-06-14 Kristian Høgsberg <krh@redhat.com> + + * src/cairo-gstate-private.h: + * src/cairo-gstate.c: (_cairo_gstate_init), + (_cairo_gstate_init_copy), (_cairo_gstate_fini), + (_cairo_gstate_set_clip), (_composite_trap_region), + (_cairo_gstate_fill), (_cairo_gstate_reset_clip), + (_cairo_gstate_intersect_clip_path), (_cairo_clip_path_reference), + (_cairo_clip_path_destroy), (_cairo_gstate_intersect_clip_region), + (_cairo_gstate_intersect_clip_mask), (_cairo_gstate_clip): + * src/cairo-pdf-surface.c: + (_cairo_pdf_surface_create_for_document), + (_cairo_pdf_path_move_to), (_cairo_pdf_path_line_to), + (_cairo_pdf_path_close_path), (_cairo_pdf_surface_fill_path), + (_cairo_pdf_surface_intersect_clip_path), + (_cairo_pdf_document_add_page): + * src/cairo-surface.c: (_cairo_surface_get_clip_mode), + (_cairo_surface_fill_path), (_cairo_surface_reset_clip), + (_cairo_surface_set_clip_path_recursive), + (_cairo_surface_set_clip_path): + * src/cairoint.h: Implement path clipping and refactor + _cairo_gstate_clip() out in three different functions + corresponding to the three different clipping modes. + + * src/cairo-glitz-surface.c: + * src/cairo-ps-surface.c: + * src/cairo-win32-surface.c: + * src/cairo-xcb-surface.c: + * src/cairo-xlib-surface.c: + * src/cairo-image-surface.c: + * src/cairo-quartz-surface.c: Add NULL pointers for + intersect_clip_path. + + * test/Makefile.am: + * test/pdf-clip.c: New test case to exercise PDF clipping code. + +2005-06-14 Carl Worth <cworth@cworth.org> + + * src/cairo-glitz-surface.c: (_cairo_glitz_surface_create_similar), + (_cairo_glitz_surface_clone_similar), + (_cairo_glitz_pattern_acquire_surface), + (_cairo_glitz_surface_composite_trapezoids): + * src/cairo-image-surface.c: (_cairo_image_surface_create_similar): + * src/cairo-pdf-surface.c: (_cairo_pdf_surface_create_similar): + * src/cairo-ps-surface.c: (_cairo_ps_surface_create_similar): + * src/cairo-quartz-surface.c: + (_cairo_quartz_surface_create_similar): + * src/cairo-surface.c: (_cairo_surface_create_similar_scratch), + (_cairo_surface_create_similar_solid): + * src/cairo-win32-surface.c: (_cairo_win32_surface_create_similar), + (_cairo_win32_surface_get_subimage): + * src/cairo-xcb-surface.c: (_cairo_xcb_surface_create_similar), + (_cairo_xcb_surface_clone_similar): + * src/cairo-xlib-surface.c: (_cairo_xlib_surface_create_similar), + (_cairo_xlib_surface_clone_similar): + * src/cairoint.h: Remove Boolean 'drawable' parameter from the + create_similar surface backend function since nothing anywhere is + actually using this parameter. + +2005-06-14 T Rowley <tim.rowley@gmail.com> + + * src/cairo-win32-font.c: Correct extents for text with a general + tranform. + +2005-06-14 Carl Worth <cworth@cworth.org> + + * src/cairo.h: Remove comment suggesting ambiguity of whether + cairo_get_target references the surface, (we decided as part of + the API shakeup that cairo functions returning pointers to + internal objects do not automatically take a reference). + +2005-06-13 Carl Worth <cworth@cworth.org> + + * src/cairoint.h: + * src/cairo-pattern.c: (_cairo_pattern_create_in_error): Add new + _cairo_pattern_create_in_error. + + * src/cairo.c: (cairo_get_source): Propagate error values from + cr->status to pattern->status. + +2005-06-13 Carl Worth <cworth@cworth.org> + + * src/cairo.c (_cairo_set_source_solid), + (cairo_set_source_surface), (cairo_mask_surface): No longer need + to check for NULL after creating a pattern. + + * src/cairo.c (cairo_set_source), (cairo_mask): Propagate status + errors from pattern->status to cr->status. + + Originally 2005-05-08 Owen Taylor <otaylor@redhat.com>: + + * src/cairo-pattern.c src/cairoint.h: If allocation of pattern + objects fails, return special static nil pattern objects. + + * src/cairo-pattern.c: If adding a color stop fails to allocate + memory, set pattern->status. (And fix a memory leak.) Make public + functions return when pattern->status is set, (and no longer + return a cairo_status_t). + + * src/cairo-pattern.c src/cairo.h doc/public/cairo-sections.txt: + Add cairo_pattern_status() + + * src/cairo-gstate.c: Check the status of gstate->source and + of mask patterns passed in. + +2005-06-13 Carl Worth <cworth@cworth.org> + + Originally 2005-05-08 Owen Taylor <otaylor@redhat.com>: + + * src/cairo.c (cairo_create): If cairo_create() fails, return + a special static object, cairo_nil. + + * src/cairo.c (cairo_reference): Don't return early if + cr->status is set. cr->status should not affect reference + counting. + + * src/cairo.c: (cairo_reference), (cairo_destroy): Ignore any + magic object with a reference count of -1. + +2005-06-13 Carl Worth <cworth@cworth.org> + + Originally 2005-06-02 Carl Worth <cworth@cworth.org>: + + * src/cairo.h: Add a status field to cairo_path_t. + + * src/cairo.c: + (cairo_copy_path), (cairo_copy_path_flat): Add documentation for + the new approach for handling errors in these functions---always + returning a valid pointer with at least a status. + (cairo_append_path): Propagate path status errors to the + context. Add note to documentation on initializing path->status. + + * src/cairo-path-data-private.h: Add missing cairo_private + qualifier to a couple functions. + + * src/cairo-path-data.c: (_cairo_path_data_create_real): Track new + status field in cairo_path_t. + (cairo_path_destroy): Don't destroy cairo_path_nil. Add + documentation. + (_cairo_path_data_create): + (_cairo_path_data_create_flat): + (_cairo_path_data_append_to_context): Add documentation. + (_cairo_path_data_create_in_error): New function to create a + placeholder cairo_path_t just to propagate a cairo_status_t error. + +2005-06-11 Carl Worth <cworth@cworth.org> + + * src/cairoint.h: + * src/cairo-gstate.c: (_cairo_gstate_init, + _cairo_gstate_init_copy, _cairo_gstate_fini): Make these functions + static, which allows slightly less awkward error handling within + them. + +2005-06-10 Carl Worth <cworth@cworth.org> + + * src/cairoint.h: Provide font-backend-specific macros for + FONT_FAMILY_DEFAULT. Change CAIRO_FT_FONT_FAMILY_DEFAULT from + "serif" to "" to allow the actual default to come from the + system/user configuration. + +2005-06-10 Carl Worth <cworth@cworth.org> + + * src/cairo.h: Pull the enum out from inside cairo_path_data_t and + give it a name of cairo_path_data_type_t. This allows C++ programs + to see the enum values. It also allows variables to be declared of + this type for manually constructing a cairo_path_t. + +2005-06-10 Carl Worth <cworth@cworth.org> + + * ROADMAP: Add 'consistent error handling' to 1.0 roadmap. (This + isn't new, we just forgot to list it here before). + + * TODO: Big cleanup to remove finished items. Also, split the file + up to separate TODO items that affect the API from items that do + not. + +2005-06-10 Carl Worth <cworth@cworth.org> + + Originally: 2005-06-09 Carl Worth <cworth@cworth.org> + + * src/cairo-pdf-surface.c: (_cairo_pdf_surface_show_page): + * src/cairo-xcb-surface.c: + (_cairo_xcb_surface_acquire_source_image), + (_cairo_xcb_surface_acquire_dest_image): + * src/cairo-xlib-surface.c: + (_cairo_xlib_surface_acquire_source_image), + (_cairo_xlib_surface_acquire_dest_image): Rework occurrences + of 'if (status == CAIRO_STATUS_SUCCESS)' to use 'if (status)' + instead where trivial. + +2005-06-10 Carl Worth <cworth@cworth.org> + + * src/cairoint.h: + * src/cairo-font.c: + * src/cairo-ft-font.c: + * src/cairo-glitz-surface.c: + * src/cairo-gstate.c: + * src/cairo-image-surface.c: + * src/cairo-pattern.c: + * src/cairo-pdf-surface.c: + * src/cairo-png.c: + * src/cairo-surface.c: + * src/cairo-win32-font.c: + * src/cairo-win32-surface.c: + * src/cairo-xcb-surface.c: + * src/cairo-xlib-surface.c: Remove STATUS_OK macro which was not + being used universally. + +2005-06-09 Carl Worth <cworth@cworth.org> + + * src/cairo.h: Remove trailing comma from enum values which gcc + 4.0 does not want to see (Luis Villa). Closes bug #3502. + +2005-06-09 Owen Taylor <otaylor@redhat.com> + + * test/Makefile.am (INCLUDES): Add + -I$(top_builddir)/src for cairo-features.h (Tomasz Cholewo) + +2005-06-07 Keith Packard <keithp@keithp.com> + + * src/cairo-pdf-surface.c: (_cairo_pdf_surface_show_glyphs): + Font matrix was output incorrectly; the implicit mirror-in-y + transformation was not computed correctly, missing a negation + of the 'xy' component. + +2005-06-02 Kristian Høgsberg <krh@redhat.com> + + * src/cairo-gstate.c (_cairo_gstate_clip): When clipping, update + the clip surface to a new surface the size of the intersection of + the old clip surface and the extents of the new clip path. + +2005-06-03 Carl Worth <cworth@cworth.org> + + * src/cairo-font.c: (cairo_font_face_reference), + (cairo_font_face_destroy), (_cairo_simple_font_face_destroy), + (_cairo_unscaled_font_reference), (_cairo_unscaled_font_destroy), + (cairo_scaled_font_reference), (cairo_scaled_font_destroy): + * src/cairo-ft-font.c: (_ft_font_cache_destroy_cache), + (_cairo_ft_unscaled_font_destroy), (_ft_font_face_destroy): + * src/cairo-glitz-surface.c: (_cairo_glitz_area_destroy): + * src/cairo-path-data.c: (cairo_path_destroy): + * src/cairo-pdf-surface.c: (cairo_pdf_font_destroy), + (cairo_pdf_ft_font_destroy): + * src/cairo-win32-font.c: (_cairo_win32_scaled_font_destroy): + Allow NULL as a valid value for several objects. That is, calling + reference or destroy on these objects will simply do nothing, + successfully. + + * src/cairo-atsui-font.c: (_cairo_atsui_font_destroy_font): Remove + extra whitespace. + +2005-06-03 Carl Worth <cworth@cworth.org> + + * src/cairoint.h: + * src/cairo-cache.c: (_cairo_cache_init), (_cairo_cache_destroy): + Remove unused cache->refcount and _cairo_cache_reference(). + + * src/cairo-cache.c: (_cairo_cache_destroy): Remove gratuitous + nesting as recommended in CODING_STYLE. + +2005-06-03 Carl Worth <cworth@cworth.org> + + * src/cairoint.h: + * src/cairo-array.c: (_cairo_user_data_array_fini): + * src/cairo-font.c: (cairo_font_face_destroy): + * src/cairo-surface.c: (cairo_surface_destroy): Fix name of + _cairo_user_data_array_destroy to be _cairo_user_data_array_fini. + +2005-06-03 Carl Worth <cworth@cworth.org> + + * src/cairo-glitz-surface.c: + (_cairo_glitz_glyph_cache_create_entry), + (_cairo_glitz_glyph_cache_destroy_entry), + (_cairo_glitz_glyph_cache_destroy_cache), + (_cairo_glitz_surface_show_glyphs): Rename functions to match the + naming scheme used by cairo-cache.c and all other users of + it. Though it's quite likely that glitz had this right and now + everything could be changed to match it instead. I'll save that + for some day when we're cleaning up the cache code. + +2005-06-03 Carl Worth <cworth@cworth.org> + + * CODING_STYLE: Fix spelling errors. + +2005-06-03 Carl Worth <cworth@cworth.org> + + * CODING_STYLE: Fix Freudian unwrapped line in paragraph + describing why long lines should be wrapped. + +2005-06-03 Carl Worth <cworth@cworth.org> + + * CODING_STYLE: Add CODING_STYLE document to standardize on some + style issues. + + * src/cairo-atsui-font.c: + * src/cairo-cache.c: + * src/cairo-ft-font.c: + * src/cairo-glitz-surface.c: + * src/cairo-gstate.c: + * src/cairo-matrix.c: + * src/cairo-pattern.c: + * src/cairo-pdf-surface.c: + * src/cairo-spline.c: + * src/cairo-wideint.c: + * src/cairo-win32-font.c: + * src/cairo-xlib-surface.c: Standardize brace handling around all + else clauses according to new CODING_STYLE guidelines. + +2005-06-03 Kristian Høgsberg <krh@redhat.com> + + Patch from Tomasz Cholewo <cholewo@ieee-cis.org>: + + * src/cairo-pdf-surface.c: (cairo_pdf_ft_font_write_head_table), + (cairo_pdf_ft_font_generate): Store the index of the checksum + instead of a pointer to the location. + +2005-06-03 Carl Worth <cworth@cworth.org> + + * src/cairoint.h: + * src/cairo-gstate.c: + * src/cairo.c: (_cairo_set_source_solid), (cairo_set_source_rgb), + (cairo_set_source_rgba): Move internal convenience up from + _cairo_gstate_set_source_solid to _cairo_set_source_solid so that + all set_source functions flow through cairo_set_source. + +2005-06-01 Carl Worth <cworth@cworth.org> + + * src/cairo-gstate.c: (_cairo_gstate_init): Remove obsolete + _cairo_gstate_set_target_surface, folding its contents into + _cairo_gstate_init, most of which disappears due to constant + folding. Ensure that gstate->next is initialized even if + _cairo_pattern_create_solid fails. + + * src/cairo-xcb-surface.c: Remove unused + _cairo_xcb_surface_set_clip_region. + +2005-06-01 Carl Worth <cworth@cworth.org> + + * src/cairoint.h: + * src/cairo-font.c: + * src/cairo-ft-font.c: + * src/cairo-glitz-surface.c: + * src/cairo-gstate.c: + * src/cairo-image-surface.c: + * src/cairo-pattern.c: + * src/cairo-pdf-surface.c: + * src/cairo-png.c: + * src/cairo-surface.c: + * src/cairo-win32-font.c: + * src/cairo-win32-surface.c: + * src/cairo-xcb-surface.c: + * src/cairo-xlib-surface.c: Rename CAIRO_OK to STATUS_OK. No + intended changes in functionality. + +2005-06-01 Carl Worth <cworth@cworth.org> + + * src/cairo-gstate-private.h: + * src/cairo-gstate.c: Rename gstate->surface to gstate->target. No + intended changes in functionality. + +2005-06-01 Carl Worth <cworth@cworth.org> + + * src/cairo-gstate-private.h: + * src/cairo-gstate.c: (_cairo_gstate_init): Remove unused fields + from cairo_gstate_t, (font_family, font_slant, + font_weight). Reorder fields to match between declaration and + initialization and to put the most problematic fields (surface and + source) at the end. No intended changes in functionality. + +2005-06-01 Carl Worth <cworth@cworth.org> + + * test/Makefile.am (XFAIL_TESTS): Add self-intersecting to the + list of expected failures. + +2005-06-01 Carl Worth <cworth@cworth.org> + + * test/.cvsignore: + * test/Makefile.am: + * test/self-intersecting-ref.png: + * test/self-intersecting.c: (draw), (main): Add self-intersecting + test which demonstrates the long-standing bug with stroking + self-intersecting paths. + +2005-06-01 Carl Worth <cworth@cworth.org> + + * src/cairo-gstate.c (_cairo_gstate_get_clip_extents): Fix bug in + converting box to rectangle that left clip_rect.height + uninitialized, (leading to unpredictable, intermittent test + failures). + +2005-05-31 Carl Worth <cworth@cworth.org> + + * src/cairo.h: + * src/cairo.c: (cairo_status_to_string), (cairo_status_string): + Add new function cairo_status_to_string an reimplement + cairo_status_string in terms of the new function. + +2005-05-27 Olivier Andrieu <oliv__a@users.sourceforge.net> + + * src/cairo-path-data.c (_cpdc_curve_to_flatten), + (_cpdp_curve_to_flatten) : Fix memory leak + +2005-05-26 Keith Packard <keithp@keithp.com> + + reviewed by: krh, otaylor, cworth + + Replace nesting-only surface clipping with gstate contained + serial-number tracked clipping sets that are loaded into the surface + on demand just before each rendering operation. This permits + multiple cairo_t contexts to reference a surface without + regard to ordering of operations among the contexts. + + Also in this patch is a change to the xlib surface that + creates two separate Pictures, one for source and one for + destination operands which separates the source clipping + from destination clipping. Cairo now specifies that sources + are never clipped by any clipping applied to them as destinations. + + * src/cairoint.h: + * src/cairo-gstate-private.h: + Move cairo_clip_t (renamed from cairo_clip_rec_t) from cairoint.h + to cairo-gstate-private.h. Eliminate stack of clip state + from surfaces. Add new surface clipping API. + + * src/cairo-gstate.c: (_cairo_gstate_init), + (_cairo_gstate_init_copy), (_cairo_gstate_fini), + (_cairo_gstate_has_surface_clip), (_cairo_gstate_set_clip), + (_cairo_gstate_get_clip_extents), + (_cairo_gstate_set_target_surface), (_cairo_gstate_paint), + (_cairo_gstate_combine_clip_surface), + (_cairo_gstate_intersect_clip), (_get_mask_extents), + (_cairo_gstate_mask), (_cairo_gstate_stroke), + (_clip_and_compute_extents_arbitrary), (_composite_trap_region), + (_cairo_gstate_fill), (_cairo_gstate_reset_clip), + (_cairo_gstate_clip), (_cairo_gstate_show_glyphs): + Manage clip objects entirely within the gstate, loading + the whole thing into the surface just before drawing. + + * src/cairo-pattern.c: + (_cairo_pattern_acquire_surface_for_gradient), + (_cairo_pattern_acquire_surface_for_solid), + (_cairo_pattern_acquire_surface_for_surface), + (_cairo_pattern_acquire_surface), (_cairo_pattern_release_surface): + Source surfaces need not have clipping modified as the + surface interface now specifies that source surfaces are always + unclipped. + + * src/cairo-surface.c: (_cairo_surface_init), + (cairo_surface_finish), (_cairo_surface_clone_similar), + (_cairo_surface_get_current_clip_serial), + (_cairo_surface_allocate_clip_serial), (_cairo_surface_reset_clip), + (_cairo_surface_can_clip_region), (_cairo_surface_set_clip_region), + (_cairo_surface_can_clip_path), (_cairo_surface_clip_path), + (_cairo_surface_get_extents): + Eliminate nested clipping contexts, leaving clip management + entirely to the gstate. Create new clip API for the gstate + which uses per-surface serial numbers to match gstate clipping + against current surface clipping values. + + Surfaces no longer track clipping regions at all, so the + old _cairo_surface_get_clip_extents has been replaced with + _cairo_surface_get_extents. For PDF/PS surfaces, this + function is expected to return a rectangle covering the + entire fixed point coordinate space to leave rendering + unclipped by the surface. + + * src/cairo-xcb-surface.c: + Region clipping capability is now signalled by a non-NULL + function pointer in set_clip_region. + + * src/cairo-xlib-surface.c: (_cairo_xlib_surface_finish), + (_cairo_xlib_surface_ensure_src_picture), + (_cairo_xlib_surface_ensure_dst_picture), + (_cairo_xlib_surface_set_matrix), (_cairo_xlib_surface_set_filter), + (_cairo_xlib_surface_set_repeat), + (_cairo_xlib_surface_set_attributes), + (_cairo_xlib_surface_composite), + (_cairo_xlib_surface_fill_rectangles), + (_cairo_xlib_surface_composite_trapezoids), + (_cairo_xlib_surface_set_clip_region), + (_cairo_xlib_surface_create_internal), + (_cairo_xlib_surface_show_glyphs32), + (_cairo_xlib_surface_show_glyphs16), + (_cairo_xlib_surface_show_glyphs8), + (_cairo_xlib_surface_show_glyphs): + Each surface now contains two Pictures, one for source + and one for destination operands so that source operands + are never clipped by destination clipping. + + * src/cairo.h: + * src/cairo.c: (cairo_status_string): + CAIRO_STATUS_BAD_NESTING removed + + * test/Makefile.am: + * test/self-copy.c: (main): + self-copy now passes (Xlib only, until libpixman changes land) + +2005-05-26 Olivier Andrieu <oliv__a@users.sourceforge.net> + + * src/cairo.c: trivial doc fixes. + +2005-05-24 Carl Worth <cworth@cworth.org> + + * gtk-doc.make: Re-synch with latest from gtk-doc CVS tree. + + * doc/public/Makefile.am (MKTMPL_OPTIONS): Add --only-section-tmpl + option so that changes to inline documentation does not lead to + churn in the .sgml template files. + + * doc/public/tmpl/cairo-font.sgml: + * doc/public/tmpl/cairo-ft.sgml: + * doc/public/tmpl/cairo-glitz.sgml: + * doc/public/tmpl/cairo-matrix.sgml: + * doc/public/tmpl/cairo-pattern.sgml: + * doc/public/tmpl/cairo-pdf.sgml: + * doc/public/tmpl/cairo-png.sgml: + * doc/public/tmpl/cairo-ps.sgml: + * doc/public/tmpl/cairo-quartz.sgml: + * doc/public/tmpl/cairo-surface.sgml: + * doc/public/tmpl/cairo-xcb.sgml: + * doc/public/tmpl/cairo-xlib.sgml: + * doc/public/tmpl/cairo.sgml: Commit new templates now that + gtk-doc has ripped all the inline portions out. + + * doc/public/tmpl/cairo-win32.sgml: + * doc/public/tmpl/cairo-xcb-xrender.sgml: + * doc/public/tmpl/cairo-xlib-xrender.sgml: New template files + added for new sections. + + * doc/public/cairo-sections.txt: Update to match current API. + + * src/cairo-xcb.h: Make parameter names match those in the .c file + and its documentation. + +2005-05-22 Carl Worth <cworth@cworth.org> + + * src/cairo.c (cairo_create): Protect less-than and greater-than + symbols in documentation string. + + * TODO: Not that a patch has been submitted for consistent error + handling. + + * src/cairo.c: Fix documentation string for cairo_create so that + it might actualyl appear in the manual. + +2005-05-18 Carl Worth <cworth@cworth.org> + + * configure.in: Add -head to CAIRO_VERSION after tagging with + SNAPSHOT_0_5_0. + 2005-05-17 Carl Worth <cworth@cworth.org> * PORTING_GUIDE: Added porting guide to help with transition to diff --git a/Makefile.am b/Makefile.am index 60ae80514..31aea9118 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,6 +9,8 @@ EXTRA_DIST = \ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = cairo.pc +DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc + # Some custom targets to make it easier to release things. # Use either: # make release-check @@ -1,3 +1,105 @@ +Snapshot 0.5.1 (2005-06-20 Carl Worth <cworth@cworth.org>) +========================================================== +API changes +----------- +* Removed cairo_status_string(cairo_t*) and add + cairo_status_to_string(cairo_status_t) in its place. Code using + cairo_status_string can be ported forward as follows: + + cairo_status (cr); + -> + cairo_status_to_string (cairo_status (cr)); + +* Removed the BAD_NESTING restriction which means that two different + cairo_t objects can now interleave drawing to the same + cairo_surface_t without causing an error. + +* The following functions which previously had a return type of + cairo_status_t now have a return type of void: + + cairo_pattern_add_color_stop_rgba + cairo_pattern_set_matrix + cairo_pattern_get_matrix + cairo_pattern_set_extend + cairo_pattern_set_filter + + See discussion of cairo_pattern_status below for more details. + +API additions +------------- +* Improved error handling: + + cairo_status_t + cairo_pattern_status (cairo_pattern_t *pattern); + + This snapshot expands the status-based error handling scheme from + cairo_t to cairo_path_t and cairo_pattern_t. It also expands the + scheme so that object-creating functions, (cairo_create, + cairo_pattern_create_*, cairo_copy_path_*), are now guaranteed to + not return NULL. Instead, in the case of out-of-memory these + functions will return a static object with + status==CAIRO_STATUS_NO_MEMORY. The status can be checked with the + functions cairo_status and cairo_pattern_status, or by direct + inspection of the new status field in cairo_path_t. + + Please note that some objects, including cairo_surface_t and all of + the font-related objects have not been converted to this + error-handling scheme. + +* In addition to the above changes, a new private function has been added: + + _cairo_error + + This function can be used to set a breakpoint in a debugger to make + it easier to find programming error in cairo-using code. (Currently, + _cairo_error is called when any error is detected within a cairo_t + context, but is not called for non-cairo_t errors such as for + cairo_path_t and cairo_pattern_t). + +* Fixed cairo_path_data_t so that its enum is visible to C++ code, (as + cairo_path_data_type_t). + +Performance improvements +------------------------ +* Made a minor performance improvement for clipping, (restrict clip + surface to the new intersected bounds). + +* Optimize rendering of a solid source pattern with a pixel-aligned + rectangular path to use backend clipping rather than rasterization + and backend compositing. + +* Optimize cairo_paint_with_alpha to defer to cairo_paint when alpha + is 1.0. + +Bug fixes +--------- +* Fixed memory leak in cairo_copy_path. + +* A build fix for non-srcdir builds. + +PDF backend fixes +----------------- +* New support for path-based clipping. + +* Fix for text rotated to angles other than multiples of π/2. + +Win32 backend fixes +------------------- +* Fix for text extents. + +Xlib backend +------------ +* Implemented a complex workaround for X server bug[*] related to + Render-based compositing with untransformed, repeating source + pictures. The workaround uses core Xlib when possible for + performance, (ie. with CAIRO_OPERATOR_SOURCE or CAIRO_OPERATOR_OVER + with an opaque source surface), and falls back to the pixman + image-based compositing otherwise. + + [*] https://bugs.freedesktop.org/show_bug.cgi?id=3566 + +* Various bug fixes, particularly in the fallback paths. + Snapshot 0.5.0 (2005-05-17 Carl Worth <cworth@cworth.org>) ========================================================== This is a pretty big, and fairly significant snapshot. It represents @@ -69,6 +69,12 @@ API Issues (more detail in TODO file) of them. Status: not started, there is a rough plan in TODO + A9. consistent error handling for all objects + Difficulty: Easy to implement to get the API right. Hard to test. + Status: Done for cairo_t, cairo_path_t, and cairo_pattern_t. + Still need to do cairo_font_face_t, + cairo_scaled_font_t, and cairo_surface_t. + Performance work ---------------- ✓P1. Make pixel-aligned rectangle compositing fast @@ -1,56 +1,84 @@ -API Shakeup planning --------------------- +Changes that are expected to impact the public API +================================================== + Patch submitted to mailing list? / Documentation included in patch? |/ Review of patch completed? ||/ Test case included? |||/ Committed. ||||/ -New functionality (more-or-less) --------------------------------- +Backwards compatible (API additions only) +----------------------------------------- cairo_begin_group, cairo_end_group, cairo_get_group - cairo_<device>_surface_mark_dirty - Consistent error handling for all objects - -Somewhat backwards-compatible changes ------------------------------------ -PDRTC user data (was Re: [cairo] Patch improving fallbacks) -PDRTC setters and getters -PDRTC cairo_output_stream_t and cairo_surface_finish() -PDRTC cairo_current_path -> cairo_copy_path_data + cairo_surface_mark_dirty (see below for details) + Add support for non-antialiased rendering. API ? + Add CAIRO_FILL_RULE_INVERSE_WINDING and CAIRO_FILL_RULE_INVERSE_EVEN_ODD + Add cairo_text_glyphs (see below for details) + Add support for programmatic patterns, (ie. arbitrary gradients) + Add cairo_arc_to. + Add support for custom caps (see below for details) + Add support for getting at image data from image surface + Add CAIRO_STATUS_DESTROYED + Add cairo_finish + +Backwards incompatible (API deletions or changes) +------------------------------------------------- PDR C cairo_surface_finish, cairo_surface_flush -PDRTC Abbreviation hunt: cairo_init_clip and cairo_concat_matrix -PDRTC Renaming the terms of the rendering equation -PDRTC default matrix -PDRTC cairo_paint -PDRTC Making set_source consistent -PDRTC cairo_stroke_path -> cairo_stroke_to_path -PDRTC cairo_current_matrix -PDRTC cairo_mask -PDRTC cairo_fill_preserve, cairo_stroke_preserve, cairo_clip_preserve PDR C A hidden offset for the xlib backend +P Consistent error handling for all objects + Split cairo_format_t (see below for details) +P---C Remove cairo_status_string in favor of cairo_status_to_string -Backwards incompatible ----------------------- -PDRTC Simplifying the operator set -PDRTC cairo_create and eliminating cairo_set_target_surface -PDRTC Eliminating cairo_copy -PDRTC Eliminating cairo_surface_set_repeat/matrix/filter -PDRTC Eliminating cairo_show_surface +Details on some of the above changes +------------------------------------ +* cairo_surface_mark_dirty -* Add support for non-antialiased rendering. API ? + One question is what the function should accept. A single + device-space rectangle seems like a consistent approach. That would + allow us to avoid needing backend-specific functions with + backend-specific region datatypes, (cf. clipping support) -* Clean up the cache code a bit, (there is at least one redundant - level of cacheing, and there are some minor style issues). + In order to get the intended efficiency benefits, we'll need to make + two changes: -* Add CAIRO_FILL_RULE_INVERSE_WINDING and CAIRO_FILL_RULE_INVERSE_EVEN_ODD + 1) In the fallback code, never fetch any data from the clean + region. -* Fix clipping to work for all operators. The equation we have come up - with is: + 2) Mark clean any region drawn with device-pixel aligned + rectangles, (cairo_paint with no clip is the most iportant + one here). - ((src Op dest) In clip) Add (dest Out clip) +* cairo_text_glyphs: + + It would function as a sort of bridge between the toy and the + real text APIs: + + > void + > cairo_text_glyphs (cairo_t *cr, const unsigned char *utf8, + > cairo_glyph_t *glyphs, int *num_glyphs); + > + > with num_glyphs as an input-output parameter. The behavior of this + > function would be such that calling: + > + > cairo_text_glyphs (cr, string, glyphs, &num_glyphs); + > cairo_show_glyphs (cr, glyphs, num_glyphs); + > + > would be equivalent too: + > + > cairo_show_text (cr, string); + > + > as long as the original size of glyphs/num_glyphs was large + > enough. + +* support for custom caps: + + It would be nice if the user had a mechanism to reliably draw custom + caps. One approach here would be to provide the coordinates of the + butt cap faces so that the user can append seamless caps to the + current path. We may also need to provide the coordinates of the + faces of every dash as well. -* Split cairo_format_t into two things: +* split cairo_format_t into two things: - An enumeration that determines the "capabilities" of a surface - A vs. ARGB. vs. RGB @@ -82,92 +110,32 @@ PDRTC Eliminating cairo_show_surface people are going to screw up and pass CAIRO_FORMAT_RGB into that, and if it "just worked" that would save people trouble....) -* Clean up the API in preparation for freezing and release. +Changes that do not affect the public API +========================================= +* Clean up the cache code a bit, (there is at least one redundant + level of cacheing, and there are some minor style issues). -* Make a more interesting PS backend, (other than the current -"giant-image for every page" approach). +* Fix clipping to work for all operators. The equation we have come up + with is: + + ((src Op dest) In clip) Add (dest Out clip) -* Figure out what to do with DPI for image/png backends. +* Make a more interesting PS backend, (other than the current + "giant-image for every page" approach). * Change stroke code to go through one giant polygon. This will fix -problems with stroking self-intersecting paths. - -* Re-work the backend clipping interface to use geometry rather than -images. + problems with stroking self-intersecting paths. * Fix the intersection problem, (see reference to Hobby's paper -mentioned in cairo_traps.c). - -* Add a new cairo_text_glyphs function (a sort of bridge between the -toy and the real text API): - - > void - > cairo_text_glyphs (cairo_t *cr, const unsigned char *utf8, - > cairo_glyph_t *glyphs, int *num_glyphs); - > - > with num_glyphs as an input-output parameter. The behavior of this - > function would be such that calling: - > - > cairo_text_glyphs (cr, string, glyphs, &num_glyphs); - > cairo_show_glyphs (cr, glyphs, num_glyphs); - > - > would be equivalent too: - > - > cairo_show_text (cr, string); - > - > as long as the original size of glyphs/num_glyphs was large - > enough. + mentioned in cairo_traps.c). * Implement dashing for cairo_curve_to. -* Implement support for programmatic patterns, (ie. figure out how to -do gradients the Right Way). - -* Implement cairo_arc_to. - * Stroking closed, degenerate paths should still draw caps. Round caps are easy; square should probably draw an axis-aligned square. -* It would be nice if the user had a mechanism to reliably draw custom - caps. One approach here would be to provide the coordinates of the - butt cap faces so that the user can append seamless caps to the - current path. We may also need to provide the coordinates of the - faces of every dash as well. - * Should add geometry pruning as appropriate. -* We need a way to get at the image data after something - like cairo_surface_create_similar with the image backend. - -* Three suggestions from Owen that will help GTK+ performance: - - - The ability have an additional rectangle-list clip in the - Xlib surface. Frequently during an expose event, GTK+ is - drawing L shaped areas - - XXXXXX - X..... - X..... - - And passing the real clip to the server is going to save - a lot of pixel operations that will be thrown away. - - - The ability to pass in a width/height to cairo_xlib_surface_create() - to avoid a round-trip. (Round-trips are bad to the point where - querying the the server is something you don't want to do in - production software) - - - More of a future thing, the ability to hint to to cairo that - the contents of the Xlib surface passed to - cairo_xlib_surface_create() are a solid fill ... this is - very much the normal case for GTK+ usage and allows for - big optimization in the no-RENDER case. - (see http://mail.gnome.org/archives/gtk-devel-list/2003-March/msg00045.html - * Verification, profiling, optimization. centi_unfinished.svg may provide a good test case. - -* Implement copy-on-write regions in pixman as a more complete - solution than the BAD_NESTING stuff to Owen's "Clip region problems" - thread. diff --git a/configure.in b/configure.in index 070b0ef64..c2305de50 100644 --- a/configure.in +++ b/configure.in @@ -5,7 +5,7 @@ AC_INIT(src/cairo.h) dnl =========================================================================== # Package version number, (as distinct from shared library version) -CAIRO_VERSION=0.5.0 +CAIRO_VERSION=0.5.1 # libtool shared library version diff --git a/doc/public/.cvsignore b/doc/public/.cvsignore index 35479d5e3..ff4418d10 100644 --- a/doc/public/.cvsignore +++ b/doc/public/.cvsignore @@ -3,6 +3,7 @@ Makefile Makefile.in cairo-decl-list.txt cairo-decl.txt +cairo-docs.sgml cairo-undocumented.txt cairo-unused.txt cairo.hierarchy @@ -13,3 +14,5 @@ cairo.signals html xml + + diff --git a/doc/public/Makefile.am b/doc/public/Makefile.am index f058d36aa..9e4c10365 100644 --- a/doc/public/Makefile.am +++ b/doc/public/Makefile.am @@ -38,6 +38,9 @@ GTKDOC_LIBS = # Extra options to supply to gtkdoc-mkdb MKDB_OPTIONS=--sgml-mode --output-format=xml +# Extra options to supply to gtkdoc-mktmpl +MKTMPL_OPTIONS= + # Non-autogenerated SGML files to be included in $(DOC_MAIN_SGML_FILE) content_files = \ language-bindings.xml diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt index b462436b8..4db600b2a 100644 --- a/doc/public/cairo-sections.txt +++ b/doc/public/cairo-sections.txt @@ -1,10 +1,4 @@ <SECTION> -<FILE>cairo-atsui</FILE> -<TITLE>ATSUI Fonts</TITLE> -cairo_atsui_font_create -</SECTION> - -<SECTION> <FILE>cairo-ft</FILE> <TITLE>FreeType Fonts</TITLE> cairo_ft_font_face_create_for_pattern @@ -23,7 +17,8 @@ cairo_glitz_surface_create <FILE>cairo-pdf</FILE> <TITLE>PDF Backend</TITLE> cairo_pdf_surface_create -cairo_pdf_surface_create_for_callback +cairo_pdf_surface_create_for_stream +cairo_pdf_surface_set_dpi </SECTION> <SECTION> @@ -39,6 +34,8 @@ cairo_surface_write_to_png_stream <FILE>cairo-ps</FILE> <TITLE>PS Backend</TITLE> cairo_ps_surface_create +cairo_ps_surface_create_for_stream +cairo_ps_surface_set_dpi </SECTION> <SECTION> @@ -61,30 +58,38 @@ cairo_win32_scaled_font_get_metrics_factor <FILE>cairo-xcb</FILE> <TITLE>XCB Backend</TITLE> cairo_xcb_surface_create +cairo_xcb_surface_create_for_bitmap +cairo_xcb_surface_set_size +</SECTION> + +<SECTION> +<FILE>cairo-xcb-xrender</FILE> +<TITLE>XCB Backend</TITLE> +cairo_xcb_surface_create_with_xrender_format </SECTION> <SECTION> <FILE>cairo-xlib</FILE> <TITLE>XLib Backend</TITLE> cairo_xlib_surface_create -cairo_xlib_surface_create_with_visual +cairo_xlib_surface_create_for_bitmap cairo_xlib_surface_set_size </SECTION> <SECTION> +<FILE>cairo-xlib-xrender</FILE> +<TITLE>XLib/Xrender Backend</TITLE> +cairo_xlib_surface_create_with_xrender_format +</SECTION> + +<SECTION> <FILE>cairo-surface</FILE> <TITLE>cairo_surface_t</TITLE> cairo_surface_t -cairo_surface_create_for_image cairo_surface_create_similar cairo_surface_reference cairo_surface_destroy cairo_surface_finish -cairo_surface_set_repeat -cairo_surface_set_matrix -cairo_surface_get_matrix -cairo_surface_set_filter -cairo_surface_get_filter cairo_surface_set_user_data cairo_surface_get_user_data cairo_surface_set_device_offset @@ -99,6 +104,7 @@ cairo_pattern_create_linear cairo_pattern_create_radial cairo_pattern_reference cairo_pattern_destroy +cairo_pattern_status cairo_pattern_add_color_stop_rgb cairo_pattern_add_color_stop_rgba cairo_pattern_set_matrix @@ -108,8 +114,6 @@ cairo_pattern_set_extend cairo_pattern_get_extend cairo_pattern_set_filter cairo_pattern_get_filter -<SUBSECTION Private> -cairo_pattern_add_color_stop </SECTION> <SECTION> @@ -128,13 +132,6 @@ cairo_matrix_invert cairo_matrix_multiply cairo_matrix_transform_distance cairo_matrix_transform_point -<SUBSECTION Private> -cairo_matrix_create -cairo_matrix_destroy -cairo_matrix_copy -cairo_matrix_set_identity -cairo_matrix_set_affine -cairo_matrix_get_affine </SECTION> <SECTION> @@ -164,7 +161,6 @@ cairo_reference cairo_destroy cairo_save cairo_restore -cairo_copy cairo_format_t cairo_operator_t cairo_set_operator @@ -172,7 +168,6 @@ cairo_set_source_rgb cairo_set_source_rgba cairo_set_source cairo_set_source_surface -cairo_set_alpha cairo_set_tolerance cairo_fill_rule_t cairo_set_fill_rule @@ -188,7 +183,6 @@ cairo_scale cairo_rotate cairo_transform cairo_set_matrix -cairo_default_matrix cairo_identity_matrix cairo_user_to_device cairo_user_to_device_distance @@ -239,7 +233,6 @@ cairo_text_extents cairo_glyph_extents cairo_text_path cairo_glyph_path -cairo_show_surface cairo_get_operator cairo_get_source cairo_get_tolerance @@ -251,16 +244,19 @@ cairo_get_line_join cairo_get_miter_limit cairo_get_matrix cairo_get_target -cairo_get_path -cairo_get_path_flat cairo_copy_path cairo_copy_path_flat cairo_append_path +cairo_path_data_type_t +cairo_path_data_t cairo_path_t cairo_path_destroy cairo_status_t cairo_status cairo_status_string +cairo_status_to_string +cairo_error_notify_func_t +cairo_set_error_notify cairo_filter_t cairo_image_surface_create cairo_image_surface_create_for_data @@ -273,7 +269,8 @@ cairo_write_func_t <SUBSECTION Private> CAIRO_BEGIN_DECLS CAIRO_END_DECLS -cairo_concat_matrix +cairo_current_font_extents +cairo_get_font_extents cairo_current_operator cairo_current_tolerance cairo_current_point @@ -284,20 +281,54 @@ cairo_current_line_join cairo_current_miter_limit cairo_current_matrix cairo_current_target_surface -cairo_current_path -cairo_current_path_flat -cairo_current_font_extents -cairo_init_clip -cairo_inverse_transform_point -cairo_inverse_transform_distance +cairo_get_status +cairo_get_status_string +cairo_concat_matrix cairo_scale_font cairo_select_font -cairo_set_pattern -cairo_set_rgb_color cairo_transform_font -cairo_get_font_extents -cairo_get_status -cairo_get_status_string cairo_transform_point cairo_transform_distance +cairo_inverse_transform_point +cairo_inverse_transform_distance +cairo_init_clip +cairo_surface_create_for_image +cairo_default_matrix +cairo_matrix_set_affine +cairo_matrix_set_identity +cairo_pattern_add_color_stop +cairo_set_rgb_color +cairo_set_pattern +cairo_xlib_surface_create_for_pixmap_with_visual +cairo_xlib_surface_create_for_window_with_visual +cairo_xcb_surface_create_for_pixmap_with_visual +cairo_xcb_surface_create_for_window_with_visual +cairo_current_path +cairo_current_path_flat +cairo_get_path +cairo_get_path_flat +cairo_set_alpha +cairo_show_surface +cairo_copy +cairo_surface_set_repeat +cairo_surface_set_matrix +cairo_surface_get_matrix +cairo_surface_set_filter +cairo_surface_get_filter +cairo_matrix_create +cairo_matrix_destroy +cairo_matrix_copy +cairo_matrix_set_identity +cairo_matrix_set_affine +cairo_matrix_get_affine +cairo_set_target_surface +cairo_set_target_glitz +cairo_set_target_image +cairo_set_target_pdf +cairo_set_target_png +cairo_set_target_ps +cairo_set_target_quartz +cairo_set_target_win32 +cairo_set_target_xcb +cairo_set_target_drawable </SECTION> diff --git a/doc/public/tmpl/cairo-atsui.sgml b/doc/public/tmpl/cairo-atsui.sgml index a47ee8c68..4a8b35aaf 100644 --- a/doc/public/tmpl/cairo-atsui.sgml +++ b/doc/public/tmpl/cairo-atsui.sgml @@ -17,12 +17,3 @@ ATSUI Fonts <!-- ##### SECTION Stability_Level ##### --> -<!-- ##### FUNCTION cairo_atsui_font_create ##### --> -<para> - -</para> - -@style: -@Returns: - - diff --git a/doc/public/tmpl/cairo-font.sgml b/doc/public/tmpl/cairo-font.sgml index 66502930e..d6c7043d2 100644 --- a/doc/public/tmpl/cairo-font.sgml +++ b/doc/public/tmpl/cairo-font.sgml @@ -84,8 +84,6 @@ Font Handling </para> @scaled_font: -<!-- # Unused Parameters # --> -@font: <!-- ##### FUNCTION cairo_scaled_font_destroy ##### --> @@ -94,8 +92,6 @@ Font Handling </para> @scaled_font: -<!-- # Unused Parameters # --> -@font: <!-- ##### STRUCT cairo_font_extents_t ##### --> @@ -117,8 +113,6 @@ Font Handling @scaled_font: @extents: @Returns: -<!-- # Unused Parameters # --> -@font: <!-- ##### STRUCT cairo_text_extents_t ##### --> @@ -142,7 +136,5 @@ Font Handling @glyphs: @num_glyphs: @extents: -<!-- # Unused Parameters # --> -@font: diff --git a/doc/public/tmpl/cairo-matrix.sgml b/doc/public/tmpl/cairo-matrix.sgml index c58abe488..d9549b4a6 100644 --- a/doc/public/tmpl/cairo-matrix.sgml +++ b/doc/public/tmpl/cairo-matrix.sgml @@ -65,14 +65,6 @@ cairo_matrix_t @yy: @x0: @y0: -<!-- # Unused Parameters # --> -@Param7: -@a: -@b: -@c: -@d: -@tx: -@ty: <!-- ##### FUNCTION cairo_matrix_init_identity ##### --> @@ -120,8 +112,6 @@ cairo_matrix_t @matrix: @tx: @ty: -<!-- # Unused Parameters # --> -@Returns: <!-- ##### FUNCTION cairo_matrix_scale ##### --> @@ -132,8 +122,6 @@ cairo_matrix_t @matrix: @sx: @sy: -<!-- # Unused Parameters # --> -@Returns: <!-- ##### FUNCTION cairo_matrix_rotate ##### --> @@ -143,8 +131,6 @@ cairo_matrix_t @matrix: @radians: -<!-- # Unused Parameters # --> -@Returns: <!-- ##### FUNCTION cairo_matrix_invert ##### --> @@ -164,8 +150,6 @@ cairo_matrix_t @result: @a: @b: -<!-- # Unused Parameters # --> -@Returns: <!-- ##### FUNCTION cairo_matrix_transform_distance ##### --> @@ -176,25 +160,15 @@ cairo_matrix_t @matrix: @dx: @dy: -<!-- # Unused Parameters # --> -@Returns: <!-- ##### FUNCTION cairo_matrix_transform_point ##### --> <para> + </para> @matrix: @x: @y: -<!-- # Unused Parameters # --> -@Returns: - -<!-- -Local variables: -mode: sgml -sgml-parent-document: ("../cairo-docs.xml" "book" "refsect2" "") -End: ---> diff --git a/doc/public/tmpl/cairo-pattern.sgml b/doc/public/tmpl/cairo-pattern.sgml index 30deec9b8..dadd7870c 100644 --- a/doc/public/tmpl/cairo-pattern.sgml +++ b/doc/public/tmpl/cairo-pattern.sgml @@ -74,6 +74,15 @@ cairo_pattern_t @pattern: +<!-- ##### FUNCTION cairo_pattern_status ##### --> +<para> + +</para> + +@pattern: +@Returns: + + <!-- ##### FUNCTION cairo_pattern_add_color_stop_rgb ##### --> <para> @@ -84,7 +93,6 @@ cairo_pattern_t @red: @green: @blue: -@Returns: <!-- ##### FUNCTION cairo_pattern_add_color_stop_rgba ##### --> @@ -98,7 +106,6 @@ cairo_pattern_t @green: @blue: @alpha: -@Returns: <!-- ##### FUNCTION cairo_pattern_set_matrix ##### --> @@ -108,7 +115,6 @@ cairo_pattern_t @pattern: @matrix: -@Returns: <!-- ##### FUNCTION cairo_pattern_get_matrix ##### --> @@ -118,6 +124,7 @@ cairo_pattern_t @pattern: @matrix: +<!-- # Unused Parameters # --> @Returns: @@ -137,7 +144,6 @@ cairo_pattern_t @pattern: @extend: -@Returns: <!-- ##### FUNCTION cairo_pattern_get_extend ##### --> @@ -156,7 +162,6 @@ cairo_pattern_t @pattern: @filter: -@Returns: <!-- ##### FUNCTION cairo_pattern_get_filter ##### --> diff --git a/doc/public/tmpl/cairo-pdf.sgml b/doc/public/tmpl/cairo-pdf.sgml index 8ff0ea17e..d29ed0e26 100644 --- a/doc/public/tmpl/cairo-pdf.sgml +++ b/doc/public/tmpl/cairo-pdf.sgml @@ -22,31 +22,31 @@ PDF Backend </para> -@fp: -@width_inches: -@height_inches: -@x_pixels_per_inch: -@y_pixels_per_inch: +@filename: +@width_in_points: +@height_in_points: @Returns: -<!-- # Unused Parameters # --> -@write_func: -@destroy_closure_func: -@closure: -@file: -<!-- ##### FUNCTION cairo_pdf_surface_create_for_callback ##### --> +<!-- ##### FUNCTION cairo_pdf_surface_create_for_stream ##### --> <para> </para> @write_func: -@destroy_closure_func: @closure: -@width_inches: -@height_inches: -@x_pixels_per_inch: -@y_pixels_per_inch: +@width_in_points: +@height_in_points: @Returns: +<!-- ##### FUNCTION cairo_pdf_surface_set_dpi ##### --> +<para> + +</para> + +@surface: +@x_dpi: +@y_dpi: + + diff --git a/doc/public/tmpl/cairo-ps.sgml b/doc/public/tmpl/cairo-ps.sgml index 4cb4a0268..4c5e8b37b 100644 --- a/doc/public/tmpl/cairo-ps.sgml +++ b/doc/public/tmpl/cairo-ps.sgml @@ -22,11 +22,31 @@ PS Backend </para> -@file: -@width_inches: -@height_inches: -@x_pixels_per_inch: -@y_pixels_per_inch: +@filename: +@width_in_points: +@height_in_points: @Returns: +<!-- ##### FUNCTION cairo_ps_surface_create_for_stream ##### --> +<para> + +</para> + +@write_func: +@closure: +@width_in_points: +@height_in_points: +@Returns: + + +<!-- ##### FUNCTION cairo_ps_surface_set_dpi ##### --> +<para> + +</para> + +@surface: +@x_dpi: +@y_dpi: + + diff --git a/doc/public/tmpl/cairo-surface.sgml b/doc/public/tmpl/cairo-surface.sgml index e92935a6c..fab1306f6 100644 --- a/doc/public/tmpl/cairo-surface.sgml +++ b/doc/public/tmpl/cairo-surface.sgml @@ -23,20 +23,6 @@ cairo_surface_t </para> -<!-- ##### MACRO cairo_surface_create_for_image ##### --> -<para> - -</para> - -@Returns: -<!-- # Unused Parameters # --> -@data: -@format: -@width: -@height: -@stride: - - <!-- ##### FUNCTION cairo_surface_create_similar ##### --> <para> @@ -74,60 +60,6 @@ cairo_surface_t @Returns: -<!-- ##### MACRO cairo_surface_set_repeat ##### --> -<para> - -</para> - -@Returns: -<!-- # Unused Parameters # --> -@surface: -@repeat: - - -<!-- ##### MACRO cairo_surface_set_matrix ##### --> -<para> - -</para> - -@Returns: -<!-- # Unused Parameters # --> -@surface: -@matrix: - - -<!-- ##### MACRO cairo_surface_get_matrix ##### --> -<para> - -</para> - -@Returns: -<!-- # Unused Parameters # --> -@surface: -@matrix: - - -<!-- ##### MACRO cairo_surface_set_filter ##### --> -<para> - -</para> - -@Returns: -<!-- # Unused Parameters # --> -@surface: -@filter: - - -<!-- ##### MACRO cairo_surface_get_filter ##### --> -<para> - -</para> - -@Returns: -<!-- # Unused Parameters # --> -@surface: - - <!-- ##### FUNCTION cairo_surface_set_user_data ##### --> <para> @@ -138,8 +70,6 @@ cairo_surface_t @user_data: @destroy: @Returns: -<!-- # Unused Parameters # --> -@data: <!-- ##### FUNCTION cairo_surface_get_user_data ##### --> diff --git a/doc/public/tmpl/cairo-win32.sgml b/doc/public/tmpl/cairo-win32.sgml new file mode 100644 index 000000000..4976ea064 --- /dev/null +++ b/doc/public/tmpl/cairo-win32.sgml @@ -0,0 +1,64 @@ +<!-- ##### SECTION Title ##### --> +Microsoft Windows Backend + +<!-- ##### SECTION Short_Description ##### --> + + +<!-- ##### SECTION Long_Description ##### --> +<para> + +</para> + +<!-- ##### SECTION See_Also ##### --> +<para> + +</para> + +<!-- ##### SECTION Stability_Level ##### --> + + +<!-- ##### FUNCTION cairo_win32_surface_create ##### --> +<para> + +</para> + +@hdc: +@Returns: + + +<!-- ##### FUNCTION cairo_win32_font_face_create_for_logfontw ##### --> +<para> + +</para> + +@logfont: +@Returns: + + +<!-- ##### FUNCTION cairo_win32_scaled_font_select_font ##### --> +<para> + +</para> + +@scaled_font: +@hdc: +@Returns: + + +<!-- ##### FUNCTION cairo_win32_scaled_font_done_font ##### --> +<para> + +</para> + +@scaled_font: + + +<!-- ##### FUNCTION cairo_win32_scaled_font_get_metrics_factor ##### --> +<para> + +</para> + +@scaled_font: +@Returns: + + diff --git a/doc/public/tmpl/cairo-xcb-xrender.sgml b/doc/public/tmpl/cairo-xcb-xrender.sgml new file mode 100644 index 000000000..892967ec0 --- /dev/null +++ b/doc/public/tmpl/cairo-xcb-xrender.sgml @@ -0,0 +1,32 @@ +<!-- ##### SECTION Title ##### --> +XCB Backend + +<!-- ##### SECTION Short_Description ##### --> + + +<!-- ##### SECTION Long_Description ##### --> +<para> + +</para> + +<!-- ##### SECTION See_Also ##### --> +<para> + +</para> + +<!-- ##### SECTION Stability_Level ##### --> + + +<!-- ##### FUNCTION cairo_xcb_surface_create_with_xrender_format ##### --> +<para> + +</para> + +@c: +@drawable: +@format: +@width: +@height: +@Returns: + + diff --git a/doc/public/tmpl/cairo-xcb.sgml b/doc/public/tmpl/cairo-xcb.sgml index 416d71638..a58912c75 100644 --- a/doc/public/tmpl/cairo-xcb.sgml +++ b/doc/public/tmpl/cairo-xcb.sgml @@ -22,10 +22,33 @@ XCB Backend </para> -@dpy: +@c: @drawable: @visual: -@format: +@width: +@height: @Returns: +<!-- ##### FUNCTION cairo_xcb_surface_create_for_bitmap ##### --> +<para> + +</para> + +@c: +@bitmap: +@width: +@height: +@Returns: + + +<!-- ##### FUNCTION cairo_xcb_surface_set_size ##### --> +<para> + +</para> + +@surface: +@width: +@height: + + diff --git a/doc/public/tmpl/cairo-xlib-xrender.sgml b/doc/public/tmpl/cairo-xlib-xrender.sgml new file mode 100644 index 000000000..4ceab1968 --- /dev/null +++ b/doc/public/tmpl/cairo-xlib-xrender.sgml @@ -0,0 +1,32 @@ +<!-- ##### SECTION Title ##### --> +XLib/Xrender Backend + +<!-- ##### SECTION Short_Description ##### --> + + +<!-- ##### SECTION Long_Description ##### --> +<para> + +</para> + +<!-- ##### SECTION See_Also ##### --> +<para> + +</para> + +<!-- ##### SECTION Stability_Level ##### --> + + +<!-- ##### FUNCTION cairo_xlib_surface_create_with_xrender_format ##### --> +<para> + +</para> + +@dpy: +@drawable: +@format: +@width: +@height: +@Returns: + + diff --git a/doc/public/tmpl/cairo-xlib.sgml b/doc/public/tmpl/cairo-xlib.sgml index 30282b226..ae8bb785c 100644 --- a/doc/public/tmpl/cairo-xlib.sgml +++ b/doc/public/tmpl/cairo-xlib.sgml @@ -24,21 +24,21 @@ XLib Backend @dpy: @drawable: -@format: -@Returns: -<!-- # Unused Parameters # --> @visual: -@colormap: +@width: +@height: +@Returns: -<!-- ##### FUNCTION cairo_xlib_surface_create_with_visual ##### --> +<!-- ##### FUNCTION cairo_xlib_surface_create_for_bitmap ##### --> <para> </para> @dpy: -@drawable: -@visual: +@bitmap: +@width: +@height: @Returns: diff --git a/doc/public/tmpl/cairo.sgml b/doc/public/tmpl/cairo.sgml index 06a5fba6d..992ace500 100644 --- a/doc/public/tmpl/cairo.sgml +++ b/doc/public/tmpl/cairo.sgml @@ -74,16 +74,6 @@ Drawing contexts. @cr: -<!-- ##### MACRO cairo_copy ##### --> -<para> - -</para> - -<!-- # Unused Parameters # --> -@dest: -@src: - - <!-- ##### ENUM cairo_format_t ##### --> <para> @@ -153,8 +143,6 @@ Drawing contexts. @cr: @source: -<!-- # Unused Parameters # --> -@pattern: <!-- ##### FUNCTION cairo_set_source_surface ##### --> @@ -168,16 +156,6 @@ Drawing contexts. @y: -<!-- ##### MACRO cairo_set_alpha ##### --> -<para> - -</para> - -<!-- # Unused Parameters # --> -@cr: -@alpha: - - <!-- ##### FUNCTION cairo_set_tolerance ##### --> <para> @@ -316,15 +294,6 @@ Drawing contexts. @matrix: -<!-- ##### MACRO cairo_default_matrix ##### --> -<para> - -</para> - -<!-- # Unused Parameters # --> -@cr: - - <!-- ##### FUNCTION cairo_identity_matrix ##### --> <para> @@ -718,7 +687,6 @@ Drawing contexts. @cr: @matrix: -@Returns: <!-- ##### FUNCTION cairo_show_text ##### --> @@ -756,10 +724,6 @@ Drawing contexts. @cr: @extents: -<!-- # Unused Parameters # --> -@font: -@Returns: -@font_matrix: <!-- ##### FUNCTION cairo_set_font_face ##### --> @@ -811,18 +775,6 @@ Drawing contexts. @num_glyphs: -<!-- ##### MACRO cairo_show_surface ##### --> -<para> - -</para> - -<!-- # Unused Parameters # --> -@cr: -@surface: -@width: -@height: - - <!-- ##### FUNCTION cairo_get_operator ##### --> <para> @@ -925,33 +877,6 @@ Drawing contexts. @Returns: -<!-- ##### MACRO cairo_get_path ##### --> -<para> - -</para> - -<!-- # Unused Parameters # --> -@cr: -@move_to: -@line_to: -@curve_to: -@close_path: -@closure: - - -<!-- ##### MACRO cairo_get_path_flat ##### --> -<para> - -</para> - -<!-- # Unused Parameters # --> -@cr: -@move_to: -@line_to: -@close_path: -@closure: - - <!-- ##### FUNCTION cairo_copy_path ##### --> <para> @@ -979,11 +904,22 @@ Drawing contexts. @path: +<!-- ##### ENUM cairo_path_data_type_t ##### --> +<para> + +</para> + +@CAIRO_PATH_MOVE_TO: +@CAIRO_PATH_LINE_TO: +@CAIRO_PATH_CURVE_TO: +@CAIRO_PATH_CLOSE_PATH: + <!-- ##### STRUCT cairo_path_t ##### --> <para> </para> +@status: @data: @num_data: @@ -1014,7 +950,7 @@ Drawing contexts. @CAIRO_STATUS_WRITE_ERROR: @CAIRO_STATUS_SURFACE_FINISHED: @CAIRO_STATUS_SURFACE_TYPE_MISMATCH: -@CAIRO_STATUS_BAD_NESTING: +@CAIRO_STATUS_PATTERN_TYPE_MISMATCH: <!-- ##### FUNCTION cairo_status ##### --> <para> @@ -1025,12 +961,19 @@ Drawing contexts. @Returns: -<!-- ##### FUNCTION cairo_status_string ##### --> +<!-- ##### MACRO cairo_status_string ##### --> <para> </para> -@cr: + + +<!-- ##### FUNCTION cairo_status_to_string ##### --> +<para> + +</para> + +@status: @Returns: @@ -1070,15 +1013,6 @@ Drawing contexts. @Returns: - -<!-- -Local variables: -mode: sgml -sgml-parent-document: ("../cairo-docs.xml" "book" "refsect2" "") -End: ---> - - <!-- ##### FUNCTION cairo_image_surface_get_width ##### --> <para> diff --git a/gtk-doc.make b/gtk-doc.make index 18c60c2d7..91cdd34d2 100644 --- a/gtk-doc.make +++ b/gtk-doc.make @@ -1,9 +1,3 @@ -# -# *** NOTE *** this file is checked into CVS for convenience only. -# DO NOT EDIT. Rather get changes into upstream gtk-doc and then -# update this version from the gtk-doc version. -# - # -*- mode: makefile -*- #################################### @@ -31,7 +25,6 @@ EXTRA_DIST = \ $(content_files) \ $(HTML_IMAGES) \ $(DOC_MAIN_SGML_FILE) \ - $(DOC_MODULE).types \ $(DOC_MODULE)-sections.txt \ $(DOC_MODULE)-overrides.txt @@ -55,7 +48,7 @@ all-local: html-build.stamp scan-build.stamp: $(HFILE_GLOB) $(CFILE_GLOB) @echo '*** Scanning header files ***' @-chmod -R u+w $(srcdir) - if grep -l '^..*$$' $(srcdir)/$(DOC_MODULE).types > /dev/null ; then \ + if grep -l '^..*$$' $(srcdir)/$(DOC_MODULE).types > /dev/null 2>&1 ; then \ CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" CFLAGS="$(GTKDOC_CFLAGS)" LDFLAGS="$(GTKDOC_LIBS)" gtkdoc-scangobj $(SCANGOBJ_OPTIONS) --module=$(DOC_MODULE) --output-dir=$(srcdir) ; \ else \ cd $(srcdir) ; \ @@ -75,7 +68,7 @@ $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES): scan-build.stamp tmpl-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt @echo '*** Rebuilding template files ***' @-chmod -R u+w $(srcdir) - cd $(srcdir) && gtkdoc-mktmpl --module=$(DOC_MODULE) + cd $(srcdir) && gtkdoc-mktmpl --module=$(DOC_MODULE) $(MKTMPL_OPTIONS) touch tmpl-build.stamp tmpl.stamp: tmpl-build.stamp @@ -83,11 +76,11 @@ tmpl.stamp: tmpl-build.stamp #### xml #### -sgml-build.stamp: tmpl.stamp $(CFILE_GLOB) $(srcdir)/tmpl/*.sgml +sgml-build.stamp: tmpl.stamp $(CFILE_GLOB) $(srcdir)/tmpl/*.sgml $(expand_content_files) @echo '*** Building XML ***' @-chmod -R u+w $(srcdir) cd $(srcdir) && \ - gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --output-format=xml $(MKDB_OPTIONS) + gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --output-format=xml --expand-content-files="$(expand_content_files)" $(MKDB_OPTIONS) touch sgml-build.stamp sgml.stamp: sgml-build.stamp @@ -146,18 +139,15 @@ dist-check-gtkdoc: @false endif -# XXX: Before this was: -# dist-hook: dist-check-gtkdoc dist-hook-local -# which seems reasonable, but for some reason the dist-check-gtkdoc -# was always failing on me, even though I do have gtk-doc installed -# and it is successfully building the documentation. - -dist-hook: dist-hook-local +dist-hook: dist-check-gtkdoc dist-hook-local mkdir $(distdir)/tmpl mkdir $(distdir)/xml mkdir $(distdir)/html -cp $(srcdir)/tmpl/*.sgml $(distdir)/tmpl -cp $(srcdir)/xml/*.xml $(distdir)/xml -cp $(srcdir)/html/* $(distdir)/html + if test -f $(srcdir)/$(DOC_MODULE).types; then \ + cp $(srcdir)/$(DOC_MODULE).types $(distdir)/$(DOC_MODULE).types; \ + fi .PHONY : dist-hook-local diff --git a/src/cairo-array.c b/src/cairo-array.c index a37ea9af5..a9f148a07 100644 --- a/src/cairo-array.c +++ b/src/cairo-array.c @@ -147,7 +147,7 @@ typedef struct { * * Initializes a #cairo_user_data_array_t structure for future * use. After initialization, the array has no keys. Call - * _cairo_user_data_array_destroy() to free any allocated memory + * _cairo_user_data_array_fini() to free any allocated memory * when done using the array. **/ void @@ -157,14 +157,14 @@ _cairo_user_data_array_init (cairo_user_data_array_t *array) } /** - * _cairo_user_data_array_destroy: + * _cairo_user_data_array_fini: * @array: a #cairo_user_data_array_t * * Destroys all current keys in the user data array and deallocates * any memory allocated for the array itself. **/ void -_cairo_user_data_array_destroy (cairo_user_data_array_t *array) +_cairo_user_data_array_fini (cairo_user_data_array_t *array) { int i, num_slots; cairo_user_data_slot_t *slots; diff --git a/src/cairo-atsui-font.c b/src/cairo-atsui-font.c index a279956df..5c7ddf54a 100644 --- a/src/cairo-atsui-font.c +++ b/src/cairo-atsui-font.c @@ -209,7 +209,6 @@ _cairo_atsui_font_destroy_font(void *abstract_font) { cairo_atsui_font_t *font = abstract_font; - if (font == NULL) return; @@ -486,14 +485,16 @@ _cairo_atsui_font_show_glyphs(void *abstract_font, CGContextSetTextMatrix(myBitmapContext, textTransform); if (pattern->type == CAIRO_PATTERN_SOLID && - _cairo_pattern_is_opaque_solid(pattern)) { + _cairo_pattern_is_opaque_solid(pattern)) + { cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *)pattern; CGContextSetRGBFillColor(myBitmapContext, solid->color.red, solid->color.green, solid->color.blue, 1.0f); - } else + } else { CGContextSetRGBFillColor(myBitmapContext, 0.0f, 0.0f, 0.0f, 0.0f); + } // TODO - bold and italic text // diff --git a/src/cairo-cache.c b/src/cairo-cache.c index e95894960..e7547bc29 100644 --- a/src/cairo-cache.c +++ b/src/cairo-cache.c @@ -182,19 +182,25 @@ _cache_lookup (cairo_cache_t *cache, { /* We are looking up an exact entry. */ if (*probe == NULL) + { /* Found an empty spot, there can't be a match */ break; + } else if (*probe != DEAD_ENTRY && (*probe)->hashcode == hash && predicate (cache, key, *probe)) + { return probe; + } } else { /* We are just looking for a free slot. */ if (*probe == NULL || *probe == DEAD_ENTRY) + { return probe; + } } if (step == 0) { @@ -339,7 +345,6 @@ _cairo_cache_init (cairo_cache_t *cache, if (cache != NULL){ cache->arrangement = &cache_arrangements[0]; - cache->refcount = 1; cache->max_memory = max_memory; cache->used_memory = 0; cache->live_entries = 0; @@ -362,31 +367,20 @@ _cairo_cache_init (cairo_cache_t *cache, } void -_cairo_cache_reference (cairo_cache_t *cache) -{ - _cache_sane_state (cache); - cache->refcount++; -} - -void _cairo_cache_destroy (cairo_cache_t *cache) { unsigned long i; - if (cache != NULL) { + if (cache == NULL) + return; - _cache_sane_state (cache); + _cache_sane_state (cache); - if (--cache->refcount > 0) - return; - - for (i = 0; i < cache->arrangement->size; ++i) { - _entry_destroy (cache, i); - } + for (i = 0; i < cache->arrangement->size; ++i) + _entry_destroy (cache, i); - free (cache->entries); - cache->entries = NULL; - cache->backend->destroy_cache (cache); - } + free (cache->entries); + cache->entries = NULL; + cache->backend->destroy_cache (cache); } cairo_status_t diff --git a/src/cairo-font.c b/src/cairo-font.c index 3bd1e0318..0aeb00b61 100644 --- a/src/cairo-font.c +++ b/src/cairo-font.c @@ -53,15 +53,19 @@ _cairo_font_face_init (cairo_font_face_t *font_face, /** * cairo_font_face_reference: - * @font_face: a #cairo_font_face_t + * @font_face: a #cairo_font_face_t, (may be NULL in which case this + * function does nothing). * * Increases the reference count on @font_face by one. This prevents - * @font_face from being destroyed until a matching call to cairo_font_face_destroy() - * is made. + * @font_face from being destroyed until a matching call to + * cairo_font_face_destroy() is made. **/ void cairo_font_face_reference (cairo_font_face_t *font_face) { + if (font_face == NULL) + return; + font_face->refcount++; } @@ -76,6 +80,9 @@ cairo_font_face_reference (cairo_font_face_t *font_face) void cairo_font_face_destroy (cairo_font_face_t *font_face) { + if (font_face == NULL) + return; + if (--(font_face->refcount) > 0) return; @@ -88,7 +95,7 @@ cairo_font_face_destroy (cairo_font_face_t *font_face) if (font_face->refcount > 0) return; - _cairo_user_data_array_destroy (&font_face->user_data); + _cairo_user_data_array_fini (&font_face->user_data); free (font_face); } @@ -327,6 +334,9 @@ _cairo_simple_font_face_destroy (void *abstract_face) cairo_cache_t *cache; cairo_simple_cache_key_t key; + if (simple_face == NULL) + return; + _lock_global_simple_cache (); cache = _get_global_simple_cache (); assert (cache); @@ -395,7 +405,7 @@ _cairo_simple_font_face_create (const char *family, return NULL; } status = _cairo_cache_lookup (cache, &key, (void **) &entry, &created_entry); - if (CAIRO_OK (status) && !created_entry) + if (status == CAIRO_STATUS_SUCCESS && !created_entry) cairo_font_face_reference (&entry->font_face->base); _unlock_global_simple_cache (); @@ -586,7 +596,7 @@ _cairo_outer_font_cache_create_entry (void *cache, } status = _cairo_cache_lookup (cache, key, (void **) &inner_entry, &created_entry); - if (!CAIRO_OK (status)) { + if (status) { free (entry); return status; } @@ -636,7 +646,7 @@ _cairo_inner_font_cache_create_entry (void *cache, k->font_matrix, k->ctm, &entry->scaled_font); - if (!CAIRO_OK (status)) { + if (status) { free (entry); return status; } @@ -727,11 +737,11 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, } status = _cairo_cache_lookup (cache, &key, (void **) &entry, NULL); - if (CAIRO_OK (status)) + if (status == CAIRO_STATUS_SUCCESS) cairo_scaled_font_reference (entry->scaled_font); _unlock_global_font_cache (); - if (!CAIRO_OK (status)) + if (status) return NULL; return entry->scaled_font; @@ -847,12 +857,18 @@ _cairo_unscaled_font_init (cairo_unscaled_font_t *unscaled_font, void _cairo_unscaled_font_reference (cairo_unscaled_font_t *unscaled_font) { + if (unscaled_font == NULL) + return; + unscaled_font->refcount++; } void _cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font) { + if (unscaled_font == NULL) + return; + if (--(unscaled_font->refcount) > 0) return; @@ -867,7 +883,8 @@ _cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font) /** * cairo_scaled_font_reference: - * @scaled_font: a #cairo_scaled_font_t + * @scaled_font: a #cairo_scaled_font_t, (may be NULL in which case + * this function does nothing) * * Increases the reference count on @scaled_font by one. This prevents * @scaled_font from being destroyed until a matching call to @@ -876,6 +893,9 @@ _cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font) void cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font) { + if (scaled_font == NULL) + return; + scaled_font->refcount++; } @@ -893,6 +913,9 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font) cairo_font_cache_key_t key; cairo_cache_t *cache; + if (scaled_font == NULL) + return; + if (--(scaled_font->refcount) > 0) return; @@ -935,7 +958,7 @@ cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font, status = _cairo_scaled_font_font_extents (scaled_font, extents); - if (!CAIRO_OK (status)) + if (status) return status; _cairo_matrix_compute_scale_factors (&scaled_font->font_matrix, diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index c02cd61e5..63f51a51c 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -256,6 +256,7 @@ static void _ft_font_cache_destroy_cache (void *cache) { ft_cache_t *fc = (ft_cache_t *) cache; + FT_Done_FreeType (fc->lib); free (fc); } @@ -337,11 +338,11 @@ _ft_unscaled_font_get_for_pattern (FcPattern *pattern) } status = _cairo_cache_lookup (cache, &key, (void **) &entry, &created_entry); - if (CAIRO_OK (status) && !created_entry) + if (status == CAIRO_STATUS_SUCCESS && !created_entry) _cairo_unscaled_font_reference (&entry->unscaled->base); _unlock_global_ft_cache (); - if (!CAIRO_OK (status)) + if (status) return NULL; return entry->unscaled; @@ -482,6 +483,9 @@ _cairo_ft_unscaled_font_destroy (void *abstract_font) { ft_unscaled_font_t *unscaled = abstract_font; + if (unscaled == NULL) + return; + if (unscaled->from_face) { /* See comments in _ft_font_face_destroy about the "zombie" state * for a _ft_font_face. @@ -575,10 +579,9 @@ _cairo_ft_unscaled_font_create_glyph (void *abstract_ height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6); stride = (width + 3) & -4; - if (width * height == 0) + if (width * height == 0) { val->image = NULL; - else - { + } else { bitmap.pixel_mode = ft_pixel_mode_grays; bitmap.num_grays = 256; @@ -863,7 +866,7 @@ _cairo_ft_scaled_font_text_to_glyphs (void *abstract_font, _cairo_ft_scaled_font_get_glyph_cache_key (scaled_font, &key); status = _cairo_utf8_to_ucs4 ((unsigned char*)utf8, -1, &ucs4, num_glyphs); - if (!CAIRO_OK (status)) + if (status) return status; face = cairo_ft_scaled_font_lock_face (&scaled_font->base); @@ -1341,6 +1344,9 @@ _ft_font_face_destroy (void *abstract_face) ft_font_face_t *tmp_face = NULL; ft_font_face_t *last_face = NULL; + if (font_face == NULL) + return; + /* When destroying the face created by cairo_ft_font_face_create_for_ft_face, * we have a special "zombie" state for the face when the unscaled font * is still alive but there are no public references to the font face. @@ -1476,7 +1482,7 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern) } /** - * cairo_ft_font_create_for_ft_face: + * cairo_ft_font_face_create_for_ft_face: * @face: A FreeType face object, already opened. This must * be kept around until the face's refcount drops to * zero and it is freed. Since the face may be referenced diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index 673b972c3..ce9da259b 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -70,7 +70,6 @@ _glitz_format (cairo_format_t format) static cairo_surface_t * _cairo_glitz_surface_create_similar (void *abstract_src, cairo_format_t format, - int draw, int width, int height) { @@ -215,9 +214,6 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, _cairo_image_surface_assume_ownership_of_data (image); - _cairo_image_surface_set_repeat (image, surface->base.repeat); - _cairo_image_surface_set_matrix (image, &(surface->base.matrix)); - *image_out = image; return CAIRO_STATUS_SUCCESS; @@ -356,7 +352,7 @@ _cairo_glitz_surface_clone_similar (void *abstract_surface, cairo_image_surface_t *image_src = (cairo_image_surface_t *) src; clone = (cairo_glitz_surface_t *) - _cairo_glitz_surface_create_similar (surface, image_src->format, 0, + _cairo_glitz_surface_create_similar (surface, image_src->format, image_src->width, image_src->height); if (!clone) @@ -602,7 +598,7 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern, src = (cairo_glitz_surface_t *) _cairo_surface_create_similar_scratch (&dst->base, - CAIRO_FORMAT_ARGB32, 0, + CAIRO_FORMAT_ARGB32, gradient->n_stops, 1); if (!src) { @@ -1035,7 +1031,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, mask = (cairo_glitz_surface_t *) _cairo_glitz_surface_create_similar (&dst->base, - CAIRO_FORMAT_A8, 0, + CAIRO_FORMAT_A8, 2, 1); if (!mask) { @@ -1135,7 +1131,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, mask = (cairo_glitz_surface_t *) _cairo_surface_create_similar_scratch (&dst->base, - CAIRO_FORMAT_A8, 0, + CAIRO_FORMAT_A8, width, height); if (!mask) { @@ -1328,7 +1324,7 @@ _cairo_glitz_area_create (cairo_glitz_root_area_t *root, static void _cairo_glitz_area_destroy (cairo_glitz_area_t *area) { - if (!area) + if (area == NULL) return; if (area->state == CAIRO_GLITZ_AREA_OCCUPIED) @@ -1390,6 +1386,8 @@ _cairo_glitz_area_find (cairo_glitz_area_t *area, cairo_bool_t kick_out, void *closure) { + cairo_status_t status; + if (area->width < width || area->height < height) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1403,8 +1401,9 @@ _cairo_glitz_area_find (cairo_glitz_area_t *area, return CAIRO_INT_STATUS_UNSUPPORTED; _cairo_glitz_area_move_out (area); - } else + } else { return CAIRO_INT_STATUS_UNSUPPORTED; + } /* fall-through */ case CAIRO_GLITZ_AREA_AVAILABLE: { @@ -1449,9 +1448,10 @@ _cairo_glitz_area_find (cairo_glitz_area_t *area, area->state = CAIRO_GLITZ_AREA_DIVIDED; - if (CAIRO_OK (_cairo_glitz_area_find (area->area[0], - width, height, - kick_out, closure))) + status = _cairo_glitz_area_find (area->area[0], + width, height, + kick_out, closure); + if (status == CAIRO_STATUS_SUCCESS) return CAIRO_STATUS_SUCCESS; } } break; @@ -1466,9 +1466,10 @@ _cairo_glitz_area_find (cairo_glitz_area_t *area, if (area->area[i]->width >= width && area->area[i]->height >= height) { - if (CAIRO_OK (_cairo_glitz_area_find (area->area[i], - width, height, - kick_out, closure))) + status = _cairo_glitz_area_find (area->area[i], + width, height, + kick_out, closure); + if (status == CAIRO_STATUS_SUCCESS) return CAIRO_STATUS_SUCCESS; rejected = TRUE; @@ -1488,8 +1489,9 @@ _cairo_glitz_area_find (cairo_glitz_area_t *area, to_area->closure, closure) >= 0) return CAIRO_INT_STATUS_UNSUPPORTED; - } else + } else { return CAIRO_INT_STATUS_UNSUPPORTED; + } } for (i = 0; i < 4; i++) @@ -1500,8 +1502,10 @@ _cairo_glitz_area_find (cairo_glitz_area_t *area, area->closure = NULL; area->state = CAIRO_GLITZ_AREA_AVAILABLE; - if (CAIRO_OK (_cairo_glitz_area_find (area, width, height, - TRUE, closure))) + + status = _cairo_glitz_area_find (area, width, height, + TRUE, closure); + if (status == CAIRO_STATUS_SUCCESS) return CAIRO_STATUS_SUCCESS; } break; @@ -1607,7 +1611,7 @@ static const cairo_glitz_area_funcs_t _cairo_glitz_area_funcs = { }; static cairo_status_t -_cairo_glitz_glyph_cache_entry_create (void *abstract_cache, +_cairo_glitz_glyph_cache_create_entry (void *abstract_cache, void *abstract_key, void **return_entry) { @@ -1631,7 +1635,7 @@ _cairo_glitz_glyph_cache_entry_create (void *abstract_cache, } static void -_cairo_glitz_glyph_cache_entry_destroy (void *abstract_cache, +_cairo_glitz_glyph_cache_destroy_entry (void *abstract_cache, void *abstract_entry) { cairo_glitz_glyph_cache_entry_t *entry = abstract_entry; @@ -1657,7 +1661,7 @@ _cairo_glitz_glyph_cache_entry_reference (void *abstract_entry) } static void -_cairo_glitz_glyph_cache_destroy (void *abstract_cache) +_cairo_glitz_glyph_cache_destroy_cache (void *abstract_cache) { cairo_glitz_glyph_cache_t *cache = abstract_cache; @@ -1669,9 +1673,9 @@ _cairo_glitz_glyph_cache_destroy (void *abstract_cache) static const cairo_cache_backend_t _cairo_glitz_glyph_cache_backend = { _cairo_glyph_cache_hash, _cairo_glyph_cache_keys_equal, - _cairo_glitz_glyph_cache_entry_create, - _cairo_glitz_glyph_cache_entry_destroy, - _cairo_glitz_glyph_cache_destroy + _cairo_glitz_glyph_cache_create_entry, + _cairo_glitz_glyph_cache_destroy_entry, + _cairo_glitz_glyph_cache_destroy_cache }; static cairo_glitz_glyph_cache_t *_cairo_glitz_glyph_caches = NULL; @@ -2088,7 +2092,7 @@ UNLOCK: } for (i = 0; i < num_glyphs; i++) - _cairo_glitz_glyph_cache_entry_destroy (cache, entries[i]); + _cairo_glitz_glyph_cache_destroy_entry (cache, entries[i]); glitz_buffer_destroy (buffer); @@ -2125,6 +2129,7 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = { NULL, /* copy_page */ NULL, /* show_page */ _cairo_glitz_surface_set_clip_region, + NULL, /* intersect_clip_path */ _cairo_glitz_surface_get_extents, _cairo_glitz_surface_show_glyphs }; diff --git a/src/cairo-gstate-private.h b/src/cairo-gstate-private.h index eeb35b83e..7e2c8597c 100644 --- a/src/cairo-gstate-private.h +++ b/src/cairo-gstate-private.h @@ -36,6 +36,47 @@ #ifndef CAIRO_GSTATE_PRIVATE_H #define CAIRO_GSTATE_PRIVATE_H +#include "cairo-path-fixed-private.h" + +struct _cairo_clip_path { + unsigned int ref_count; + cairo_path_fixed_t path; + cairo_fill_rule_t fill_rule; + double tolerance; + cairo_clip_path_t *prev; +}; + +typedef struct _cairo_clip { + cairo_clip_mode_t mode; + + /* + * Mask-based clipping for cases where the backend + * clipping isn't sufficiently able. + * + * The rectangle here represents the + * portion of the destination surface that this + * clip surface maps to, it does not + * represent the extents of the clip region or + * clip paths + */ + cairo_surface_t *surface; + cairo_rectangle_t surface_rect; + /* + * Surface clip serial number to store + * in the surface when this clip is set + */ + unsigned int serial; + /* + * A clip region that can be placed in the surface + */ + pixman_region16_t *region; + /* + * If the surface supports path clipping, we store the list of + * clipping paths that has been set here as a linked list. + */ + cairo_clip_path_t *path; +} cairo_clip_t; + struct _cairo_gstate { cairo_operator_t operator; @@ -53,27 +94,21 @@ struct _cairo_gstate { int num_dashes; double dash_offset; - char *font_family; /* NULL means CAIRO_FONT_FAMILY_DEFAULT; */ - cairo_font_slant_t font_slant; - cairo_font_weight_t font_weight; - cairo_font_face_t *font_face; cairo_scaled_font_t *scaled_font; /* Specific to the current CTM */ - - cairo_surface_t *surface; - int surface_level; /* Used to detect bad nested use */ - - cairo_pattern_t *source; - - cairo_clip_rec_t clip; - cairo_matrix_t font_matrix; + cairo_clip_t clip; + cairo_matrix_t ctm; cairo_matrix_t ctm_inverse; cairo_pen_t pen_regular; + cairo_surface_t *target; + + cairo_pattern_t *source; + struct _cairo_gstate *next; }; diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 45c729fc9..94770f329 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -42,8 +42,14 @@ #include "cairo-gstate-private.h" static cairo_status_t -_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, - cairo_surface_t *surface); +_cairo_gstate_init (cairo_gstate_t *gstate, + cairo_surface_t *target); + +static cairo_status_t +_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other); + +static void +_cairo_gstate_fini (cairo_gstate_t *gstate); static cairo_status_t _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, @@ -61,6 +67,15 @@ _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate); static void _cairo_gstate_unset_font (cairo_gstate_t *gstate); +static void +_cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src); + +static void +_cairo_clip_path_reference (cairo_clip_path_t *clip_path); + +static void +_cairo_clip_path_destroy (cairo_clip_path_t *clip_path); + cairo_gstate_t * _cairo_gstate_create (cairo_surface_t *target) { @@ -81,12 +96,10 @@ _cairo_gstate_create (cairo_surface_t *target) return gstate; } -cairo_status_t +static cairo_status_t _cairo_gstate_init (cairo_gstate_t *gstate, cairo_surface_t *target) { - cairo_status_t status; - gstate->operator = CAIRO_GSTATE_OPERATOR_DEFAULT; gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT; @@ -102,37 +115,36 @@ _cairo_gstate_init (cairo_gstate_t *gstate, gstate->num_dashes = 0; gstate->dash_offset = 0.0; - gstate->scaled_font = NULL; gstate->font_face = NULL; + gstate->scaled_font = NULL; cairo_matrix_init_scale (&gstate->font_matrix, CAIRO_GSTATE_DEFAULT_FONT_SIZE, CAIRO_GSTATE_DEFAULT_FONT_SIZE); - gstate->surface = NULL; - gstate->surface_level = 0; - + gstate->clip.mode = _cairo_surface_get_clip_mode (target); gstate->clip.region = NULL; gstate->clip.surface = NULL; - - gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK); - if (!gstate->source) - return CAIRO_STATUS_NO_MEMORY; + gstate->clip.serial = 0; + gstate->clip.path = NULL; _cairo_gstate_identity_matrix (gstate); _cairo_pen_init_empty (&gstate->pen_regular); - gstate->next = NULL; + gstate->target = target; + cairo_surface_reference (gstate->target); - status = _cairo_gstate_set_target_surface (gstate, target); - if (status) - return status; + gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK); + if (gstate->source->status) + return CAIRO_STATUS_NO_MEMORY; + + gstate->next = NULL; return CAIRO_STATUS_SUCCESS; } -cairo_status_t +static cairo_status_t _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) { cairo_status_t status; @@ -151,8 +163,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double)); } - if (other->clip.region) - { + if (other->clip.region) { gstate->clip.region = pixman_region_create (); pixman_region_copy (gstate->clip.region, other->clip.region); } @@ -163,8 +174,9 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) if (gstate->scaled_font) cairo_scaled_font_reference (gstate->scaled_font); - cairo_surface_reference (gstate->surface); + cairo_surface_reference (gstate->target); cairo_surface_reference (gstate->clip.surface); + _cairo_clip_path_reference (gstate->clip.path); cairo_pattern_reference (gstate->source); @@ -172,16 +184,8 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) if (status) goto CLEANUP_FONT; - status = _cairo_surface_begin (gstate->surface); - if (status) - goto CLEANUP_PEN; - gstate->surface_level = gstate->surface->level; - return status; - CLEANUP_PEN: - _cairo_pen_fini (&gstate->pen_regular); - CLEANUP_FONT: cairo_scaled_font_destroy (gstate->scaled_font); gstate->scaled_font = NULL; @@ -201,19 +205,23 @@ _cairo_gstate_fini (cairo_gstate_t *gstate) if (gstate->scaled_font) cairo_scaled_font_destroy (gstate->scaled_font); - if (gstate->surface) { - _cairo_surface_end (gstate->surface); - cairo_surface_destroy (gstate->surface); - gstate->surface = NULL; + if (gstate->target) { + cairo_surface_destroy (gstate->target); + gstate->target = NULL; } if (gstate->clip.surface) cairo_surface_destroy (gstate->clip.surface); gstate->clip.surface = NULL; + if (gstate->clip.path) + _cairo_clip_path_destroy (gstate->clip.path); + gstate->clip.path = NULL; + if (gstate->clip.region) pixman_region_destroy (gstate->clip.region); gstate->clip.region = NULL; + gstate->clip.serial = 0; cairo_pattern_destroy (gstate->source); @@ -259,30 +267,30 @@ _cairo_gstate_begin_group (cairo_gstate_t *gstate) Pixmap pix; unsigned int width, height; - gstate->parent_surface = gstate->surface; + gstate->parent_surface = gstate->target; - width = _cairo_surface_get_width (gstate->surface); - height = _cairo_surface_get_height (gstate->surface); + width = _cairo_surface_get_width (gstate->target); + height = _cairo_surface_get_height (gstate->target); pix = XCreatePixmap (gstate->dpy, - _cairo_surface_get_drawable (gstate->surface), + _cairo_surface_get_drawable (gstate->target), width, height, - _cairo_surface_get_depth (gstate->surface)); + _cairo_surface_get_depth (gstate->target)); if (pix == 0) return CAIRO_STATUS_NO_MEMORY; - gstate->surface = cairo_surface_create (gstate->dpy); - if (gstate->surface == NULL) + gstate->target = cairo_surface_create (gstate->dpy); + if (gstate->target == NULL) return CAIRO_STATUS_NO_MEMORY; - _cairo_surface_set_drawableWH (gstate->surface, pix, width, height); + _cairo_surface_set_drawableWH (gstate->target, pix, width, height); - status = _cairo_surface_fill_rectangle (gstate->surface, + status = _cairo_surface_fill_rectangle (gstate->target, CAIRO_OPERATOR_SOURCE, &CAIRO_COLOR_TRANSPARENT, 0, 0, - _cairo_surface_get_width (gstate->surface), - _cairo_surface_get_height (gstate->surface)); + _cairo_surface_get_width (gstate->target), + _cairo_surface_get_height (gstate->target)); if (status) return status; @@ -311,22 +319,22 @@ _cairo_gstate_end_group (cairo_gstate_t *gstate) _cairo_surface_get_damaged_width/Height if cairo_surface_t actually kept track of such informaton. * _cairo_surface_composite (gstate->operator, - gstate->surface, + gstate->target, mask, gstate->parent_surface, 0, 0, 0, 0, 0, 0, - _cairo_surface_get_width (gstate->surface), - _cairo_surface_get_height (gstate->surface)); + _cairo_surface_get_width (gstate->target), + _cairo_surface_get_height (gstate->target)); _cairo_surface_fini (&mask); - pix = _cairo_surface_get_drawable (gstate->surface); + pix = _cairo_surface_get_drawable (gstate->target); XFreePixmap (gstate->dpy, pix); - cairo_surface_destroy (gstate->surface); - gstate->surface = gstate->parent_surface; + cairo_surface_destroy (gstate->target); + gstate->target = gstate->parent_surface; gstate->parent_surface = NULL; return CAIRO_STATUS_SUCCESS; @@ -334,41 +342,57 @@ _cairo_gstate_end_group (cairo_gstate_t *gstate) */ static cairo_status_t -_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface) +_cairo_gstate_set_clip (cairo_gstate_t *gstate) { - cairo_status_t status; + cairo_surface_t *surface = gstate->target; - if (gstate->surface == surface) + if (!surface) + return CAIRO_STATUS_NULL_POINTER; + if (gstate->clip.serial == _cairo_surface_get_current_clip_serial (surface)) return CAIRO_STATUS_SUCCESS; - if (surface) { - status = _cairo_surface_begin_reset_clip (surface); - if (!CAIRO_OK (status)) - return status; - } - - _cairo_gstate_unset_font (gstate); - - if (gstate->surface) { - _cairo_surface_end (gstate->surface); - cairo_surface_destroy (gstate->surface); - } - - gstate->surface = surface; + if (gstate->clip.path) + return _cairo_surface_set_clip_path (surface, + gstate->clip.path, + gstate->clip.serial); + + if (gstate->clip.region) + return _cairo_surface_set_clip_region (surface, + gstate->clip.region, + gstate->clip.serial); + + return _cairo_surface_reset_clip (surface); +} - /* Sometimes the user wants to return to having no target surface, - * (just like after cairo_create). This can be useful for forcing - * the old surface to be destroyed. */ - if (surface == NULL) { - gstate->surface_level = 0; - return CAIRO_STATUS_SUCCESS; +static cairo_status_t +_cairo_gstate_get_clip_extents (cairo_gstate_t *gstate, + cairo_rectangle_t *rectangle) +{ + cairo_status_t status; + + status = _cairo_surface_get_extents (gstate->target, rectangle); + if (status) + return status; + /* check path extents here */ + + if (gstate->clip.region) { + pixman_box16_t *clip_box; + cairo_rectangle_t clip_rect; + + /* get region extents as a box */ + clip_box = pixman_region_extents (gstate->clip.region); + /* convert to a rectangle */ + clip_rect.x = clip_box->x1; + clip_rect.width = clip_box->x2 - clip_box->x1; + clip_rect.y = clip_box->y1; + clip_rect.height = clip_box->y2 - clip_box->y1; + /* intersect with surface extents */ + _cairo_rectangle_intersect (rectangle, &clip_rect); } - cairo_surface_reference (gstate->surface); - gstate->surface_level = surface->level; - - _cairo_gstate_identity_matrix (gstate); - + if (gstate->clip.surface) + _cairo_rectangle_intersect (rectangle, &gstate->clip.surface_rect); + return CAIRO_STATUS_SUCCESS; } @@ -378,15 +402,15 @@ _cairo_gstate_get_target (cairo_gstate_t *gstate) if (gstate == NULL) return NULL; - return gstate->surface; + return gstate->target; } cairo_status_t _cairo_gstate_set_source (cairo_gstate_t *gstate, cairo_pattern_t *source) { - if (source == NULL) - return CAIRO_STATUS_NULL_POINTER; + if (source->status) + return source->status; cairo_pattern_reference (source); cairo_pattern_destroy (gstate->source); @@ -395,24 +419,6 @@ _cairo_gstate_set_source (cairo_gstate_t *gstate, return CAIRO_STATUS_SUCCESS; } -cairo_status_t -_cairo_gstate_set_source_solid (cairo_gstate_t *gstate, - const cairo_color_t *color) -{ - cairo_status_t status; - cairo_pattern_t *source; - - source = _cairo_pattern_create_solid (color); - if (!source) - return CAIRO_STATUS_NO_MEMORY; - - status = _cairo_gstate_set_source (gstate, source); - - cairo_pattern_destroy (source); - - return CAIRO_STATUS_SUCCESS; -} - cairo_pattern_t * _cairo_gstate_get_source (cairo_gstate_t *gstate) { @@ -684,18 +690,18 @@ void _cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y) { cairo_matrix_transform_point (&gstate->ctm, x, y); - if (gstate->surface) { - *x += gstate->surface->device_x_offset; - *y += gstate->surface->device_y_offset; + if (gstate->target) { + *x += gstate->target->device_x_offset; + *y += gstate->target->device_y_offset; } } void _cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y) { - if (gstate->surface) { - *x -= gstate->surface->device_x_offset; - *y -= gstate->surface->device_y_offset; + if (gstate->target) { + *x -= gstate->target->device_x_offset; + *y -= gstate->target->device_y_offset; } cairo_matrix_transform_point (&gstate->ctm_inverse, x, y); } @@ -717,10 +723,10 @@ _cairo_gstate_pattern_transform (cairo_gstate_t *gstate, { cairo_matrix_t tmp_matrix = gstate->ctm_inverse; - if (gstate->surface) + if (gstate->target) cairo_matrix_translate (&tmp_matrix, - - gstate->surface->device_x_offset, - - gstate->surface->device_y_offset); + - gstate->target->device_x_offset, + - gstate->target->device_y_offset); _cairo_pattern_transform (pattern, &tmp_matrix); } @@ -733,11 +739,15 @@ _cairo_gstate_paint (cairo_gstate_t *gstate) cairo_box_t box; cairo_traps_t traps; - if (gstate->surface->level != gstate->surface_level) - return CAIRO_STATUS_BAD_NESTING; - - status = _cairo_surface_get_clip_extents (gstate->surface, &rectangle); - if (!CAIRO_OK (status)) + if (gstate->source->status) + return gstate->source->status; + + status = _cairo_gstate_set_clip (gstate); + if (status) + return status; + + status = _cairo_gstate_get_clip_extents (gstate, &rectangle); + if (status) return status; box.p1.x = _cairo_fixed_from_int (rectangle.x); @@ -745,13 +755,13 @@ _cairo_gstate_paint (cairo_gstate_t *gstate) box.p2.x = _cairo_fixed_from_int (rectangle.x + rectangle.width); box.p2.y = _cairo_fixed_from_int (rectangle.y + rectangle.height); status = _cairo_traps_init_box (&traps, &box); - if (!CAIRO_OK (status)) + if (status) return status; _cairo_gstate_clip_and_composite_trapezoids (gstate, gstate->source, gstate->operator, - gstate->surface, + gstate->target, &traps); _cairo_traps_fini (&traps); @@ -778,8 +788,8 @@ _cairo_gstate_combine_clip_surface (cairo_gstate_t *gstate, &pattern.base, NULL, intermediate, - extents->x - gstate->clip.rect.x, - extents->y - gstate->clip.rect.y, + extents->x - gstate->clip.surface_rect.x, + extents->y - gstate->clip.surface_rect.y, 0, 0, 0, 0, extents->width, extents->height); @@ -832,8 +842,8 @@ _cairo_gstate_intersect_clip (cairo_gstate_t *gstate, pixman_region16_t *clip_rect; cairo_status_t status; - status = _region_new_from_rect (&gstate->clip.rect, &clip_rect); - if (!CAIRO_OK (status)) + status = _region_new_from_rect (&gstate->clip.surface_rect, &clip_rect); + if (status) return status; if (pixman_region_intersect (region, @@ -843,7 +853,7 @@ _cairo_gstate_intersect_clip (cairo_gstate_t *gstate, pixman_region_destroy (clip_rect); - if (!CAIRO_OK (status)) + if (status) return status; } @@ -855,27 +865,12 @@ _get_mask_extents (cairo_gstate_t *gstate, cairo_pattern_t *mask, cairo_rectangle_t *extents) { - cairo_rectangle_t clip_rect; - pixman_region16_t *clip_region; - cairo_status_t status; - - status = _cairo_surface_get_clip_extents (gstate->surface, &clip_rect); - if (!CAIRO_OK (status)) - return status; - - status = _region_new_from_rect (&clip_rect, &clip_region); - if (!CAIRO_OK (status)) - return status; - - status = _cairo_gstate_intersect_clip (gstate, clip_region); - if (!CAIRO_OK (status)) - return status; - - _region_rect_extents (clip_region, extents); - - pixman_region_destroy (clip_region); - - return CAIRO_STATUS_SUCCESS; + /* + * XXX should take mask extents into account, but + * that involves checking the transform... For now, + * be lazy and just use the destination extents + */ + return _cairo_gstate_get_clip_extents (gstate, extents); } cairo_status_t @@ -889,9 +884,16 @@ _cairo_gstate_mask (cairo_gstate_t *gstate, cairo_status_t status; int mask_x, mask_y; - if (gstate->surface->level != gstate->surface_level) - return CAIRO_STATUS_BAD_NESTING; - + if (mask->status) + return mask->status; + + if (gstate->source->status) + return gstate->source->status; + + status = _cairo_gstate_set_clip (gstate); + if (status) + return status; + _get_mask_extents (gstate, mask, &extents); if (gstate->clip.surface) { @@ -913,13 +915,13 @@ _cairo_gstate_mask (cairo_gstate_t *gstate, 0, 0, 0, 0, extents.width, extents.height); - if (!CAIRO_OK (status)) { + if (status) { cairo_surface_destroy (intermediate); return status; } status = _cairo_gstate_combine_clip_surface (gstate, intermediate, &extents); - if (!CAIRO_OK (status)) { + if (status) { cairo_surface_destroy (intermediate); return status; } @@ -942,7 +944,7 @@ _cairo_gstate_mask (cairo_gstate_t *gstate, status = _cairo_surface_composite (gstate->operator, &pattern.base, effective_mask, - gstate->surface, + gstate->target, extents.x, extents.y, extents.x - mask_x, extents.y - mask_y, extents.x, extents.y, @@ -960,12 +962,16 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) cairo_status_t status; cairo_traps_t traps; - if (gstate->surface->level != gstate->surface_level) - return CAIRO_STATUS_BAD_NESTING; - + if (gstate->source->status) + return gstate->source->status; + if (gstate->line_width <= 0.0) return CAIRO_STATUS_SUCCESS; + status = _cairo_gstate_set_clip (gstate); + if (status) + return status; + _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate); _cairo_traps_init (&traps); @@ -979,7 +985,7 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) _cairo_gstate_clip_and_composite_trapezoids (gstate, gstate->source, gstate->operator, - gstate->surface, + gstate->target, &traps); _cairo_traps_fini (&traps); @@ -1079,7 +1085,7 @@ _clip_and_compute_extents_region (cairo_gstate_t *gstate, cairo_status_t status; status = _cairo_gstate_intersect_clip (gstate, trap_region); - if (!CAIRO_OK (status)) + if (status) return status; _region_rect_extents (trap_region, extents); @@ -1105,24 +1111,28 @@ _clip_and_compute_extents_arbitrary (cairo_gstate_t *gstate, cairo_status_t status; status = _region_new_from_rect (extents, &intersection); - if (!CAIRO_OK (status)) + if (status) return status; if (pixman_region_intersect (intersection, gstate->clip.region, intersection) == PIXMAN_REGION_STATUS_SUCCESS) + { _region_rect_extents (intersection, extents); + } else + { status = CAIRO_STATUS_NO_MEMORY; + } pixman_region_destroy (intersection); - if (!CAIRO_OK (status)) + if (status) return status; } if (gstate->clip.surface) - _cairo_rectangle_intersect (extents, &gstate->clip.rect); + _cairo_rectangle_intersect (extents, &gstate->clip.surface_rect); return CAIRO_STATUS_SUCCESS; } @@ -1137,17 +1147,25 @@ _composite_trap_region (cairo_gstate_t *gstate, pixman_region16_t *trap_region, cairo_rectangle_t *extents) { - cairo_status_t status, tmp_status; + cairo_status_t status; cairo_pattern_union_t pattern; cairo_pattern_union_t mask; int num_rects = pixman_region_num_rects (trap_region); + unsigned int clip_serial; if (num_rects == 0) return CAIRO_STATUS_SUCCESS; if (num_rects > 1) { - status = _cairo_surface_set_clip_region (dst, trap_region); - if (!CAIRO_OK (status)) + + if (gstate->clip.mode != CAIRO_CLIP_MODE_REGION) + return CAIRO_INT_STATUS_UNSUPPORTED; + + clip_serial = _cairo_surface_allocate_clip_serial (gstate->target); + status = _cairo_surface_set_clip_region (gstate->target, + trap_region, + clip_serial); + if (status) return status; } @@ -1162,8 +1180,8 @@ _composite_trap_region (cairo_gstate_t *gstate, gstate->clip.surface ? &mask.base : NULL, dst, extents->x, extents->y, - extents->x - (gstate->clip.surface ? gstate->clip.rect.x : 0), - extents->y - (gstate->clip.surface ? gstate->clip.rect.y : 0), + extents->x - (gstate->clip.surface ? gstate->clip.surface_rect.x : 0), + extents->y - (gstate->clip.surface ? gstate->clip.surface_rect.y : 0), extents->x, extents->y, extents->width, extents->height); @@ -1171,12 +1189,6 @@ _composite_trap_region (cairo_gstate_t *gstate, if (gstate->clip.surface) _cairo_pattern_fini (&mask.base); - if (num_rects > 1) { - tmp_status = _cairo_surface_set_clip_region (dst, gstate->clip.region); - if (!CAIRO_OK (tmp_status)) - status = tmp_status; - } - return status; } @@ -1250,11 +1262,11 @@ _composite_traps_intermediate_surface (cairo_gstate_t *gstate, traps->num_traps); _cairo_pattern_fini (&pattern.base); - if (!CAIRO_OK (status)) + if (status) goto out; status = _cairo_gstate_combine_clip_surface (gstate, intermediate, extents); - if (!CAIRO_OK (status)) + if (status) goto out; _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); @@ -1364,11 +1376,11 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, if (traps->num_traps == 0) return CAIRO_STATUS_SUCCESS; - if (gstate->surface == NULL) + if (gstate->target == NULL) return CAIRO_STATUS_NO_TARGET_SURFACE; status = _cairo_traps_extract_region (traps, &trap_region); - if (!CAIRO_OK (status)) + if (status) return status; if (trap_region) @@ -1376,7 +1388,7 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, else status = _clip_and_compute_extents_arbitrary (gstate, traps, &extents); - if (!CAIRO_OK (status)) + if (status) goto out; if (_cairo_rectangle_empty (&extents)) @@ -1405,16 +1417,23 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, /* Solid rectangles are handled specially */ status = _composite_trap_region_solid (gstate, (cairo_solid_pattern_t *)src, operator, dst, trap_region); - } else if (trap_region && pixman_region_num_rects (trap_region) <= 1) { - /* For a simple rectangle, we can just use composite(), for more - * rectangles, we'd have to set a clip region. That might still - * be a win, but it's less obvious. (Depends on the backend) - */ - status = _composite_trap_region (gstate, src, operator, dst, - trap_region, &extents); } else { - status = _composite_traps (gstate, src, operator, - dst, traps, &extents); + if (trap_region) { + /* For a simple rectangle, we can just use composite(), for more + * rectangles, we have to set a clip region. The cost of rasterizing + * trapezoids is pretty high for most backends currently, so it's + * worthwhile even if a region is needed. + */ + status = _composite_trap_region (gstate, src, operator, dst, + trap_region, &extents); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + goto out; + + /* If a clip regions aren't supported, fall through */ + } + + status = _composite_traps (gstate, src, operator, + dst, traps, &extents); } } @@ -1431,13 +1450,19 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) cairo_status_t status; cairo_traps_t traps; - if (gstate->surface->level != gstate->surface_level) - return CAIRO_STATUS_BAD_NESTING; + if (gstate->source->status) + return gstate->source->status; + + status = _cairo_gstate_set_clip (gstate); + if (status) + return status; status = _cairo_surface_fill_path (gstate->operator, gstate->source, - gstate->surface, - path); + gstate->target, + path, + gstate->fill_rule, + gstate->tolerance); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; @@ -1453,7 +1478,7 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) _cairo_gstate_clip_and_composite_trapezoids (gstate, gstate->source, gstate->operator, - gstate->surface, + gstate->target, &traps); _cairo_traps_fini (&traps); @@ -1490,19 +1515,19 @@ BAIL: cairo_status_t _cairo_gstate_copy_page (cairo_gstate_t *gstate) { - if (gstate->surface == NULL) + if (gstate->target == NULL) return CAIRO_STATUS_NO_TARGET_SURFACE; - return _cairo_surface_copy_page (gstate->surface); + return _cairo_surface_copy_page (gstate->target); } cairo_status_t _cairo_gstate_show_page (cairo_gstate_t *gstate) { - if (gstate->surface == NULL) + if (gstate->target == NULL) return CAIRO_STATUS_NO_TARGET_SURFACE; - return _cairo_surface_show_page (gstate->surface); + return _cairo_surface_show_page (gstate->target); } cairo_status_t @@ -1574,9 +1599,6 @@ BAIL: cairo_status_t _cairo_gstate_reset_clip (cairo_gstate_t *gstate) { - if (gstate->surface->level != gstate->surface_level) - return CAIRO_STATUS_BAD_NESTING; - /* destroy any existing clip-region artifacts */ if (gstate->clip.surface) cairo_surface_destroy (gstate->clip.surface); @@ -1586,109 +1608,213 @@ _cairo_gstate_reset_clip (cairo_gstate_t *gstate) pixman_region_destroy (gstate->clip.region); gstate->clip.region = NULL; - /* reset the surface's clip to the whole surface */ - if (gstate->surface) - _cairo_surface_set_clip_region (gstate->surface, - gstate->clip.region); + if (gstate->clip.path) + _cairo_clip_path_destroy (gstate->clip.path); + gstate->clip.path = NULL; + gstate->clip.serial = 0; + return CAIRO_STATUS_SUCCESS; } -cairo_status_t -_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path) +static cairo_status_t +_cairo_gstate_intersect_clip_path (cairo_gstate_t *gstate, + cairo_path_fixed_t *path) { + cairo_clip_path_t *clip_path; cairo_status_t status; - cairo_pattern_union_t pattern; - cairo_traps_t traps; - cairo_box_t extents; - pixman_region16_t *region; - if (gstate->surface->level != gstate->surface_level) - return CAIRO_STATUS_BAD_NESTING; - - /* Fill the clip region as traps. */ + if (gstate->clip.mode != CAIRO_CLIP_MODE_PATH) + return CAIRO_INT_STATUS_UNSUPPORTED; - _cairo_traps_init (&traps); - status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps); - if (!CAIRO_OK (status)) { - _cairo_traps_fini (&traps); + clip_path = malloc (sizeof (cairo_clip_path_t)); + if (clip_path == NULL) + return CAIRO_STATUS_NO_MEMORY; + + status = _cairo_path_fixed_init_copy (&clip_path->path, path); + if (status) return status; - } - /* Check to see if we can represent these traps as a PixRegion. */ + clip_path->ref_count = 1; + clip_path->fill_rule = gstate->fill_rule; + clip_path->tolerance = gstate->tolerance; + clip_path->prev = gstate->clip.path; + gstate->clip.path = clip_path; + gstate->clip.serial = _cairo_surface_allocate_clip_serial (gstate->target); - status = _cairo_traps_extract_region (&traps, ®ion); - if (!CAIRO_OK (status)) { - _cairo_traps_fini (&traps); - return status; - } + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_clip_path_reference (cairo_clip_path_t *clip_path) +{ + if (clip_path == NULL) + return; + + clip_path->ref_count++; +} + +static void +_cairo_clip_path_destroy (cairo_clip_path_t *clip_path) +{ + if (clip_path == NULL) + return; + + clip_path->ref_count--; + if (clip_path->ref_count) + return; + + _cairo_path_fixed_fini (&clip_path->path); + _cairo_clip_path_destroy (clip_path->prev); + free (clip_path); +} + +static cairo_status_t +_cairo_gstate_intersect_clip_region (cairo_gstate_t *gstate, + cairo_traps_t *traps) +{ + pixman_region16_t *region; + cairo_status_t status; + + if (gstate->clip.mode != CAIRO_CLIP_MODE_REGION) + return CAIRO_INT_STATUS_UNSUPPORTED; - if (region) { - status = CAIRO_STATUS_SUCCESS; - - if (gstate->clip.region == NULL) { - gstate->clip.region = region; - } else { - pixman_region16_t *intersection = pixman_region_create(); - - if (pixman_region_intersect (intersection, - gstate->clip.region, region) - == PIXMAN_REGION_STATUS_SUCCESS) { - pixman_region_destroy (gstate->clip.region); - gstate->clip.region = intersection; - } else { - status = CAIRO_STATUS_NO_MEMORY; - } - pixman_region_destroy (region); - } - - if (CAIRO_OK (status)) - status = _cairo_surface_set_clip_region (gstate->surface, - gstate->clip.region); + status = _cairo_traps_extract_region (traps, ®ion); + if (status) + return status; - if (status != CAIRO_INT_STATUS_UNSUPPORTED) { - _cairo_traps_fini (&traps); - return status; - } + if (region == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; - /* Fall through as status == CAIRO_INT_STATUS_UNSUPPORTED - means that backend doesn't support clipping regions and - mask surface clipping should be used instead. */ + status = CAIRO_STATUS_SUCCESS; + if (gstate->clip.region == NULL) { + gstate->clip.region = region; + } else { + pixman_region16_t *intersection = pixman_region_create(); + + if (pixman_region_intersect (intersection, + gstate->clip.region, region) + == PIXMAN_REGION_STATUS_SUCCESS) { + pixman_region_destroy (gstate->clip.region); + gstate->clip.region = intersection; + } else { + status = CAIRO_STATUS_NO_MEMORY; + } + pixman_region_destroy (region); } + gstate->clip.serial = _cairo_surface_allocate_clip_serial (gstate->target); + return status; +} - /* Otherwise represent the clip as a mask surface. */ - - if (gstate->clip.surface == NULL) { - _cairo_traps_extents (&traps, &extents); - _cairo_box_round_to_rectangle (&extents, &gstate->clip.rect); - gstate->clip.surface = - _cairo_surface_create_similar_solid (gstate->surface, - CAIRO_FORMAT_A8, - gstate->clip.rect.width, - gstate->clip.rect.height, - CAIRO_COLOR_WHITE); - if (gstate->clip.surface == NULL) - return CAIRO_STATUS_NO_MEMORY; - } +static cairo_status_t +_cairo_gstate_intersect_clip_mask (cairo_gstate_t *gstate, + cairo_traps_t *traps) +{ + cairo_pattern_union_t pattern; + cairo_box_t extents; + cairo_rectangle_t surface_rect; + cairo_surface_t *surface; + cairo_status_t status; + + /* Represent the clip as a mask surface. We create a new surface + * the size of the intersection of the old mask surface and the + * extents of the new clip path. */ + + _cairo_traps_extents (traps, &extents); + _cairo_box_round_to_rectangle (&extents, &surface_rect); + + if (gstate->clip.surface != NULL) + _cairo_rectangle_intersect (&surface_rect, &gstate->clip.surface_rect); - translate_traps (&traps, -gstate->clip.rect.x, -gstate->clip.rect.y); + surface = _cairo_surface_create_similar_solid (gstate->target, + CAIRO_FORMAT_A8, + surface_rect.width, + surface_rect.height, + CAIRO_COLOR_WHITE); + if (surface == NULL) + return CAIRO_STATUS_NO_MEMORY; + + /* Render the new clipping path into the new mask surface. */ + + translate_traps (traps, -surface_rect.x, -surface_rect.y); _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE); status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN, &pattern.base, - gstate->clip.surface, + surface, 0, 0, 0, 0, - gstate->clip.rect.width, - gstate->clip.rect.height, - traps.traps, - traps.num_traps); + surface_rect.width, + surface_rect.height, + traps->traps, + traps->num_traps); _cairo_pattern_fini (&pattern.base); + + if (status) { + cairo_surface_destroy (surface); + return status; + } + + /* If there was a clip surface already, combine it with the new + * mask surface using the IN operator, so we get the intersection + * of the old and new clipping paths. */ + + if (gstate->clip.surface != NULL) { + _cairo_pattern_init_for_surface (&pattern.surface, gstate->clip.surface); + + status = _cairo_surface_composite (CAIRO_OPERATOR_IN, + &pattern.base, + NULL, + surface, + surface_rect.x - gstate->clip.surface_rect.x, + surface_rect.y - gstate->clip.surface_rect.y, + 0, 0, + 0, 0, + surface_rect.width, + surface_rect.height); + + _cairo_pattern_fini (&pattern.base); + + if (status) { + cairo_surface_destroy (surface); + return status; + } + + cairo_surface_destroy (gstate->clip.surface); + } + + gstate->clip.surface = surface; + gstate->clip.surface_rect = surface_rect; + + return status; +} + +cairo_status_t +_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path) +{ + cairo_status_t status; + cairo_traps_t traps; + status = _cairo_gstate_intersect_clip_path (gstate, path); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + _cairo_traps_init (&traps); + status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps); + if (status) + goto bail; + + status = _cairo_gstate_intersect_clip_region (gstate, &traps); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + goto bail; + + status = _cairo_gstate_intersect_clip_mask (gstate, &traps); + + bail: _cairo_traps_fini (&traps); - return CAIRO_STATUS_SUCCESS; + return status; } static void @@ -1969,9 +2095,13 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, cairo_box_t bbox; cairo_rectangle_t extents; - if (gstate->surface->level != gstate->surface_level) - return CAIRO_STATUS_BAD_NESTING; - + if (gstate->source->status) + return gstate->source->status; + + status = _cairo_gstate_set_clip (gstate); + if (status) + return status; + status = _cairo_gstate_ensure_font (gstate); if (status) return status; @@ -2001,7 +2131,7 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, cairo_surface_t *intermediate; cairo_surface_pattern_t intermediate_pattern; - _cairo_rectangle_intersect (&extents, &gstate->clip.rect); + _cairo_rectangle_intersect (&extents, &gstate->clip.surface_rect); /* Shortcut if empty */ if (_cairo_rectangle_empty (&extents)) { @@ -2048,8 +2178,8 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, &pattern.base, NULL, intermediate, - extents.x - gstate->clip.rect.x, - extents.y - gstate->clip.rect.y, + extents.x - gstate->clip.surface_rect.x, + extents.y - gstate->clip.surface_rect.y, 0, 0, 0, 0, extents.width, extents.height); @@ -2066,7 +2196,7 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, status = _cairo_surface_composite (gstate->operator, &pattern.base, &intermediate_pattern.base, - gstate->surface, + gstate->target, extents.x, extents.y, 0, 0, extents.x, extents.y, @@ -2086,7 +2216,7 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, status = _cairo_scaled_font_show_glyphs (gstate->scaled_font, gstate->operator, &pattern.base, - gstate->surface, + gstate->target, extents.x, extents.y, extents.x, extents.y, extents.width, extents.height, diff --git a/src/cairo-hash.c b/src/cairo-hash.c index e95894960..e7547bc29 100644 --- a/src/cairo-hash.c +++ b/src/cairo-hash.c @@ -182,19 +182,25 @@ _cache_lookup (cairo_cache_t *cache, { /* We are looking up an exact entry. */ if (*probe == NULL) + { /* Found an empty spot, there can't be a match */ break; + } else if (*probe != DEAD_ENTRY && (*probe)->hashcode == hash && predicate (cache, key, *probe)) + { return probe; + } } else { /* We are just looking for a free slot. */ if (*probe == NULL || *probe == DEAD_ENTRY) + { return probe; + } } if (step == 0) { @@ -339,7 +345,6 @@ _cairo_cache_init (cairo_cache_t *cache, if (cache != NULL){ cache->arrangement = &cache_arrangements[0]; - cache->refcount = 1; cache->max_memory = max_memory; cache->used_memory = 0; cache->live_entries = 0; @@ -362,31 +367,20 @@ _cairo_cache_init (cairo_cache_t *cache, } void -_cairo_cache_reference (cairo_cache_t *cache) -{ - _cache_sane_state (cache); - cache->refcount++; -} - -void _cairo_cache_destroy (cairo_cache_t *cache) { unsigned long i; - if (cache != NULL) { + if (cache == NULL) + return; - _cache_sane_state (cache); + _cache_sane_state (cache); - if (--cache->refcount > 0) - return; - - for (i = 0; i < cache->arrangement->size; ++i) { - _entry_destroy (cache, i); - } + for (i = 0; i < cache->arrangement->size; ++i) + _entry_destroy (cache, i); - free (cache->entries); - cache->entries = NULL; - cache->backend->destroy_cache (cache); - } + free (cache->entries); + cache->entries = NULL; + cache->backend->destroy_cache (cache); } cairo_status_t diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index 19dc7b611..255cd0c43 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -259,7 +259,6 @@ cairo_image_surface_get_height (cairo_surface_t *surface) static cairo_surface_t * _cairo_image_surface_create_similar (void *abstract_src, cairo_format_t format, - int drawable, int width, int height) { @@ -352,7 +351,7 @@ _cairo_image_surface_clone_similar (void *abstract_surface, return CAIRO_INT_STATUS_UNSUPPORTED; } -cairo_status_t +static cairo_status_t _cairo_image_surface_set_matrix (cairo_image_surface_t *surface, const cairo_matrix_t *matrix) { @@ -375,7 +374,7 @@ _cairo_image_surface_set_matrix (cairo_image_surface_t *surface, return CAIRO_STATUS_SUCCESS; } -cairo_status_t +static cairo_status_t _cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t filter) { pixman_filter_t pixman_filter; @@ -405,7 +404,7 @@ _cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t return CAIRO_STATUS_SUCCESS; } -cairo_status_t +static cairo_status_t _cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat) { pixman_image_set_repeat (surface->pixman_image, repeat); @@ -518,12 +517,12 @@ _cairo_image_surface_composite (cairo_operator_t operator, return status; status = _cairo_image_surface_set_attributes (src, &src_attr); - if (CAIRO_OK (status)) + if (status == CAIRO_STATUS_SUCCESS) { if (mask) { status = _cairo_image_surface_set_attributes (mask, &mask_attr); - if (CAIRO_OK (status)) + if (status == CAIRO_STATUS_SUCCESS) pixman_composite (_pixman_operator (operator), src->pixman_image, mask->pixman_image, @@ -621,7 +620,7 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t operator, /* XXX: The pixman_trapezoid_t cast is evil and needs to go away * somehow. */ status = _cairo_image_surface_set_attributes (src, &attributes); - if (CAIRO_OK (status)) + if (status == CAIRO_STATUS_SUCCESS) pixman_composite_trapezoids (_pixman_operator (operator), src->pixman_image, dst->pixman_image, @@ -714,6 +713,7 @@ static const cairo_surface_backend_t cairo_image_surface_backend = { NULL, /* copy_page */ NULL, /* show_page */ _cairo_image_abstract_surface_set_clip_region, + NULL, /* intersect_clip_path */ _cairo_image_abstract_surface_get_extents, NULL /* show_glyphs */ }; diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c index 82ec0dbb7..98feb5714 100644 --- a/src/cairo-matrix.c +++ b/src/cairo-matrix.c @@ -526,7 +526,9 @@ _cairo_matrix_compute_scale_factors (const cairo_matrix_t *matrix, _cairo_matrix_compute_determinant (matrix, &det); if (det == 0) + { *sx = *sy = 0; + } else { double x = x_major != 0; @@ -560,25 +562,29 @@ _cairo_matrix_compute_scale_factors (const cairo_matrix_t *matrix, } cairo_bool_t -_cairo_matrix_is_integer_translation(const cairo_matrix_t *mat, +_cairo_matrix_is_integer_translation(const cairo_matrix_t *m, int *itx, int *ity) { - double a, b, c, d, tx, ty; - int ttx, tty; - int ok = 0; - _cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty); - ttx = _cairo_fixed_from_double (tx); - tty = _cairo_fixed_from_double (ty); - ok = ((a == 1.0) - && (b == 0.0) - && (c == 0.0) - && (d == 1.0) - && (_cairo_fixed_is_integer(ttx)) - && (_cairo_fixed_is_integer(tty))); - if (ok) { - *itx = _cairo_fixed_integer_part(ttx); - *ity = _cairo_fixed_integer_part(tty); - return TRUE; - } - return FALSE; + cairo_bool_t is_integer_translation; + cairo_fixed_t x0_fixed, y0_fixed; + + x0_fixed = _cairo_fixed_from_double (m->x0); + y0_fixed = _cairo_fixed_from_double (m->y0); + + is_integer_translation = ((m->xx == 1.0) && + (m->yx == 0.0) && + (m->xy == 0.0) && + (m->yy == 1.0) && + (_cairo_fixed_is_integer(x0_fixed)) && + (_cairo_fixed_is_integer(y0_fixed))); + + if (! is_integer_translation) + return FALSE; + + if (itx) + *itx = _cairo_fixed_integer_part(x0_fixed); + if (ity) + *ity = _cairo_fixed_integer_part(y0_fixed); + + return TRUE; } diff --git a/src/cairo-path-data-private.h b/src/cairo-path-data-private.h index e47eaaef9..f7f429437 100644 --- a/src/cairo-path-data-private.h +++ b/src/cairo-path-data-private.h @@ -38,17 +38,18 @@ #include "cairoint.h" -extern cairo_path_t _cairo_path_nil; - -cairo_path_t * +cairo_private cairo_path_t * _cairo_path_data_create (cairo_path_fixed_t *path, cairo_gstate_t *gstate); -cairo_path_t * +cairo_private cairo_path_t * _cairo_path_data_create_flat (cairo_path_fixed_t *path, cairo_gstate_t *gstate); -cairo_status_t +cairo_private cairo_path_t * +_cairo_path_data_create_in_error (cairo_status_t status); + +cairo_private cairo_status_t _cairo_path_data_append_to_context (cairo_path_t *path, cairo_t *cr); diff --git a/src/cairo-path-data.c b/src/cairo-path-data.c index 95fc3bb26..519c76315 100644 --- a/src/cairo-path-data.c +++ b/src/cairo-path-data.c @@ -37,8 +37,8 @@ #include "cairo-path-fixed-private.h" #include "cairo-gstate-private.h" -cairo_path_t -_cairo_path_nil = { NULL, 0 }; +static cairo_path_t +cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 }; /* Closure for path interpretation. */ typedef struct cairo_path_data_count { @@ -105,14 +105,18 @@ _cpdc_curve_to_flatten (void *closure, status = _cairo_spline_decompose (&spline, cpdc->tolerance); if (status) - return status; + goto out; for (i=1; i < spline.num_points; i++) _cpdc_line_to (cpdc, &spline.points[i]); cpdc->current_point = *p3; - return CAIRO_STATUS_SUCCESS; + status = CAIRO_STATUS_SUCCESS; + + out: + _cairo_spline_fini (&spline); + return status; } static cairo_status_t @@ -276,14 +280,18 @@ _cpdp_curve_to_flatten (void *closure, status = _cairo_spline_decompose (&spline, cpdp->gstate->tolerance); if (status) - return status; + goto out; for (i=1; i < spline.num_points; i++) _cpdp_line_to (cpdp, &spline.points[i]); cpdp->current_point = *p3; - return CAIRO_STATUS_SUCCESS; + status = CAIRO_STATUS_SUCCESS; + + out: + _cairo_spline_fini (&spline); + return status; } static cairo_status_t @@ -339,7 +347,7 @@ _cairo_path_data_create_real (cairo_path_fixed_t *path_fixed, path = malloc (sizeof (cairo_path_t)); if (path == NULL) - return &_cairo_path_nil; + return &cairo_path_nil; path->num_data = _cairo_path_data_count (path, path_fixed, gstate->tolerance, flatten); @@ -347,23 +355,56 @@ _cairo_path_data_create_real (cairo_path_fixed_t *path_fixed, path->data = malloc (path->num_data * sizeof (cairo_path_data_t)); if (path->data == NULL) { free (path); - return &_cairo_path_nil; + return &cairo_path_nil; } + path->status = CAIRO_STATUS_SUCCESS; + _cairo_path_data_populate (path, path_fixed, gstate, flatten); return path; } +/** + * cairo_path_destroy: + * @path: a path to destroy which was previously returned by either + * cairo_copy_path or cairo_copy_path_flat. + * + * Immediately releases all memory associated with @path. After a call + * to cairo_path_destroy() the @path pointer is no longer valid and + * should not be used further. + * + * NOTE: cairo_path_destroy function should only be called with a + * pointer to a #cairo_path_t returned by a cairo function. Any path + * that is created manually (ie. outside of cairo) should be destroyed + * manually as well. + **/ void cairo_path_destroy (cairo_path_t *path) { + if (path == NULL || path == &cairo_path_nil) + return; + free (path->data); path->num_data = 0; free (path); } +/** + * _cairo_path_data_create: + * @path: a fixed-point, device-space path to be converted and copied + * @gstate: the current graphics state + * + * Creates a user-space #cairo_path_t copy of the given device-space + * @path. The @gstate parameter provides the inverse CTM for the + * conversion. + * + * Return value: the new copy of the path. If there is insufficient + * memory a pointer to a special static cairo_path_nil will be + * returned instead with status==CAIRO_STATUS_NO_MEMORY and + * data==NULL. + **/ cairo_path_t * _cairo_path_data_create (cairo_path_fixed_t *path, cairo_gstate_t *gstate) @@ -371,6 +412,21 @@ _cairo_path_data_create (cairo_path_fixed_t *path, return _cairo_path_data_create_real (path, gstate, FALSE); } +/** + * _cairo_path_data_create_flat: + * @path: a fixed-point, device-space path to be flattened, converted and copied + * @gstate: the current graphics state + * + * Creates a flattened, user-space #cairo_path_t copy of the given + * device-space @path. The @gstate parameter provide the inverse CTM + * for the conversion, as well as the tolerance value to control the + * accuracy of the flattening. + * + * Return value: the flattened copy of the path. If there is insufficient + * memory a pointer to a special static cairo_path_nil will be + * returned instead with status==CAIRO_STATUS_NO_MEMORY and + * data==NULL. + **/ cairo_path_t * _cairo_path_data_create_flat (cairo_path_fixed_t *path, cairo_gstate_t *gstate) @@ -378,6 +434,45 @@ _cairo_path_data_create_flat (cairo_path_fixed_t *path, return _cairo_path_data_create_real (path, gstate, TRUE); } +/** + * _cairo_path_data_create_in_error: + * @status: an error status + * + * Create an empty #cairo_path_t object to hold an error status. This + * is useful for propagating status values from an existing object to + * a new #cairo_path_t. + * + * Return value: a #cairo_path_t object with status of @status, NULL + * data, and 0 num_data. If there is insufficient memory a pointer to + * a special static cairo_path_nil will be returned instead with + * status==CAIRO_STATUS_NO_MEMORY rather than @status. + **/ +cairo_path_t * +_cairo_path_data_create_in_error (cairo_status_t status) +{ + cairo_path_t *path; + + path = malloc (sizeof (cairo_path_t)); + if (path == NULL) + return &cairo_path_nil; + + path->status = status; + path->data = NULL; + path->num_data = 0; + + return path; +} + +/** + * _cairo_path_data_append_to_context: + * @path: the path data to be appended + * @cr: a cairo context + * + * Append @path to the current path within @cr. + * + * Return value: CAIRO_STATUS_INVALID_PATH_DATA if the data in @path + * is invalid, and CAIRO_STATUS_SUCCESS otherwise. + **/ cairo_status_t _cairo_path_data_append_to_context (cairo_path_t *path, cairo_t *cr) diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 1746b6b2a..cd099fdd2 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -50,20 +50,67 @@ typedef struct _cairo_shader_op { ((unsigned char) \ ((((unsigned char) (c1)) * (int) ((unsigned char) (c2))) / 0xff)) +static const cairo_solid_pattern_t cairo_solid_pattern_nil = { + { CAIRO_PATTERN_SOLID, /* type */ + (unsigned int)-1, /* ref_count */ + CAIRO_STATUS_NO_MEMORY, /* status */ + { 1., 0., 0., 1., 0., 0., }, /* matrix */ + CAIRO_FILTER_DEFAULT, /* filter */ + CAIRO_EXTEND_DEFAULT }, /* extend */ + { 0.0, 0.0, 0.0, 1.0, /* solid black */ + 0x0, 0x0, 0x0, 0xffff } +}; + +static const cairo_surface_pattern_t cairo_surface_pattern_nil = { + { CAIRO_PATTERN_SURFACE, /* type */ + (unsigned int)-1, /* ref_count */ + CAIRO_STATUS_NO_MEMORY, /* status */ + { 1., 0., 0., 1., 0., 0., }, /* matrix */ + CAIRO_FILTER_DEFAULT, /* filter */ + CAIRO_EXTEND_DEFAULT }, /* extend */ + NULL /* surface */ +}; + +static const cairo_linear_pattern_t cairo_linear_pattern_nil = { + { { CAIRO_PATTERN_LINEAR, /* type */ + (unsigned int)-1, /* ref_count */ + CAIRO_STATUS_NO_MEMORY, /* status */ + { 1., 0., 0., 1., 0., 0., }, /* matrix */ + CAIRO_FILTER_DEFAULT, /* filter */ + CAIRO_EXTEND_DEFAULT }, /* extend */ + NULL, /* stops */ + 0 }, /* n_stops */ + { 0., 0. }, { 1.0, 1.0 } /* point0, point1 */ +}; + +static const cairo_radial_pattern_t cairo_radial_pattern_nil = { + { { CAIRO_PATTERN_RADIAL, /* type */ + (unsigned int)-1, /* ref_count */ + CAIRO_STATUS_NO_MEMORY, /* status */ + { 1., 0., 0., 1., 0., 0., }, /* matrix */ + CAIRO_FILTER_DEFAULT, /* filter */ + CAIRO_EXTEND_DEFAULT }, /* extend */ + NULL, /* stops */ + 0 }, /* n_stops */ + { 0., 0. }, { 0.0, 0.0 }, /* center0, center1 */ + 1.0, 1.0, /* radius0, radius1 */ +}; + static void _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type) { pattern->type = type; pattern->ref_count = 1; + pattern->status = CAIRO_STATUS_SUCCESS; pattern->extend = CAIRO_EXTEND_DEFAULT; pattern->filter = CAIRO_FILTER_DEFAULT; cairo_matrix_init_identity (&pattern->matrix); } -static cairo_status_t -_cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern, - cairo_gradient_pattern_t *other) +static void +_cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern, + const cairo_gradient_pattern_t *other) { if (other->base.type == CAIRO_PATTERN_LINEAR) { @@ -83,18 +130,22 @@ _cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern, if (other->n_stops) { pattern->stops = malloc (other->n_stops * sizeof (cairo_color_stop_t)); - if (!pattern->stops) - return CAIRO_STATUS_NO_MEMORY; + if (!pattern->stops) { + if (other->base.type == CAIRO_PATTERN_LINEAR) + _cairo_gradient_pattern_init_copy (pattern, &cairo_linear_pattern_nil.base); + else + _cairo_gradient_pattern_init_copy (pattern, &cairo_radial_pattern_nil.base); + return; + } memcpy (pattern->stops, other->stops, other->n_stops * sizeof (cairo_color_stop_t)); } - - return CAIRO_STATUS_SUCCESS; } -cairo_status_t -_cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other) +void +_cairo_pattern_init_copy (cairo_pattern_t *pattern, + const cairo_pattern_t *other) { switch (other->type) { case CAIRO_PATTERN_SOLID: { @@ -114,17 +165,12 @@ _cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other) case CAIRO_PATTERN_RADIAL: { cairo_gradient_pattern_t *dst = (cairo_gradient_pattern_t *) pattern; cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) other; - cairo_status_t status; - status = _cairo_gradient_pattern_init_copy (dst, src); - if (status) - return status; + _cairo_gradient_pattern_init_copy (dst, src); } break; } pattern->ref_count = 1; - - return CAIRO_STATUS_SUCCESS; } void @@ -210,13 +256,44 @@ _cairo_pattern_create_solid (const cairo_color_t *color) pattern = malloc (sizeof (cairo_solid_pattern_t)); if (pattern == NULL) - return NULL; + return (cairo_pattern_t *) &cairo_solid_pattern_nil.base; _cairo_pattern_init_solid (pattern, color); return &pattern->base; } +/** + * _cairo_pattern_create_in_error: + * @status: an error status + * + * Create an empty #cairo_pattern_t object to hold an error + * status. This is useful for propagating status values from an + * existing object to a new #cairo_pattern_t. + * + * Return value: a (solid, black) #cairo_pattern_t object with status + * of @status. If there is insufficient memory a pointer to a special, + * static cairo_solid_pattern_nil will be returned instead with a + * status of CAIRO_STATUS_NO_MEMORY rather than @status. + * + * Return value: + **/ +cairo_pattern_t * +_cairo_pattern_create_in_error (cairo_status_t status) +{ + cairo_solid_pattern_t *pattern; + + pattern = malloc (sizeof (cairo_solid_pattern_t)); + if (pattern == NULL) + return (cairo_pattern_t *) &cairo_solid_pattern_nil.base; + + _cairo_pattern_init_solid (pattern, CAIRO_COLOR_BLACK); + + pattern->base.status = status; + + return &pattern->base; +} + cairo_pattern_t * cairo_pattern_create_for_surface (cairo_surface_t *surface) { @@ -224,16 +301,10 @@ cairo_pattern_create_for_surface (cairo_surface_t *surface) pattern = malloc (sizeof (cairo_surface_pattern_t)); if (pattern == NULL) - return NULL; + return (cairo_pattern_t *)&cairo_surface_pattern_nil.base; _cairo_pattern_init_for_surface (pattern, surface); - /* this will go away when we completely remove the surface attributes */ - if (surface->repeat) - pattern->base.extend = CAIRO_EXTEND_REPEAT; - else - pattern->base.extend = CAIRO_EXTEND_DEFAULT; - return &pattern->base; } @@ -244,7 +315,7 @@ cairo_pattern_create_linear (double x0, double y0, double x1, double y1) pattern = malloc (sizeof (cairo_linear_pattern_t)); if (pattern == NULL) - return NULL; + return (cairo_pattern_t *) &cairo_linear_pattern_nil.base; _cairo_pattern_init_linear (pattern, x0, y0, x1, y1); @@ -259,7 +330,7 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0, pattern = malloc (sizeof (cairo_radial_pattern_t)); if (pattern == NULL) - return NULL; + return (cairo_pattern_t *) &cairo_radial_pattern_nil.base; _cairo_pattern_init_radial (pattern, cx0, cy0, radius0, cx1, cy1, radius1); @@ -272,15 +343,36 @@ cairo_pattern_reference (cairo_pattern_t *pattern) if (pattern == NULL) return; + if (pattern->ref_count == (unsigned int)-1) + return; + pattern->ref_count++; } +/** + * cairo_pattern_status: + * @pattern: a #cairo_pattern_t + * + * Checks whether an error has previously occurred for this + * pattern. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY + **/ +cairo_status_t +cairo_pattern_status (cairo_pattern_t *pattern) +{ + return pattern->status; +} + void cairo_pattern_destroy (cairo_pattern_t *pattern) { if (pattern == NULL) return; + if (pattern->ref_count == (unsigned int)-1) + return; + pattern->ref_count--; if (pattern->ref_count) return; @@ -289,31 +381,31 @@ cairo_pattern_destroy (cairo_pattern_t *pattern) free (pattern); } -static cairo_status_t +static void _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern, double offset, cairo_color_t *color) { cairo_color_stop_t *stop; + cairo_color_stop_t *new_stops; pattern->n_stops++; - pattern->stops = realloc (pattern->stops, - pattern->n_stops * sizeof (cairo_color_stop_t)); - if (pattern->stops == NULL) { - pattern->n_stops = 0; - - return CAIRO_STATUS_NO_MEMORY; + new_stops = realloc (pattern->stops, + pattern->n_stops * sizeof (cairo_color_stop_t)); + if (new_stops == NULL) { + pattern->base.status = CAIRO_STATUS_NO_MEMORY; + return; } + + pattern->stops = new_stops; stop = &pattern->stops[pattern->n_stops - 1]; stop->offset = _cairo_fixed_from_double (offset); stop->color = *color; - - return CAIRO_STATUS_SUCCESS; } -cairo_status_t +void cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, double offset, double red, @@ -322,11 +414,14 @@ cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, { cairo_color_t color; + if (pattern->status) + return; + if (pattern->type != CAIRO_PATTERN_LINEAR && pattern->type != CAIRO_PATTERN_RADIAL) { - /* XXX: CAIRO_STATUS_INVALID_PATTERN? */ - return CAIRO_STATUS_SUCCESS; + pattern->status = CAIRO_STATUS_PATTERN_TYPE_MISMATCH; + return; } _cairo_restrict_value (&offset, 0.0, 1.0); @@ -335,12 +430,12 @@ cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, _cairo_restrict_value (&blue, 0.0, 1.0); _cairo_color_init_rgb (&color, red, green, blue); - return _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern, - offset, - &color); + _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern, + offset, + &color); } -cairo_status_t +void cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, double offset, double red, @@ -350,11 +445,14 @@ cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, { cairo_color_t color; + if (pattern->status) + return; + if (pattern->type != CAIRO_PATTERN_LINEAR && pattern->type != CAIRO_PATTERN_RADIAL) { - /* XXX: CAIRO_STATUS_INVALID_PATTERN? */ - return CAIRO_STATUS_SUCCESS; + pattern->status = CAIRO_STATUS_PATTERN_TYPE_MISMATCH; + return; } _cairo_restrict_value (&offset, 0.0, 1.0); @@ -364,34 +462,34 @@ cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, _cairo_restrict_value (&alpha, 0.0, 1.0); _cairo_color_init_rgba (&color, red, green, blue, alpha); - return _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern, - offset, - &color); + _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern, + offset, + &color); } -cairo_status_t +void cairo_pattern_set_matrix (cairo_pattern_t *pattern, const cairo_matrix_t *matrix) { - pattern->matrix = *matrix; + if (pattern->status) + return; - return CAIRO_STATUS_SUCCESS; + pattern->matrix = *matrix; } -cairo_status_t +void cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix) { *matrix = pattern->matrix; - - return CAIRO_STATUS_SUCCESS; } -cairo_status_t +void cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter) { - pattern->filter = filter; + if (pattern->status) + return; - return CAIRO_STATUS_SUCCESS; + pattern->filter = filter; } cairo_filter_t @@ -400,12 +498,13 @@ cairo_pattern_get_filter (cairo_pattern_t *pattern) return pattern->filter; } -cairo_status_t +void cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend) { - pattern->extend = extend; + if (pattern->status) + return; - return CAIRO_STATUS_SUCCESS; + pattern->extend = extend; } cairo_extend_t @@ -418,6 +517,8 @@ void _cairo_pattern_transform (cairo_pattern_t *pattern, const cairo_matrix_t *ctm_inverse) { + assert (pattern->status == CAIRO_STATUS_SUCCESS); + cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix); } @@ -868,8 +969,9 @@ _cairo_image_data_set_radial (cairo_radial_pattern_t *pattern, c0_x = y_x + c0_y; factor = (c0_e - r0) / (c0_x - r0); - } else + } else { factor = -r0; + } } _cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++); @@ -960,7 +1062,6 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern, attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE; attr->filter = CAIRO_FILTER_NEAREST; attr->acquired = FALSE; - attr->clip_saved = FALSE; return status; } @@ -988,7 +1089,6 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern, attribs->extend = CAIRO_EXTEND_REPEAT; attribs->filter = CAIRO_FILTER_NEAREST; attribs->acquired = FALSE; - attribs->clip_saved = FALSE; return CAIRO_STATUS_SUCCESS; } @@ -1015,7 +1115,7 @@ _cairo_pattern_is_opaque_solid (cairo_pattern_t *pattern) solid = (cairo_solid_pattern_t *) pattern; - return (solid->color.alpha >= ((double)0xff00 / (double)0xffff)); + return CAIRO_ALPHA_IS_OPAQUE (solid->color.alpha); } static cairo_int_status_t @@ -1032,35 +1132,23 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern, int tx, ty; attr->acquired = FALSE; - attr->clip_saved = FALSE; if (_cairo_surface_is_image (dst)) { cairo_image_surface_t *image; - status = _cairo_surface_begin_reset_clip (pattern->surface); - if (!CAIRO_OK (status)) - return status; - status = _cairo_surface_acquire_source_image (pattern->surface, &image, &attr->extra); - if (!CAIRO_OK (status)) + if (status) return status; - _cairo_surface_end (pattern->surface); - *out = &image->base; attr->acquired = TRUE; } else { - status = _cairo_surface_begin_reset_clip (pattern->surface); - if (!CAIRO_OK (status)) - return status; - status = _cairo_surface_clone_similar (dst, pattern->surface, out); - _cairo_surface_end (pattern->surface); } attr->extend = pattern->base.extend; @@ -1111,6 +1199,9 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern, { cairo_status_t status; + if (pattern->status) + return pattern->status; + switch (pattern->type) { case CAIRO_PATTERN_SOLID: { cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) pattern; @@ -1144,11 +1235,13 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern, attributes); } else + { status = _cairo_pattern_acquire_surface_for_gradient (src, dst, x, y, width, height, surface_out, attributes); + } } break; case CAIRO_PATTERN_SURFACE: { cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) pattern; @@ -1162,17 +1255,6 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern, status = CAIRO_INT_STATUS_UNSUPPORTED; } - - if (CAIRO_OK (status) && (*surface_out)->clip_region) { - status = _cairo_surface_begin_reset_clip (*surface_out); - if (!CAIRO_OK (status)) { - _cairo_pattern_release_surface (dst, *surface_out, attributes); - return status; - } - - attributes->clip_saved = TRUE; - } - return status; } @@ -1189,16 +1271,16 @@ _cairo_pattern_release_surface (cairo_surface_t *dst, cairo_surface_t *surface, cairo_surface_attributes_t *attributes) { - if (attributes->clip_saved) - _cairo_surface_end (surface); - if (attributes->acquired) { _cairo_surface_release_source_image (dst, (cairo_image_surface_t *) surface, attributes->extra); - } else + } + else + { cairo_surface_destroy (surface); + } } cairo_int_status_t @@ -1219,6 +1301,11 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src, cairo_int_status_t status; cairo_pattern_union_t tmp; + if (src->status) + return src->status; + if (mask && mask->status) + return mask->status; + /* If src and mask are both solid, then the mask alpha can be * combined into src and mask can be ignored. */ @@ -1227,7 +1314,7 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src, * support RENDER-style 4-channel masks. */ if (src->type == CAIRO_PATTERN_SOLID && mask && mask->type == CAIRO_PATTERN_SOLID) - { + { cairo_color_t combined; cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src; cairo_solid_pattern_t *mask_solid = (cairo_solid_pattern_t *) mask; @@ -1238,7 +1325,9 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src, _cairo_pattern_init_solid (&tmp.solid, &combined); mask = NULL; - } else { + } + else + { _cairo_pattern_init_copy (&tmp.base, src); } diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 228c2c89a..3d65aa75e 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -126,7 +126,7 @@ struct cairo_pdf_ft_font { cairo_pdf_font_t base; ft_subset_glyph_t *glyphs; FT_Face face; - unsigned long *checksum_location; + int checksum_index; cairo_array_t output; int *parent_to_subset; cairo_status_t status; @@ -188,6 +188,7 @@ struct cairo_pdf_surface { cairo_array_t streams; cairo_array_t alphas; cairo_array_t fonts; + cairo_bool_t has_clip; }; #define DEFAULT_DPI 300 @@ -291,6 +292,9 @@ cairo_pdf_font_generate (cairo_pdf_font_t *font, static void cairo_pdf_font_destroy (cairo_pdf_font_t *font) { + if (font == NULL) + return; + font->backend->destroy (font); } @@ -378,6 +382,9 @@ cairo_pdf_ft_font_destroy (void *abstract_font) { cairo_pdf_ft_font_t *font = abstract_font; + if (font == NULL) + return; + _cairo_unscaled_font_destroy (font->base.unscaled_font); free (font->base.base_font); free (font->parent_to_subset); @@ -505,8 +512,7 @@ cairo_pdf_ft_font_write_glyf_table (cairo_pdf_ft_font_t *font, 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 { + } else { begin = be32_to_cpu (u.long_offsets[index]); end = be32_to_cpu (u.long_offsets[index + 1]); } @@ -541,9 +547,7 @@ cairo_pdf_ft_font_write_head_table (cairo_pdf_ft_font_t *font, 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); + font->checksum_index = _cairo_array_num_elements (&font->output); cairo_pdf_ft_font_write_be32 (font, 0); cairo_pdf_ft_font_write_be32 (font, head->Magic_Number); @@ -633,8 +637,7 @@ cairo_pdf_ft_font_write_loca_table (cairo_pdf_ft_font_t *font, 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 { + } else { for (i = 0; i < font->base.num_glyphs + 1; i++) cairo_pdf_ft_font_write_be32 (font, font->glyphs[i].location); } @@ -754,6 +757,7 @@ cairo_pdf_ft_font_generate (void *abstract_font, { cairo_pdf_ft_font_t *font = abstract_font; unsigned long start, end, next, checksum; + unsigned long *checksum_location; int i; font->face = _cairo_ft_unscaled_font_lock_face (font->base.unscaled_font); @@ -778,7 +782,8 @@ cairo_pdf_ft_font_generate (void *abstract_font, checksum = 0xb1b0afba - cairo_pdf_ft_font_calculate_checksum (font, 0, end); - *font->checksum_location = cpu_to_be32 (checksum); + checksum_location = _cairo_array_index (&font->output, font->checksum_index); + *checksum_location = cpu_to_be32 (checksum); *data = _cairo_array_index (&font->output, 0); *length = _cairo_array_num_elements (&font->output); @@ -985,6 +990,7 @@ _cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document, _cairo_array_init (&surface->xobjects, sizeof (cairo_pdf_resource_t)); _cairo_array_init (&surface->alphas, sizeof (double)); _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_resource_t)); + surface->has_clip = FALSE; return &surface->base; } @@ -1011,7 +1017,6 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface) static cairo_surface_t * _cairo_pdf_surface_create_similar (void *abstract_src, cairo_format_t format, - int drawable, int width, int height) { @@ -1225,7 +1230,7 @@ _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst, src = pattern->surface; status = _cairo_surface_acquire_source_image (src, &image, &image_extra); - if (!CAIRO_OK (status)) + if (status) return status; id = emit_image_data (dst->document, image); @@ -1281,7 +1286,7 @@ _cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst, src = (cairo_pdf_surface_t *) pattern->surface; - i2u = src->base.matrix; + i2u = pattern->base.matrix; cairo_matrix_invert (&i2u); cairo_matrix_scale (&i2u, 1.0 / src->width, 1.0 / src->height); @@ -1400,7 +1405,7 @@ emit_surface_pattern (cairo_pdf_surface_t *dst, } status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra); - if (!CAIRO_OK (status)) + if (status) return; _cairo_pdf_document_close_stream (document); @@ -1635,6 +1640,7 @@ intersect (cairo_line_t *line, cairo_fixed_t y) typedef struct { cairo_output_stream_t *output_stream; + cairo_bool_t has_current_point; } pdf_path_info_t; static cairo_status_t @@ -1646,6 +1652,7 @@ _cairo_pdf_path_move_to (void *closure, cairo_point_t *point) "%f %f m ", _cairo_fixed_to_double (point->x), _cairo_fixed_to_double (point->y)); + info->has_current_point = TRUE; return CAIRO_STATUS_SUCCESS; } @@ -1654,11 +1661,19 @@ static cairo_status_t _cairo_pdf_path_line_to (void *closure, cairo_point_t *point) { pdf_path_info_t *info = closure; + const char *pdf_operator; + + if (info->has_current_point) + pdf_operator = "l"; + else + pdf_operator = "m"; _cairo_output_stream_printf (info->output_stream, - "%f %f l ", + "%f %f %s ", _cairo_fixed_to_double (point->x), - _cairo_fixed_to_double (point->y)); + _cairo_fixed_to_double (point->y), + pdf_operator); + info->has_current_point = TRUE; return CAIRO_STATUS_SUCCESS; } @@ -1690,6 +1705,7 @@ _cairo_pdf_path_close_path (void *closure) _cairo_output_stream_printf (info->output_stream, "h\r\n"); + info->has_current_point = FALSE; return CAIRO_STATUS_SUCCESS; } @@ -1698,15 +1714,16 @@ static cairo_int_status_t _cairo_pdf_surface_fill_path (cairo_operator_t operator, cairo_pattern_t *pattern, void *abstract_dst, - cairo_path_fixed_t *path) + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance) { cairo_pdf_surface_t *surface = abstract_dst; cairo_pdf_document_t *document = surface->document; + const char *pdf_operator; cairo_status_t status; pdf_path_info_t info; - return CAIRO_INT_STATUS_UNSUPPORTED; - emit_pattern (surface, pattern); /* After the above switch the current stream should belong to this @@ -1715,6 +1732,7 @@ _cairo_pdf_surface_fill_path (cairo_operator_t operator, document->current_stream == surface->current_stream); info.output_stream = document->output_stream; + info.has_current_point = FALSE; status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD, @@ -1724,8 +1742,20 @@ _cairo_pdf_surface_fill_path (cairo_operator_t operator, _cairo_pdf_path_close_path, &info); + switch (fill_rule) { + case CAIRO_FILL_RULE_WINDING: + pdf_operator = "f"; + break; + case CAIRO_FILL_RULE_EVEN_ODD: + pdf_operator = "f*"; + break; + default: + ASSERT_NOT_REACHED; + } + _cairo_output_stream_printf (document->output_stream, - "f\r\n"); + "%s\r\n", + pdf_operator); return status; } @@ -1794,10 +1824,12 @@ _cairo_pdf_surface_show_page (void *abstract_surface) cairo_int_status_t status; status = _cairo_pdf_document_add_page (document, surface); - if (status == CAIRO_STATUS_SUCCESS) - _cairo_pdf_surface_clear (surface); + if (status) + return status; - return status; + _cairo_pdf_surface_clear (surface); + + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t @@ -1886,7 +1918,7 @@ _cairo_pdf_surface_show_glyphs (cairo_scaled_font_t *scaled_font, " %f %f %f %f %f %f Tm (\\%o) Tj", scaled_font->scale.xx, scaled_font->scale.yx, - scaled_font->scale.xy, + -scaled_font->scale.xy, -scaled_font->scale.yy, glyphs[i].x, glyphs[i].y, @@ -1900,6 +1932,62 @@ _cairo_pdf_surface_show_glyphs (cairo_scaled_font_t *scaled_font, return CAIRO_STATUS_SUCCESS; } +static cairo_int_status_t +_cairo_pdf_surface_intersect_clip_path (void *dst, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance) +{ + cairo_pdf_surface_t *surface = dst; + cairo_pdf_document_t *document = surface->document; + cairo_output_stream_t *output = document->output_stream; + cairo_status_t status; + pdf_path_info_t info; + const char *pdf_operator; + + _cairo_pdf_surface_ensure_stream (surface); + + if (path == NULL) { + if (surface->has_clip) + _cairo_output_stream_printf (output, "Q\r\n"); + surface->has_clip = FALSE; + return CAIRO_STATUS_SUCCESS; + } + + if (!surface->has_clip) { + _cairo_output_stream_printf (output, "q "); + surface->has_clip = TRUE; + } + + info.output_stream = document->output_stream; + info.has_current_point = FALSE; + + status = _cairo_path_fixed_interpret (path, + CAIRO_DIRECTION_FORWARD, + _cairo_pdf_path_move_to, + _cairo_pdf_path_line_to, + _cairo_pdf_path_curve_to, + _cairo_pdf_path_close_path, + &info); + + switch (fill_rule) { + case CAIRO_FILL_RULE_WINDING: + pdf_operator = "W"; + break; + case CAIRO_FILL_RULE_EVEN_ODD: + pdf_operator = "W*"; + break; + default: + ASSERT_NOT_REACHED; + } + + _cairo_output_stream_printf (document->output_stream, + "%s n\r\n", + pdf_operator); + + return status; +} + static const cairo_surface_backend_t cairo_pdf_surface_backend = { _cairo_pdf_surface_create_similar, _cairo_pdf_surface_finish, @@ -1914,6 +2002,7 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = { _cairo_pdf_surface_copy_page, _cairo_pdf_surface_show_page, NULL, /* set_clip_region */ + _cairo_pdf_surface_intersect_clip_path, _cairo_pdf_surface_get_extents, _cairo_pdf_surface_show_glyphs, _cairo_pdf_surface_fill_path @@ -2232,6 +2321,11 @@ _cairo_pdf_document_add_page (cairo_pdf_document_t *document, assert (!document->finished); + _cairo_pdf_surface_ensure_stream (surface); + + if (surface->has_clip) + _cairo_output_stream_printf (output, "Q\r\n"); + _cairo_pdf_document_close_stream (document); page_id = _cairo_pdf_document_new_object (document); diff --git a/src/cairo-png.c b/src/cairo-png.c index ecb23ca45..d7297848d 100644 --- a/src/cairo-png.c +++ b/src/cairo-png.c @@ -212,7 +212,7 @@ cairo_surface_write_to_png (cairo_surface_t *surface, status = write_png (surface, stdio_write_func, fp); - if (fclose (fp) && CAIRO_OK (status)) + if (fclose (fp) && status == CAIRO_STATUS_SUCCESS) status = CAIRO_STATUS_WRITE_ERROR; return status; @@ -226,10 +226,12 @@ struct png_write_closure_t { static void stream_write_func (png_structp png, png_bytep data, png_size_t size) { + cairo_status_t status; struct png_write_closure_t *png_closure; png_closure = png_get_io_ptr (png); - if (!CAIRO_OK (png_closure->write_func (png_closure->closure, data, size))) + status = png_closure->write_func (png_closure->closure, data, size); + if (status) png_error(png, "Write Error"); } @@ -432,10 +434,12 @@ struct png_read_closure_t { static void stream_read_func (png_structp png, png_bytep data, png_size_t size) { + cairo_status_t status; struct png_read_closure_t *png_closure; png_closure = png_get_io_ptr (png); - if (!CAIRO_OK (png_closure->read_func (png_closure->closure, data, size))) + status = png_closure->read_func (png_closure->closure, data, size); + if (status) png_error(png, "Read Error"); } diff --git a/src/cairo-private.h b/src/cairo-private.h index a43c8ef7f..7051f7ebd 100644 --- a/src/cairo-private.h +++ b/src/cairo-private.h @@ -42,10 +42,11 @@ struct _cairo { unsigned int ref_count; - cairo_gstate_t *gstate; + cairo_status_t status; + cairo_path_fixed_t path; - cairo_status_t status; + cairo_gstate_t *gstate; }; #endif /* CAIRO_PRIVATE_H */ diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index a79703e1d..dd12c2ca5 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -159,7 +159,6 @@ cairo_ps_surface_create_for_stream (cairo_write_func_t write_func, static cairo_surface_t * _cairo_ps_surface_create_similar (void *abstract_src, cairo_format_t format, - int drawable, int width, int height) { @@ -373,6 +372,7 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = { _cairo_ps_surface_copy_page, _cairo_ps_surface_show_page, _cairo_ps_surface_set_clip_region, + NULL, /* intersect_clip_path */ _cairo_ps_surface_get_extents, NULL /* show_glyphs */ }; diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index 292f5b491..566842515 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -62,7 +62,6 @@ static cairo_surface_t *_cairo_quartz_surface_create_similar(void *abstract_src, cairo_format_t format, - int drawable, int width, int height) { @@ -227,6 +226,7 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = { NULL, /* copy_page */ NULL, /* show_page */ _cairo_quartz_surface_set_clip_region, + NULL, /* intersect_clip_path */ _cairo_quartz_surface_get_extents, NULL /* show_glyphs */ }; diff --git a/src/cairo-spline.c b/src/cairo-spline.c index 5119a8e2b..60ad6c54d 100644 --- a/src/cairo-spline.c +++ b/src/cairo-spline.c @@ -64,23 +64,21 @@ _cairo_spline_init (cairo_spline_t *spline, spline->c = *c; spline->d = *d; - if (a->x != b->x || a->y != b->y) { + if (a->x != b->x || a->y != b->y) _cairo_slope_init (&spline->initial_slope, &spline->a, &spline->b); - } else if (a->x != c->x || a->y != c->y) { + else if (a->x != c->x || a->y != c->y) _cairo_slope_init (&spline->initial_slope, &spline->a, &spline->c); - } else if (a->x != d->x || a->y != d->y) { + else if (a->x != d->x || a->y != d->y) _cairo_slope_init (&spline->initial_slope, &spline->a, &spline->d); - } else { + else return CAIRO_INT_STATUS_DEGENERATE; - } - if (c->x != d->x || c->y != d->y) { + if (c->x != d->x || c->y != d->y) _cairo_slope_init (&spline->final_slope, &spline->c, &spline->d); - } else if (b->x != d->x || b->y != d->y) { + else if (b->x != d->x || b->y != d->y) _cairo_slope_init (&spline->final_slope, &spline->b, &spline->d); - } else { + else _cairo_slope_init (&spline->final_slope, &spline->a, &spline->d); - } spline->num_points = 0; spline->points_size = 0; diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 0bcf80cf8..318ee87d9 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -38,17 +38,7 @@ #include <stdlib.h> #include "cairoint.h" - -struct _cairo_surface_save { - cairo_surface_save_t *next; - pixman_region16_t *clip_region; -}; - -static cairo_status_t -_cairo_surface_set_clip_region_internal (cairo_surface_t *surface, - pixman_region16_t *region, - cairo_bool_t copy_region, - cairo_bool_t free_existing); +#include "cairo-gstate-private.h" void _cairo_surface_init (cairo_surface_t *surface, @@ -61,131 +51,23 @@ _cairo_surface_init (cairo_surface_t *surface, _cairo_user_data_array_init (&surface->user_data); - cairo_matrix_init_identity (&surface->matrix); - surface->filter = CAIRO_FILTER_GOOD; - surface->repeat = 0; - surface->device_x_offset = 0; surface->device_y_offset = 0; - surface->clip_region = NULL; - - surface->saves = NULL; - surface->level = 0; -} - -static cairo_status_t -_cairo_surface_begin_internal (cairo_surface_t *surface, - cairo_bool_t reset_clip) -{ - cairo_surface_save_t *save; - - if (surface->finished) - return CAIRO_STATUS_SURFACE_FINISHED; - - save = malloc (sizeof (cairo_surface_save_t)); - if (!save) - return CAIRO_STATUS_NO_MEMORY; - - if (surface->clip_region) { - if (reset_clip) - { - cairo_status_t status; - - save->clip_region = surface->clip_region; - status = _cairo_surface_set_clip_region_internal (surface, NULL, FALSE, FALSE); - if (!CAIRO_OK (status)) { - free (save); - return status; - } - } - else - { - save->clip_region = pixman_region_create (); - pixman_region_copy (save->clip_region, surface->clip_region); - } - } else { - save->clip_region = NULL; - } - - save->next = surface->saves; - surface->saves = save; - surface->level++; - - return CAIRO_STATUS_SUCCESS; -} - -/** - * _cairo_surface_begin: - * @surface: a #cairo_surface_t - * - * Must be called before beginning to use the surface. State - * of the surface like the clip region will be saved then restored - * on the matching call _cairo_surface_end(). - */ -cairo_private cairo_status_t -_cairo_surface_begin (cairo_surface_t *surface) -{ - return _cairo_surface_begin_internal (surface, FALSE); -} - -/** - * _cairo_surface_begin_reset_clip: - * @surface: a #cairo_surface_t - * - * Must be called before beginning to use the surface. State - * of the surface like the clip region will be saved then restored - * on the matching call _cairo_surface_end(). - * - * After the state is saved, the clip region is cleared. This - * combination of operations is a little artificial; the caller could - * simply call _cairo_surface_set_clip_region (surface, NULL); after - * _cairo_surface_save(). Combining the two saves a copy of the clip - * region, and also simplifies error handling for the caller. - **/ -cairo_private cairo_status_t -_cairo_surface_begin_reset_clip (cairo_surface_t *surface) -{ - return _cairo_surface_begin_internal (surface, TRUE); -} - -/** - * _cairo_surface_end: - * @surface: a #cairo_surface_t - * - * Restores any state saved by _cairo_surface_begin() - **/ -cairo_private cairo_status_t -_cairo_surface_end (cairo_surface_t *surface) -{ - cairo_surface_save_t *save; - pixman_region16_t *clip_region; - - if (!surface->saves) - return CAIRO_STATUS_BAD_NESTING; - - save = surface->saves; - surface->saves = save->next; - surface->level--; - - clip_region = save->clip_region; - free (save); - - return _cairo_surface_set_clip_region_internal (surface, clip_region, FALSE, TRUE); + surface->next_clip_serial = 0; + surface->current_clip_serial = 0; } cairo_surface_t * _cairo_surface_create_similar_scratch (cairo_surface_t *other, cairo_format_t format, - int drawable, int width, int height) { if (other == NULL) return NULL; - return other->backend->create_similar (other, format, drawable, - width, height); + return other->backend->create_similar (other, format, width, height); } cairo_surface_t * @@ -212,7 +94,7 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other, cairo_status_t status; cairo_surface_t *surface; - surface = _cairo_surface_create_similar_scratch (other, format, 1, + surface = _cairo_surface_create_similar_scratch (other, format, width, height); if (surface == NULL) @@ -229,6 +111,17 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other, return surface; } +cairo_clip_mode_t +_cairo_surface_get_clip_mode (cairo_surface_t *surface) +{ + if (surface->backend->intersect_clip_path != NULL) + return CAIRO_CLIP_MODE_PATH; + else if (surface->backend->set_clip_region != NULL) + return CAIRO_CLIP_MODE_REGION; + else + return CAIRO_CLIP_MODE_MASK; +} + void cairo_surface_reference (cairo_surface_t *surface) { @@ -250,7 +143,7 @@ cairo_surface_destroy (cairo_surface_t *surface) cairo_surface_finish (surface); - _cairo_user_data_array_destroy (&surface->user_data); + _cairo_user_data_array_fini (&surface->user_data); free (surface); } @@ -286,14 +179,6 @@ cairo_surface_finish (cairo_surface_t *surface) if (surface->finished) return CAIRO_STATUS_SURFACE_FINISHED; - if (surface->saves) - return CAIRO_STATUS_BAD_NESTING; - - if (surface->clip_region) { - pixman_region_destroy (surface->clip_region); - surface->clip_region = NULL; - } - if (surface->backend->finish) { status = surface->backend->finish (surface); if (status) @@ -521,7 +406,7 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, if (surface->backend->clone_similar) { status = surface->backend->clone_similar (surface, src, clone_out); if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; + return status; } status = _cairo_surface_acquire_source_image (src, &image, &image_extra); @@ -592,7 +477,7 @@ _fallback_composite (cairo_operator_t operator, cairo_status_t status; status = _fallback_init (&state, dst, dst_x, dst_y, width, height); - if (!CAIRO_OK (status) || !state.image) + if (status || !state.image) return status; state.image->base.backend->composite (operator, src, mask, @@ -704,7 +589,7 @@ _fallback_fill_rectangles (cairo_surface_t *surface, } status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1); - if (!CAIRO_OK (status) || !state.image) + if (status || !state.image) return status; /* If the fetched image isn't at 0,0, we need to offset the rectangles */ @@ -766,13 +651,16 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface, } cairo_private cairo_int_status_t -_cairo_surface_fill_path (cairo_operator_t operator, - cairo_pattern_t *pattern, - cairo_surface_t *dst, - cairo_path_fixed_t *path) +_cairo_surface_fill_path (cairo_operator_t operator, + cairo_pattern_t *pattern, + cairo_surface_t *dst, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance) { if (dst->backend->fill_path) - return dst->backend->fill_path (operator, pattern, dst, path); + return dst->backend->fill_path (operator, pattern, dst, path, + fill_rule, tolerance); else return CAIRO_INT_STATUS_UNSUPPORTED; } @@ -797,7 +685,7 @@ _fallback_composite_trapezoids (cairo_operator_t operator, int i; status = _fallback_init (&state, dst, dst_x, dst_y, width, height); - if (!CAIRO_OK (status) || !state.image) + if (status || !state.image) return status; /* If the destination image isn't at 0,0, we need to offset the trapezoids */ @@ -907,62 +795,180 @@ _cairo_surface_show_page (cairo_surface_t *surface) return surface->backend->show_page (surface); } -static cairo_status_t -_cairo_surface_set_clip_region_internal (cairo_surface_t *surface, - pixman_region16_t *region, - cairo_bool_t copy_region, - cairo_bool_t free_existing) +/** + * _cairo_surface_get_current_clip_serial: + * @surface: the #cairo_surface_t to return the serial number for + * + * Returns the serial number associated with the current + * clip in the surface. All gstate functions must + * verify that the correct clip is set in the surface before + * invoking any surface drawing function + */ +cairo_private unsigned int +_cairo_surface_get_current_clip_serial (cairo_surface_t *surface) +{ + return surface->current_clip_serial; +} + +/** + * _cairo_surface_allocate_clip_serial: + * @surface: the #cairo_surface_t to allocate a serial number from + * + * Each surface has a separate set of clipping serial numbers, + * and this function allocates one from the specified surface. + * As zero is reserved for the special no-clipping case, + * this function will not return that. + */ +cairo_private unsigned int +_cairo_surface_allocate_clip_serial (cairo_surface_t *surface) +{ + unsigned int serial; + + if ((serial = ++(surface->next_clip_serial)) == 0) + serial = ++(surface->next_clip_serial); + return serial; +} + +/** + * _cairo_surface_reset_clip: + * @surface: the #cairo_surface_t to reset the clip on + * + * This function sets the clipping for the surface to + * None, which is to say that drawing is entirely + * unclipped. It also sets the clip serial number + * to zero. + */ +cairo_private cairo_status_t +_cairo_surface_reset_clip (cairo_surface_t *surface) { + cairo_status_t status; + if (surface->finished) return CAIRO_STATUS_SURFACE_FINISHED; - - if (region == surface->clip_region) - return CAIRO_STATUS_SUCCESS; - if (surface->backend->set_clip_region == NULL) - return CAIRO_INT_STATUS_UNSUPPORTED; + surface->current_clip_serial = 0; - if (surface->clip_region) { - if (free_existing) - pixman_region_destroy (surface->clip_region); - surface->clip_region = NULL; + if (surface->backend->intersect_clip_path) { + status = surface->backend->intersect_clip_path (surface, + NULL, + CAIRO_FILL_RULE_WINDING, + 0); + if (status) + return status; } - if (region) { - if (copy_region) { - surface->clip_region = pixman_region_create (); - pixman_region_copy (surface->clip_region, region); - } else - surface->clip_region = region; + if (surface->backend->set_clip_region != NULL) { + status = surface->backend->set_clip_region (surface, NULL); + if (status) + return status; } + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_surface_set_clip_region: + * @surface: the #cairo_surface_t to reset the clip on + * @region: the #pixman_region16_t to use for clipping + * @serial: the clip serial number associated with the region + * + * This function sets the clipping for the surface to + * the specified region and sets the surface clipping + * serial number to the associated serial number. + */ +cairo_private cairo_status_t +_cairo_surface_set_clip_region (cairo_surface_t *surface, + pixman_region16_t *region, + unsigned int serial) +{ + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + assert (surface->backend->set_clip_region != NULL); + + surface->current_clip_serial = serial; return surface->backend->set_clip_region (surface, region); } -cairo_status_t -_cairo_surface_set_clip_region (cairo_surface_t *surface, - pixman_region16_t *region) +static cairo_status_t +_cairo_surface_set_clip_path_recursive (cairo_surface_t *surface, + cairo_clip_path_t *clip_path) { - return _cairo_surface_set_clip_region_internal (surface, region, TRUE, TRUE); + cairo_status_t status; + + if (clip_path == NULL) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_surface_set_clip_path_recursive (surface, clip_path->prev); + if (status) + return status; + + return surface->backend->intersect_clip_path (surface, + &clip_path->path, + clip_path->fill_rule, + clip_path->tolerance); } -cairo_status_t -_cairo_surface_get_clip_extents (cairo_surface_t *surface, - cairo_rectangle_t *rectangle) + +/** + * _cairo_surface_set_clip_path: + * @surface: the #cairo_surface_t to reset the clip on + * @path: the path to intersect against the current clipping path + * @fill_rule: fill rule to use for clipping + * @tolerance: tesselation to use for tesselating clipping path + * @serial: the clip serial number associated with the region + * + * Sets the clipping path to be the intersection of the current + * clipping path of the surface and the given path. + **/ +cairo_private cairo_status_t +_cairo_surface_set_clip_path (cairo_surface_t *surface, + cairo_clip_path_t *clip_path, + unsigned int serial) { + cairo_status_t status; + if (surface->finished) return CAIRO_STATUS_SURFACE_FINISHED; - if (surface->clip_region) { - pixman_box16_t *box = pixman_region_extents (surface->clip_region); + assert (surface->backend->intersect_clip_path != NULL); - rectangle->x = box->x1; - rectangle->y = box->y1; - rectangle->width = box->x2 - box->x1; - rectangle->height = box->y2 - box->y1; - - return CAIRO_STATUS_SUCCESS; - } + status = surface->backend->intersect_clip_path (surface, + NULL, + CAIRO_FILL_RULE_WINDING, + 0); + if (status) + return status; + + status = _cairo_surface_set_clip_path_recursive (surface, clip_path); + if (status) + return status; + + surface->current_clip_serial = serial; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_surface_get_extents: + * @surface: the #cairo_surface_t to fetch extents for + * + * This function returns a bounding box for the surface. The + * surface bounds are defined as a region beyond which no + * rendering will possibly be recorded, in otherwords, + * it is the maximum extent of potentially usable + * coordinates. For simple pixel-based surfaces, + * it can be a close bound on the retained pixel + * region. For virtual surfaces (PDF et al), it + * cannot and must extend to the reaches of the + * target system coordinate space. + */ + +cairo_status_t +_cairo_surface_get_extents (cairo_surface_t *surface, + cairo_rectangle_t *rectangle) +{ + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; return surface->backend->get_extents (surface, rectangle); } diff --git a/src/cairo-traps.c b/src/cairo-traps.c index 15dfc1bca..a97d58481 100644 --- a/src/cairo-traps.c +++ b/src/cairo-traps.c @@ -820,7 +820,7 @@ _cairo_traps_extract_region (cairo_traps_t *traps, int width = _cairo_fixed_integer_part(traps->traps[i].right.p1.x) - x; int height = _cairo_fixed_integer_part(traps->traps[i].left.p2.y) - y; - /* Sometimes we get degenerate trapezoids from the tesellator, + /* XXX: Sometimes we get degenerate trapezoids from the tesellator, * if we call pixman_region_union_rect(), it bizarrly fails on such * an empty rectangle, so skip them. */ diff --git a/src/cairo-wideint.c b/src/cairo-wideint.c index 953108339..60946d90b 100644 --- a/src/cairo-wideint.c +++ b/src/cairo-wideint.c @@ -1,5 +1,5 @@ /* - * $Id: cairo-wideint.c,v 1.4 2005-01-19 15:07:00 cworth Exp $ + * $Id: cairo-wideint.c,v 1.5 2005-06-03 21:51:57 cworth Exp $ * * Copyright © 2004 Keith Packard * @@ -421,7 +421,9 @@ _cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den) num = _cairo_uint64_sub (num, den); } else + { q0 = 0; + } q1 = 0; r0 = num.lo; @@ -937,7 +939,9 @@ _cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den) num = _cairo_uint128_sub (num, den); } else + { q0 = _cairo_uint32_to_uint64 (0); + } q1 = _cairo_uint32_to_uint64 (0); r0 = num.lo; diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c index 78b3ca212..eef2b4e72 100644 --- a/src/cairo-win32-font.c +++ b/src/cairo-win32-font.c @@ -104,6 +104,8 @@ static void _compute_transform (cairo_win32_scaled_font_t *scaled_font, cairo_matrix_t *sc) { + cairo_status_t status; + if (NEARLY_ZERO (sc->yx) && NEARLY_ZERO (sc->xy)) { scaled_font->preserve_axes = TRUE; scaled_font->x_scale = sc->xx; @@ -154,8 +156,10 @@ _compute_transform (cairo_win32_scaled_font_t *scaled_font, 1.0 / scaled_font->logical_scale, 1.0 / scaled_font->logical_scale); scaled_font->device_to_logical = scaled_font->logical_to_device; - if (!CAIRO_OK (cairo_matrix_invert (&scaled_font->device_to_logical))) - cairo_matrix_init_identity (&scaled_font->device_to_logical); + + status = cairo_matrix_invert (&scaled_font->device_to_logical); + if (status) + cairo_matrix_init_identity (&scaled_font->device_to_logical); } static BYTE @@ -194,8 +198,9 @@ _get_system_quality (void) } return ANTIALIASED_QUALITY; - } else + } else { return DEFAULT_QUALITY; + } } static cairo_scaled_font_t * @@ -367,7 +372,7 @@ _cairo_win32_scaled_font_select_unscaled_font (cairo_scaled_font_t *scaled_font, return _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_select_unscaled_font"); status = _win32_scaled_font_set_identity_transform (hdc); - if (!CAIRO_OK (status)) { + if (status) { SelectObject (hdc, old_hfont); return status; } @@ -399,7 +404,7 @@ _cairo_win32_scaled_font_create (const char *family, cairo_status_t status; status = _cairo_utf8_to_utf16 (family, -1, &face_name, &face_name_len); - if (!CAIRO_OK (status)) + if (status) return status; if (face_name_len > LF_FACESIZE - 1) { @@ -465,6 +470,9 @@ _cairo_win32_scaled_font_destroy (void *abstract_font) { cairo_win32_scaled_font_t *scaled_font = abstract_font; + if (scaled_font == NULL) + return; + if (scaled_font->scaled_hfont) DeleteObject (scaled_font->scaled_hfont); @@ -496,7 +504,7 @@ _cairo_win32_scaled_font_text_to_glyphs (void *abstract_font, HDC hdc = NULL; status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &n16); - if (!CAIRO_OK (status)) + if (status) return status; gcp_results.lStructSize = sizeof (GCP_RESULTS); @@ -518,7 +526,7 @@ _cairo_win32_scaled_font_text_to_glyphs (void *abstract_font, } status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); - if (!CAIRO_OK (status)) + if (status) goto FAIL1; while (TRUE) { @@ -610,7 +618,7 @@ _cairo_win32_scaled_font_font_extents (void *abstract_font, * from the GDI in logical space, then convert back to font space */ status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); - if (!CAIRO_OK (status)) + if (status) return status; GetTextMetrics (hdc, &metrics); cairo_win32_scaled_font_done_font (&scaled_font->base); @@ -629,7 +637,7 @@ _cairo_win32_scaled_font_font_extents (void *abstract_font, * avoid them. */ status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc); - if (!CAIRO_OK (status)) + if (status) return status; GetTextMetrics (hdc, &metrics); _cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base); @@ -672,7 +680,7 @@ _cairo_win32_scaled_font_glyph_extents (void *abstract_font, * from the GDI in device space and convert to font space. */ status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); - if (!CAIRO_OK (status)) + if (status) return status; GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX, &metrics, 0, NULL, &matrix); @@ -714,7 +722,7 @@ _cairo_win32_scaled_font_glyph_extents (void *abstract_font, _cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base); extents->x_bearing = (double)metrics.gmptGlyphOrigin.x / scaled_font->em_square; - extents->y_bearing = (double)metrics.gmptGlyphOrigin.y / scaled_font->em_square; + extents->y_bearing = - (double)metrics.gmptGlyphOrigin.y / scaled_font->em_square; extents->width = (double)metrics.gmBlackBoxX / scaled_font->em_square; extents->height = (double)metrics.gmBlackBoxY / scaled_font->em_square; extents->x_advance = (double)metrics.gmCellIncX / scaled_font->em_square; @@ -745,7 +753,7 @@ _cairo_win32_scaled_font_glyph_bbox (void *abstract_font, return CAIRO_STATUS_NO_MEMORY; status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); - if (!CAIRO_OK (status)) + if (status) return status; for (i = 0; i < num_glyphs; i++) { @@ -844,7 +852,7 @@ _add_glyph (cairo_glyph_state_t *state, if (logical_y != state->last_y) { cairo_status_t status = _flush_glyphs (state); - if (!CAIRO_OK (status)) + if (status) return status; state->start_x = logical_x; } @@ -890,7 +898,7 @@ _draw_glyphs_on_surface (cairo_win32_surface_t *surface, return _cairo_win32_print_gdi_error ("_draw_glyphs_on_surface:SaveDC"); status = cairo_win32_scaled_font_select_font (&scaled_font->base, surface->dc); - if (!CAIRO_OK (status)) + if (status) goto FAIL1; SetTextColor (surface->dc, color); @@ -902,7 +910,7 @@ _draw_glyphs_on_surface (cairo_win32_surface_t *surface, for (i = 0; i < num_glyphs; i++) { status = _add_glyph (&state, glyphs[i].index, glyphs[i].x - x_offset, glyphs[i].y - y_offset); - if (!CAIRO_OK (status)) + if (status) goto FAIL2; } @@ -1152,7 +1160,7 @@ static const cairo_font_face_backend_t _cairo_win32_font_face_backend = { }; /** - * cairo_win32_scaled_font_create_for_logfontw: + * cairo_win32_font_face_create_for_logfontw: * @logfont: A #LOGFONTW structure specifying the font to use. * The lfHeight, lfWidth, lfOrientation and lfEscapement * fields of this structure are ignored. @@ -1231,7 +1239,7 @@ cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font, } status = _win32_scaled_font_set_world_transform ((cairo_win32_scaled_font_t *)scaled_font, hdc); - if (!CAIRO_OK (status)) { + if (status) { SetGraphicsMode (hdc, old_mode); SelectObject (hdc, old_hfont); return status; diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c index 9df86380b..8d63adbf3 100644 --- a/src/cairo-win32-surface.c +++ b/src/cairo-win32-surface.c @@ -1,6 +1,6 @@ /* Cairo - a vector graphics library with display and print output * - * Copyright 2005 Red Hat, Inc. + * Copyright © 2005 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -292,7 +292,6 @@ _cairo_win32_surface_create_for_dc (HDC original_dc, static cairo_surface_t * _cairo_win32_surface_create_similar (void *abstract_src, cairo_format_t format, - int drawable, int width, int height) { @@ -359,7 +358,6 @@ _cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface, local = (cairo_win32_surface_t *) _cairo_win32_surface_create_similar (surface, surface->format, - 0, width, height); if (!local) return CAIRO_STATUS_NO_MEMORY; @@ -404,12 +402,13 @@ _cairo_win32_surface_acquire_source_image (void *abstract_sur status = _cairo_win32_surface_get_subimage (abstract_surface, 0, 0, surface->clip_rect.width, surface->clip_rect.height, &local); - if (CAIRO_OK (status)) { - *image_out = (cairo_image_surface_t *)local->image; - *image_extra = local; - } + if (status) + return status; - return status; + *image_out = (cairo_image_surface_t *)local->image; + *image_extra = local; + + return CAIRO_STATUS_SUCCESS; } static void @@ -475,17 +474,18 @@ _cairo_win32_surface_acquire_dest_image (void *abstract_surfa status = _cairo_win32_surface_get_subimage (abstract_surface, x1, y1, x2 - x1, y2 - y1, &local); - if (CAIRO_OK (status)) { - *image_out = (cairo_image_surface_t *)local->image; - *image_extra = local; - - image_rect->x = x1; - image_rect->y = y1; - image_rect->width = x2 - x1; - image_rect->height = y2 - y1; - } + if (status) + return status; - return status; + *image_out = (cairo_image_surface_t *)local->image; + *image_extra = local; + + image_rect->x = x1; + image_rect->y = y1; + image_rect->width = x2 - x1; + image_rect->height = y2 - y1; + + return CAIRO_STATUS_SUCCESS; } static void @@ -941,6 +941,7 @@ static const cairo_surface_backend_t cairo_win32_surface_backend = { NULL, /* copy_page */ NULL, /* show_page */ _cairo_win32_surface_set_clip_region, + NULL, /* intersect_clip_path */ _cairo_win32_surface_get_extents, NULL /* show_glyphs */ }; diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index 95568d608..4e3204452 100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -229,7 +229,6 @@ _CAIRO_FORMAT_DEPTH (cairo_format_t format) static cairo_surface_t * _cairo_xcb_surface_create_similar (void *abstract_src, cairo_format_t format, - int drawable, int width, int height) { @@ -371,7 +370,7 @@ _get_image_surface (cairo_xcb_surface_t *surface, rect.x = interest_rect->x; rect.y = interest_rect->y; rect.width = interest_rect->width; - rect.height = interest_rect->width; + rect.height = interest_rect->height; if (rect.x > x1) x1 = rect.x; @@ -521,9 +520,6 @@ _get_image_surface (cairo_xcb_surface_t *surface, /* Let the surface take ownership of the data */ _cairo_image_surface_assume_ownership_of_data (image); - _cairo_image_surface_set_repeat (image, surface->base.repeat); - _cairo_image_surface_set_matrix (image, &(surface->base.matrix)); - *image_out = image; return CAIRO_STATUS_SUCCESS; } @@ -569,10 +565,12 @@ _cairo_xcb_surface_acquire_source_image (void *abstract_surfa cairo_status_t status; status = _get_image_surface (surface, NULL, &image, NULL); - if (status == CAIRO_STATUS_SUCCESS) - *image_out = image; + if (status) + return status; - return status; + *image_out = image; + + return CAIRO_STATUS_SUCCESS; } static void @@ -595,10 +593,12 @@ _cairo_xcb_surface_acquire_dest_image (void *abstract_surface cairo_status_t status; status = _get_image_surface (surface, interest_rect, &image, image_rect_out); - if (status == CAIRO_STATUS_SUCCESS) - *image_out = image; + if (status) + return status; - return status; + *image_out = image; + + return CAIRO_STATUS_SUCCESS; } static void @@ -637,7 +637,7 @@ _cairo_xcb_surface_clone_similar (void *abstract_surface, cairo_image_surface_t *image_src = (cairo_image_surface_t *)src; clone = (cairo_xcb_surface_t *) - _cairo_xcb_surface_create_similar (surface, image_src->format, 0, + _cairo_xcb_surface_create_similar (surface, image_src->format, image_src->width, image_src->height); if (clone == NULL) return CAIRO_STATUS_NO_MEMORY; @@ -850,12 +850,12 @@ _cairo_xcb_surface_composite (cairo_operator_t operator, return status; status = _cairo_xcb_surface_set_attributes (src, &src_attr); - if (CAIRO_OK (status)) + if (status == CAIRO_STATUS_SUCCESS) { if (mask) { status = _cairo_xcb_surface_set_attributes (mask, &mask_attr); - if (CAIRO_OK (status)) + if (status == CAIRO_STATUS_SUCCESS) XCBRenderComposite (dst->dpy, _render_operator (operator), src->picture, @@ -966,7 +966,7 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator, /* XXX: _format_from_cairo is slow. should cache something. */ render_format = _format_from_cairo (dst->dpy, CAIRO_FORMAT_A8), status = _cairo_xcb_surface_set_attributes (src, &attributes); - if (CAIRO_OK (status)) + if (status == CAIRO_STATUS_SUCCESS) XCBRenderTrapezoids (dst->dpy, _render_operator (operator), src->picture, dst->picture, @@ -981,14 +981,6 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator, } static cairo_int_status_t -_cairo_xcb_surface_set_clip_region (void *abstract_surface, - pixman_region16_t *region) -{ - /* XXX: FIXME */ - return CAIRO_INT_STATUS_UNSUPPORTED; -} - -static cairo_int_status_t _cairo_xcb_surface_get_extents (void *abstract_surface, cairo_rectangle_t *rectangle) { @@ -1016,7 +1008,8 @@ static const cairo_surface_backend_t cairo_xcb_surface_backend = { _cairo_xcb_surface_composite_trapezoids, NULL, /* copy_page */ NULL, /* show_page */ - _cairo_xcb_surface_set_clip_region, + NULL, /* _cairo_xcb_surface_set_clip_region */ + NULL, /* intersect_clip_path */ _cairo_xcb_surface_get_extents, NULL /* show_glyphs */ }; diff --git a/src/cairo-xcb.h b/src/cairo-xcb.h index 57a7aebd1..17dfafa02 100644 --- a/src/cairo-xcb.h +++ b/src/cairo-xcb.h @@ -47,7 +47,7 @@ CAIRO_BEGIN_DECLS cairo_surface_t * cairo_xcb_surface_create (XCBConnection *c, - XCBDRAWABLE pixmap, + XCBDRAWABLE drawable, XCBVISUALTYPE *visual, int width, int height); diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 41fb00c44..f06d409e2 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -46,7 +46,17 @@ typedef int (*cairo_xlib_error_func_t) (Display *display, typedef struct _cairo_xlib_surface cairo_xlib_surface_t; -static void _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface); +static void +_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface); + +static void +_cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface); + +static void +_cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface); + +static cairo_bool_t +_cairo_surface_is_xlib (cairo_surface_t *surface); /* * Instead of taking two round trips for each blending request, @@ -70,11 +80,25 @@ struct _cairo_xlib_surface { int render_major; int render_minor; + /* TRUE if the server has a bug with repeating pictures + * + * https://bugs.freedesktop.org/show_bug.cgi?id=3566 + * + * We can't test for this because it depends on whether the + * picture is in video memory or not. + */ + cairo_bool_t buggy_repeat; + int width; int height; int depth; - Picture picture; + Picture dst_picture, src_picture; + + cairo_bool_t have_clip_rects; + XRectangle *clip_rects; + int num_clip_rects; + XRenderPictFormat *format; }; @@ -157,7 +181,6 @@ _CAIRO_FORMAT_XRENDER_FORMAT(Display *dpy, cairo_format_t format) static cairo_surface_t * _cairo_xlib_surface_create_similar (void *abstract_src, cairo_format_t format, - int drawable, int width, int height) { @@ -197,8 +220,11 @@ static cairo_status_t _cairo_xlib_surface_finish (void *abstract_surface) { cairo_xlib_surface_t *surface = abstract_surface; - if (surface->picture) - XRenderFreePicture (surface->dpy, surface->picture); + if (surface->dst_picture) + XRenderFreePicture (surface->dpy, surface->dst_picture); + + if (surface->src_picture) + XRenderFreePicture (surface->dpy, surface->src_picture); if (surface->owns_pixmap) XFreePixmap (surface->dpy, surface->drawable); @@ -206,6 +232,9 @@ _cairo_xlib_surface_finish (void *abstract_surface) if (surface->gc) XFreeGC (surface->dpy, surface->gc); + if (surface->clip_rects) + free (surface->clip_rects); + surface->dpy = NULL; return CAIRO_STATUS_SUCCESS; @@ -281,7 +310,7 @@ _get_image_surface (cairo_xlib_surface_t *surface, rect.x = interest_rect->x; rect.y = interest_rect->y; rect.width = interest_rect->width; - rect.height = interest_rect->width; + rect.height = interest_rect->height; if (rect.x > x1) x1 = rect.x; @@ -425,14 +454,54 @@ _get_image_surface (cairo_xlib_surface_t *surface, ximage->data = NULL; XDestroyImage (ximage); - _cairo_image_surface_set_repeat (image, surface->base.repeat); - _cairo_image_surface_set_matrix (image, &(surface->base.matrix)); - *image_out = image; return CAIRO_STATUS_SUCCESS; } static void +_cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface) +{ + if (!surface->src_picture) + surface->src_picture = XRenderCreatePicture (surface->dpy, + surface->drawable, + surface->format, + 0, NULL); +} + +static void +_cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_surface_t *surface) +{ + if (surface->have_clip_rects) + XRenderSetPictureClipRectangles (surface->dpy, surface->dst_picture, + 0, 0, + surface->clip_rects, + surface->num_clip_rects); +} + +static void +_cairo_xlib_surface_set_gc_clip_rects (cairo_xlib_surface_t *surface) +{ + if (surface->have_clip_rects) + XSetClipRectangles(surface->dpy, surface->gc, + 0, 0, + surface->clip_rects, + surface->num_clip_rects, YXSorted); +} + +static void +_cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface) +{ + if (!surface->dst_picture) { + surface->dst_picture = XRenderCreatePicture (surface->dpy, + surface->drawable, + surface->format, + 0, NULL); + _cairo_xlib_surface_set_picture_clip_rects (surface); + } + +} + +static void _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface) { XGCValues gcv; @@ -443,6 +512,7 @@ _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface) gcv.graphics_exposures = False; surface->gc = XCreateGC (surface->dpy, surface->drawable, GCGraphicsExposures, &gcv); + _cairo_xlib_surface_set_gc_clip_rects (surface); } static cairo_status_t @@ -499,10 +569,12 @@ _cairo_xlib_surface_acquire_source_image (void *abstract_surf cairo_status_t status; status = _get_image_surface (surface, NULL, &image, NULL); - if (status == CAIRO_STATUS_SUCCESS) - *image_out = image; + if (status) + return status; - return status; + *image_out = image; + + return CAIRO_STATUS_SUCCESS; } static void @@ -525,10 +597,12 @@ _cairo_xlib_surface_acquire_dest_image (void *abstract_surfac cairo_status_t status; status = _get_image_surface (surface, interest_rect, &image, image_rect_out); - if (status == CAIRO_STATUS_SUCCESS) - *image_out = image; + if (status) + return status; - return status; + *image_out = image; + + return CAIRO_STATUS_SUCCESS; } static void @@ -567,7 +641,7 @@ _cairo_xlib_surface_clone_similar (void *abstract_surface, cairo_image_surface_t *image_src = (cairo_image_surface_t *)src; clone = (cairo_xlib_surface_t *) - _cairo_xlib_surface_create_similar (surface, image_src->format, 0, + _cairo_xlib_surface_create_similar (surface, image_src->format, image_src->width, image_src->height); if (clone == NULL) return CAIRO_STATUS_NO_MEMORY; @@ -588,7 +662,7 @@ _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface, { XTransform xtransform; - if (!surface->picture) + if (!surface->src_picture) return CAIRO_STATUS_SUCCESS; xtransform.matrix[0][0] = _cairo_fixed_from_double (matrix->xx); @@ -617,7 +691,7 @@ _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface, return CAIRO_INT_STATUS_UNSUPPORTED; } - XRenderSetPictureTransform (surface->dpy, surface->picture, &xtransform); + XRenderSetPictureTransform (surface->dpy, surface->src_picture, &xtransform); return CAIRO_STATUS_SUCCESS; } @@ -628,7 +702,7 @@ _cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface, { char *render_filter; - if (!surface->picture) + if (!surface->src_picture) return CAIRO_STATUS_SUCCESS; if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface)) @@ -660,7 +734,7 @@ _cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface, break; } - XRenderSetPictureFilter (surface->dpy, surface->picture, + XRenderSetPictureFilter (surface->dpy, surface->src_picture, render_filter, NULL, 0); return CAIRO_STATUS_SUCCESS; @@ -672,13 +746,13 @@ _cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface, int repeat) XRenderPictureAttributes pa; unsigned long mask; - if (!surface->picture) + if (!surface->src_picture) return CAIRO_STATUS_SUCCESS; mask = CPRepeat; pa.repeat = repeat; - XRenderChangePicture (surface->dpy, surface->picture, mask, &pa); + XRenderChangePicture (surface->dpy, surface->src_picture, mask, &pa); return CAIRO_STATUS_SUCCESS; } @@ -689,6 +763,8 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface, { cairo_int_status_t status; + _cairo_xlib_surface_ensure_src_picture (surface); + status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix); if (status) return status; @@ -711,6 +787,139 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface, return CAIRO_STATUS_SUCCESS; } +/* Checks whether we can can directly draw from src to dst with + * the core protocol: either with CopyArea or using src as a + * a tile in a GC. + */ +static cairo_bool_t +_surfaces_compatible (cairo_xlib_surface_t *src, + cairo_xlib_surface_t *dst) +{ + + if (src->dpy != dst->dpy) + return FALSE; + + /* We must not only match depth and format/visual, we must also + * match screen. We don't have that information, and rather than + * asking for it round-trip, we'll just return FALSE if we have + * more than one screen on the display. + */ + if (ScreenCount (dst->dpy) > 1) + return FALSE; + + return (src->depth == dst->depth && + ((src->format != NULL && src->format == dst->format) || + (src->visual != NULL && src->visual == dst->visual))); +} + +static cairo_bool_t +_surface_has_alpha (cairo_xlib_surface_t *surface) +{ + if (surface->format) { + if (surface->format->type == PictTypeDirect && + surface->format->direct.alphaMask != 0) + return TRUE; + else + return FALSE; + } else { + + /* In the no-render case, we never have alpha */ + return FALSE; + } +} + +/* There is a bug in most older X servers with compositing using a repeating + * source pattern when the source is in off-screen video memory. When that + * bug could be triggered, we need a fallback: in the common case where we have no + * transformation and the source and destination have the same format/visual, + * we can do the operation using the core protocol, otherwise, we need + * a software fallback. + */ +typedef enum { + DO_RENDER, /* use render */ + DO_XLIB, /* core protocol fallback */ + DO_UNSUPPORTED /* software fallback */ +} composite_operation_t; + +/* Initial check for the bug; we need to recheck after we turn + * patterns into surfaces, since that may introduce a repeating + * pattern for gradient patterns. + * + * All we do here is reject cases where we *know* are going to + * hit the bug and won't be able to use a core protocol fallback. + */ +static composite_operation_t +_categorize_composite_repeat (cairo_xlib_surface_t *dst, + cairo_operator_t operator, + cairo_pattern_t *src_pattern, + cairo_bool_t have_mask) + +{ + if (!dst->buggy_repeat) + return DO_RENDER; + + if (src_pattern->type == CAIRO_PATTERN_SURFACE) + { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)src_pattern; + + if (_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) && + src_pattern->extend == CAIRO_EXTEND_REPEAT) + { + /* This is the case where we have a bug; reject some cases where a + * core protocol fallback is impossible. + */ + if (have_mask || + !(operator == CAIRO_OPERATOR_SOURCE || operator == CAIRO_OPERATOR_OVER)) + return DO_UNSUPPORTED; + + if (_cairo_surface_is_xlib (surface_pattern->surface)) { + cairo_xlib_surface_t *src = (cairo_xlib_surface_t *)surface_pattern->surface; + + if (operator == CAIRO_OPERATOR_OVER && _surface_has_alpha (src)) + return DO_UNSUPPORTED; + + if (src->dpy == dst->dpy && !_surfaces_compatible (src, dst)) + return DO_UNSUPPORTED; + } + } + } + + return DO_RENDER; +} + +/* Recheck for composite-repeat once we've turned patterns into Xlib surfaces + * If we end up returning DO_UNSUPPORTED here, we're throwing away work we + * did to turn gradients into a pattern, but most of the time we can handle + * that case with core protocol fallback. + */ +static composite_operation_t +_recategorize_composite_repeat (cairo_xlib_surface_t *dst, + cairo_operator_t operator, + cairo_xlib_surface_t *src, + cairo_surface_attributes_t *src_attr, + cairo_bool_t have_mask) +{ + if (!dst->buggy_repeat) + return DO_RENDER; + + if (_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) && + src_attr->extend == CAIRO_EXTEND_REPEAT && + (src->width != 1 || src->height != 1)) + { + if (!have_mask && + (operator == CAIRO_OPERATOR_SOURCE || + (operator == CAIRO_OPERATOR_OVER && !_surface_has_alpha (src)))) + { + if (_surfaces_compatible (dst, src)) + return DO_XLIB; + } + + return DO_UNSUPPORTED; + } + + return DO_RENDER; +} + static int _render_operator (cairo_operator_t operator) { @@ -770,10 +979,16 @@ _cairo_xlib_surface_composite (cairo_operator_t operator, cairo_xlib_surface_t *src; cairo_xlib_surface_t *mask; cairo_int_status_t status; + composite_operation_t operation; if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; + operation = _categorize_composite_repeat (dst, operator, src_pattern, + mask_pattern != NULL); + if (operation == DO_UNSUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; + status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern, &dst->base, src_x, src_y, @@ -785,16 +1000,28 @@ _cairo_xlib_surface_composite (cairo_operator_t operator, if (status) return status; + operation = _recategorize_composite_repeat (dst, operator, src, &src_attr, + mask_pattern != NULL); + if (operation == DO_UNSUPPORTED) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto FAIL; + } + status = _cairo_xlib_surface_set_attributes (src, &src_attr); - if (CAIRO_OK (status)) { + if (status) + goto FAIL; + + if (operation == DO_RENDER) + { + _cairo_xlib_surface_ensure_dst_picture (dst); if (mask) { status = _cairo_xlib_surface_set_attributes (mask, &mask_attr); - if (CAIRO_OK (status)) + if (status == CAIRO_STATUS_SUCCESS) XRenderComposite (dst->dpy, _render_operator (operator), - src->picture, - mask->picture, - dst->picture, + src->src_picture, + mask->src_picture, + dst->dst_picture, src_x + src_attr.x_offset, src_y + src_attr.y_offset, mask_x + mask_attr.x_offset, @@ -804,9 +1031,9 @@ _cairo_xlib_surface_composite (cairo_operator_t operator, } else { XRenderComposite (dst->dpy, _render_operator (operator), - src->picture, + src->src_picture, 0, - dst->picture, + dst->dst_picture, src_x + src_attr.x_offset, src_y + src_attr.y_offset, 0, 0, @@ -814,6 +1041,30 @@ _cairo_xlib_surface_composite (cairo_operator_t operator, width, height); } } + else /* DO_XLIB */ + { + /* This case is only used for bug fallbacks, though it is theoretically + * applicable to the case where we don't have the RENDER extension as + * well. + * + * We've checked that we have a repeating unscaled source in + * _recategorize_composite_repeat. + */ + int itx, ity; + + _cairo_xlib_surface_ensure_gc (dst); + _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity); + + XSetTSOrigin (dst->dpy, dst->gc, + - (itx + src_attr.x_offset), - (ity + src_attr.y_offset)); + XSetTile (dst->dpy, dst->gc, src->drawable); + XSetFillStyle (dst->dpy, dst->gc, FillTiled); + + XFillRectangle (dst->dpy, dst->drawable, dst->gc, + dst_x, dst_y, width, height); + } + + FAIL: if (mask) _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr); @@ -842,9 +1093,10 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, render_color.alpha = color->alpha_short; /* XXX: This XRectangle cast is evil... it needs to go away somehow. */ + _cairo_xlib_surface_ensure_dst_picture (surface); XRenderFillRectangles (surface->dpy, _render_operator (operator), - surface->picture, + surface->dst_picture, &render_color, (XRectangle *) rects, num_rects); return CAIRO_STATUS_SUCCESS; @@ -867,11 +1119,16 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, cairo_xlib_surface_t *dst = abstract_dst; cairo_xlib_surface_t *src; cairo_int_status_t status; + composite_operation_t operation; int render_reference_x, render_reference_y; int render_src_x, render_src_y; if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; + + operation = _categorize_composite_repeat (dst, operator, pattern, TRUE); + if (operation == DO_UNSUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_pattern_acquire_surface (pattern, &dst->base, src_x, src_y, width, height, @@ -879,7 +1136,13 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, &attributes); if (status) return status; - + + operation = _recategorize_composite_repeat (dst, operator, src, &attributes, TRUE); + if (operation == DO_UNSUPPORTED) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto FAIL; + } + if (traps[0].left.p1.y < traps[0].left.p2.y) { render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x); render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y); @@ -892,16 +1155,18 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, render_src_y = src_y + render_reference_y - dst_y; /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */ + _cairo_xlib_surface_ensure_dst_picture (dst); status = _cairo_xlib_surface_set_attributes (src, &attributes); - if (CAIRO_OK (status)) + if (status == CAIRO_STATUS_SUCCESS) XRenderCompositeTrapezoids (dst->dpy, _render_operator (operator), - src->picture, dst->picture, + src->src_picture, dst->dst_picture, XRenderFindStandardFormat (dst->dpy, PictStandardA8), render_src_x + attributes.x_offset, render_src_y + attributes.y_offset, (XTrapezoid *) traps, num_traps); + FAIL: _cairo_pattern_release_surface (&dst->base, &src->base, &attributes); return status; @@ -913,14 +1178,22 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, { cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; + if (surface->clip_rects) { + free (surface->clip_rects); + surface->clip_rects = NULL; + } + + surface->have_clip_rects = FALSE; + surface->num_clip_rects = 0; + if (region == NULL) { if (surface->gc) XSetClipMask (surface->dpy, surface->gc, None); - if (surface->picture) { + if (surface->format && surface->dst_picture) { XRenderPictureAttributes pa; pa.clip_mask = None; - XRenderChangePicture (surface->dpy, surface->picture, + XRenderChangePicture (surface->dpy, surface->dst_picture, CPClipMask, &pa); } } else { @@ -946,15 +1219,15 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, rects[i].height = boxes[i].y2 - boxes[i].y1; } + surface->have_clip_rects = TRUE; + surface->clip_rects = rects; + surface->num_clip_rects = n_boxes; + if (surface->gc) - XSetClipRectangles(surface->dpy, surface->gc, - 0, 0, rects, n_boxes, YXSorted); - if (surface->picture) - XRenderSetPictureClipRectangles (surface->dpy, surface->picture, - 0, 0, rects, n_boxes); - - if (rects) - free (rects); + _cairo_xlib_surface_set_gc_clip_rects (surface); + + if (surface->dst_picture) + _cairo_xlib_surface_set_picture_clip_rects (surface); } return CAIRO_STATUS_SUCCESS; @@ -1003,6 +1276,7 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = { NULL, /* copy_page */ NULL, /* show_page */ _cairo_xlib_surface_set_clip_region, + NULL, /* intersect_clip_path */ _cairo_xlib_surface_get_extents, _cairo_xlib_surface_show_glyphs }; @@ -1043,15 +1317,12 @@ _cairo_xlib_surface_create_internal (Display *dpy, surface->gc = NULL; surface->drawable = drawable; surface->owns_pixmap = FALSE; - surface->visual = visual; - surface->format = format; surface->use_pixmap = 0; surface->width = width; surface->height = height; - surface->depth = depth; if (format) { - surface->depth = format->depth; + depth = format->depth; } else if (visual) { int i, j, k; @@ -1061,10 +1332,10 @@ _cairo_xlib_surface_create_internal (Display *dpy, for (i = 0; i < ScreenCount (dpy); i++) { Screen *screen = ScreenOfDisplay (dpy, i); for (j = 0; j < screen->ndepths; j++) { - Depth *depth = &screen->depths[j]; - for (k = 0; k < depth->nvisuals; k++) { - if (&depth->visuals[k] == visual) { - surface->depth = depth->depth; + Depth *d = &screen->depths[j]; + for (k = 0; k < d->nvisuals; k++) { + if (&d->visuals[k] == visual) { + depth = d->depth; goto found; } } @@ -1080,22 +1351,34 @@ _cairo_xlib_surface_create_internal (Display *dpy, surface->render_minor = -1; } - surface->picture = None; + surface->buggy_repeat = FALSE; + if (strcmp (ServerVendor (dpy), "The X.Org Foundation") == 0) { + if (VendorRelease (dpy) <= 60802000) + surface->buggy_repeat = TRUE; + } + + surface->dst_picture = None; + surface->src_picture = None; if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) { - if (!format) { - if (visual) { + if (visual) format = XRenderFindVisualFormat (dpy, visual); - } else if (depth == 1) + else if (depth == 1) format = XRenderFindStandardFormat (dpy, PictStandardA1); } - - if (format) - surface->picture = XRenderCreatePicture (dpy, drawable, - format, 0, NULL); + } else { + format = NULL; } + surface->visual = visual; + surface->format = format; + surface->depth = depth; + + surface->have_clip_rects = FALSE; + surface->clip_rects = NULL; + surface->num_clip_rects = 0; + return (cairo_surface_t *) surface; } @@ -1479,8 +1762,8 @@ _cairo_xlib_surface_show_glyphs32 (cairo_scaled_font_t *scaled_font, XRenderCompositeText32 (self->dpy, _render_operator (operator), - src->picture, - self->picture, + src->src_picture, + self->dst_picture, g->a8_pict_format, source_x, source_y, 0, 0, @@ -1556,8 +1839,8 @@ _cairo_xlib_surface_show_glyphs16 (cairo_scaled_font_t *scaled_font, XRenderCompositeText16 (self->dpy, _render_operator (operator), - src->picture, - self->picture, + src->src_picture, + self->dst_picture, g->a8_pict_format, source_x, source_y, 0, 0, @@ -1632,8 +1915,8 @@ _cairo_xlib_surface_show_glyphs8 (cairo_scaled_font_t *scaled_font, XRenderCompositeText8 (self->dpy, _render_operator (operator), - src->picture, - self->picture, + src->src_picture, + self->dst_picture, g->a8_pict_format, source_x, source_y, 0, 0, @@ -1678,11 +1961,16 @@ _cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font, cairo_glyph_cache_key_t key; glyphset_cache_entry_t **entries; glyphset_cache_entry_t *stack_entries [N_STACK_BUF]; + composite_operation_t operation; int i; - if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (self)) + if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (self) || !self->format) return CAIRO_INT_STATUS_UNSUPPORTED; + operation = _categorize_composite_repeat (self, operator, pattern, TRUE); + if (operation == DO_UNSUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; + status = _cairo_pattern_acquire_surface (pattern, &self->base, source_x, source_y, width, height, (cairo_surface_t **) &src, @@ -1690,6 +1978,12 @@ _cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font, if (status) return status; + operation = _recategorize_composite_repeat (self, operator, src, &attributes, TRUE); + if (operation == DO_UNSUPPORTED) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto FAIL; + } + status = _cairo_xlib_surface_set_attributes (src, &attributes); if (status) goto FAIL; @@ -1738,21 +2032,28 @@ _cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font, /* Call the appropriate sub-function. */ + _cairo_xlib_surface_ensure_dst_picture (self); if (elt_size == 8) + { status = _cairo_xlib_surface_show_glyphs8 (scaled_font, operator, g, &key, src, self, source_x + attributes.x_offset, source_y + attributes.y_offset, glyphs, entries, num_glyphs); + } else if (elt_size == 16) + { status = _cairo_xlib_surface_show_glyphs16 (scaled_font, operator, g, &key, src, self, source_x + attributes.x_offset, source_y + attributes.y_offset, glyphs, entries, num_glyphs); + } else + { status = _cairo_xlib_surface_show_glyphs32 (scaled_font, operator, g, &key, src, self, source_x + attributes.x_offset, source_y + attributes.y_offset, glyphs, entries, num_glyphs); + } for (i = 0; i < num_glyphs; ++i) _xlib_glyphset_cache_destroy_entry (g, entries[i]); diff --git a/src/cairo.c b/src/cairo.c index f825c733e..73dfc2cdd 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -43,37 +43,56 @@ #define CAIRO_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */ +static const cairo_t cairo_nil = { + (unsigned int)-1, /* ref_count */ + CAIRO_STATUS_NO_MEMORY, /* status */ + { /* path */ + NULL, NULL, /* op_buf_head, op_buf_tail */ + NULL, NULL, /* arg_buf_head, arg_buf_tail */ + { 0, 0 }, /* last_move_point */ + { 0, 0 }, /* current point */ + FALSE, /* has_current_point */ + }, + NULL /* gstate */ +}; + #include <assert.h> -#ifdef NDEBUG -#define CAIRO_CHECK_SANITY(cr) -#else -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: - case CAIRO_STATUS_INVALID_RESTORE: - case CAIRO_STATUS_INVALID_POP_GROUP: - case CAIRO_STATUS_NO_CURRENT_POINT: - case CAIRO_STATUS_INVALID_MATRIX: - case CAIRO_STATUS_NO_TARGET_SURFACE: - case CAIRO_STATUS_NULL_POINTER: - case CAIRO_STATUS_INVALID_STRING: - case CAIRO_STATUS_INVALID_PATH_DATA: - break; - default: - return 0; - } - return 1; +/* This has to be updated whenever cairo_status_t is extended. That's + * a bit of a pain, but it should be easy to always catch as long as + * one adds a new test case to test a trigger of the new status value. + */ +#define CAIRO_STATUS_LAST_STATUS CAIRO_STATUS_SURFACE_TYPE_MISMATCH + +/** + * _cairo_error: + * @cr: a cairo context + * @status: a status value indicating an error, (eg. not + * CAIRO_STATUS_SUCCESS) + * + * Sets cr->status to @status. + * + * All assignments of an error status to cr->status should happen + * either inside of _cairo_error(), or else _cairo_error() should be + * called immediately after the assignment. + * + * The purpose of this function is to allow the user to set a + * breakpoint in _cairo_error() to generate a stack trace for when the + * user causes cairo to detect an error. + * + * _cairo_error also calls the error notify callback function that the + * user may have set with cairo_set_error_notify. + **/ +static void +_cairo_error (cairo_t *cr, cairo_status_t status) +{ + assert (status > CAIRO_STATUS_SUCCESS && + status <= CAIRO_STATUS_LAST_STATUS); + + cr->status = status; } -#define CAIRO_CHECK_SANITY(cr) assert(cairo_sane_state ((cr))) -#endif -/* +/** * cairo_create: * @target: target surface for the context * @@ -81,7 +100,7 @@ cairo_sane_state (cairo_t *cr) * default values and with @target as a target surface. The target * surface should be constructed with a backend-specific function such * as cairo_image_surface_create (or any other - * cairo_<backend>_surface_create variant). + * cairo_<backend>_surface_create variant). * * This function references @target, so you can immediately * call cairo_surface_destroy() on it if you don't need to @@ -100,7 +119,12 @@ cairo_sane_state (cairo_t *cr) * Return value: a newly allocated #cairo_t with a reference * count of 1. The initial reference count should be released * with cairo_destroy() when you are done using the #cairo_t. - */ + * This function never returns %NULL. If memory cannot be + * allocated, a special #cairo_t object will be returned on + * which cairo_status() returns %CAIRO_STATUS_NO_MEMORY. + * You can use this object normally, but no drawing will + * be done. + **/ cairo_t * cairo_create (cairo_surface_t *target) { @@ -108,24 +132,24 @@ cairo_create (cairo_surface_t *target) cr = malloc (sizeof (cairo_t)); if (cr == NULL) - return NULL; + return (cairo_t *) &cairo_nil; - cr->status = CAIRO_STATUS_SUCCESS; cr->ref_count = 1; + cr->status = CAIRO_STATUS_SUCCESS; + _cairo_path_fixed_init (&cr->path); if (target == NULL) { cr->gstate = NULL; - cr->status = CAIRO_STATUS_NULL_POINTER; + _cairo_error (cr, CAIRO_STATUS_NULL_POINTER); return cr; } cr->gstate = _cairo_gstate_create (target); if (cr->gstate == NULL) - cr->status = CAIRO_STATUS_NO_MEMORY; + _cairo_error (cr, CAIRO_STATUS_NO_MEMORY); - CAIRO_CHECK_SANITY (cr); return cr; } @@ -140,12 +164,10 @@ cairo_create (cairo_surface_t *target) void cairo_reference (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->ref_count == (unsigned int)-1) return; - + cr->ref_count++; - CAIRO_CHECK_SANITY (cr); } /** @@ -159,7 +181,9 @@ cairo_reference (cairo_t *cr) void cairo_destroy (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); + if (cr->ref_count == (unsigned int)-1) + return; + cr->ref_count--; if (cr->ref_count) return; @@ -197,21 +221,20 @@ cairo_save (cairo_t *cr) { cairo_gstate_t *top; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } top = _cairo_gstate_clone (cr->gstate); if (top == NULL) { - cr->status = CAIRO_STATUS_NO_MEMORY; - CAIRO_CHECK_SANITY (cr); + _cairo_error (cr, CAIRO_STATUS_NO_MEMORY); return; } top->next = cr->gstate; cr->gstate = top; - CAIRO_CHECK_SANITY (cr); } slim_hidden_def(cairo_save); @@ -228,9 +251,10 @@ cairo_restore (cairo_t *cr) { cairo_gstate_t *top; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } top = cr->gstate; cr->gstate = top->next; @@ -238,12 +262,7 @@ cairo_restore (cairo_t *cr) _cairo_gstate_destroy (top); if (cr->gstate == NULL) - cr->status = CAIRO_STATUS_INVALID_RESTORE; - - if (cr->status) - return; - - CAIRO_CHECK_SANITY (cr); + _cairo_error (cr, CAIRO_STATUS_INVALID_RESTORE); } slim_hidden_def(cairo_restore); @@ -291,12 +310,26 @@ cairo_pop_group (cairo_t *cr) void cairo_set_operator (cairo_t *cr, cairo_operator_t op) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_operator (cr->gstate, op); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); +} + +static void +_cairo_set_source_solid (cairo_t *cr, const cairo_color_t *color) +{ + cairo_pattern_t *source; + + source = _cairo_pattern_create_solid (color); + + cairo_set_source (cr, source); + + cairo_pattern_destroy (source); } /** @@ -319,9 +352,10 @@ cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue) { cairo_color_t color; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } _cairo_restrict_value (&red, 0.0, 1.0); _cairo_restrict_value (&green, 0.0, 1.0); @@ -329,9 +363,7 @@ cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue) _cairo_color_init_rgb (&color, red, green, blue); - cr->status = _cairo_gstate_set_source_solid (cr->gstate, &color); - - CAIRO_CHECK_SANITY (cr); + _cairo_set_source_solid (cr, &color); } /** @@ -357,9 +389,10 @@ cairo_set_source_rgba (cairo_t *cr, { cairo_color_t color; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } _cairo_restrict_value (&red, 0.0, 1.0); _cairo_restrict_value (&green, 0.0, 1.0); @@ -368,9 +401,7 @@ cairo_set_source_rgba (cairo_t *cr, _cairo_color_init_rgba (&color, red, green, blue, alpha); - cr->status = _cairo_gstate_set_source_solid (cr->gstate, &color); - - CAIRO_CHECK_SANITY (cr); + _cairo_set_source_solid (cr, &color); } void @@ -382,23 +413,18 @@ cairo_set_source_surface (cairo_t *cr, cairo_pattern_t *pattern; cairo_matrix_t matrix; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } pattern = cairo_pattern_create_for_surface (surface); - if (!pattern) { - cr->status = CAIRO_STATUS_NO_MEMORY; - return; - } cairo_matrix_init_translate (&matrix, -x, -y); cairo_pattern_set_matrix (pattern, &matrix); cairo_set_source (cr, pattern); cairo_pattern_destroy (pattern); - - CAIRO_CHECK_SANITY (cr); } /** @@ -418,12 +444,24 @@ cairo_set_source_surface (cairo_t *cr, void cairo_set_source (cairo_t *cr, cairo_pattern_t *source) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); + return; + } + + if (source == NULL) { + _cairo_error (cr, CAIRO_STATUS_NULL_POINTER); + return; + } + + if (source->status) { + _cairo_error (cr, source->status); return; + } cr->status = _cairo_gstate_set_source (cr->gstate, source); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -439,11 +477,12 @@ cairo_set_source (cairo_t *cr, cairo_pattern_t *source) cairo_pattern_t * cairo_get_source (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - /* XXX: We'll want to do something like this: - if (cr->status) - return cairo_pattern_nil; - */ + if (cr->status) { + cairo_pattern_t *pattern; + pattern = _cairo_pattern_create_in_error (cr->status); + _cairo_error (cr, cr->status); + return pattern; + } return _cairo_gstate_get_source (cr->gstate); } @@ -464,14 +503,16 @@ cairo_get_source (cairo_t *cr) void cairo_set_tolerance (cairo_t *cr, double tolerance) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } _cairo_restrict_value (&tolerance, CAIRO_TOLERANCE_MINIMUM, tolerance); cr->status = _cairo_gstate_set_tolerance (cr->gstate, tolerance); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -488,12 +529,14 @@ cairo_set_tolerance (cairo_t *cr, double tolerance) void cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_fill_rule (cr->gstate, fill_rule); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -513,14 +556,16 @@ cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule) void cairo_set_line_width (cairo_t *cr, double width) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } _cairo_restrict_value (&width, 0.0, width); cr->status = _cairo_gstate_set_line_width (cr->gstate, width); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -540,12 +585,14 @@ cairo_set_line_width (cairo_t *cr, double width) void cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_line_cap (cr->gstate, line_cap); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -565,34 +612,40 @@ cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap) void cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_line_join (cr->gstate, line_join); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } void cairo_set_dash (cairo_t *cr, double *dashes, int ndash, double offset) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_dash (cr->gstate, dashes, ndash, offset); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } void cairo_set_miter_limit (cairo_t *cr, double limit) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_miter_limit (cr->gstate, limit); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } @@ -611,12 +664,14 @@ cairo_set_miter_limit (cairo_t *cr, double limit) void cairo_translate (cairo_t *cr, double tx, double ty) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_translate (cr->gstate, tx, ty); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -633,12 +688,14 @@ cairo_translate (cairo_t *cr, double tx, double ty) void cairo_scale (cairo_t *cr, double sx, double sy) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_scale (cr->gstate, sx, sy); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } @@ -657,12 +714,14 @@ cairo_scale (cairo_t *cr, double sx, double sy) void cairo_rotate (cairo_t *cr, double angle) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_rotate (cr->gstate, angle); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -678,12 +737,14 @@ void cairo_transform (cairo_t *cr, const cairo_matrix_t *matrix) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_transform (cr->gstate, matrix); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -698,12 +759,14 @@ void cairo_set_matrix (cairo_t *cr, const cairo_matrix_t *matrix) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_matrix (cr->gstate, matrix); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -718,12 +781,14 @@ cairo_set_matrix (cairo_t *cr, void cairo_identity_matrix (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_identity_matrix (cr->gstate); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -739,12 +804,14 @@ cairo_identity_matrix (cairo_t *cr) void cairo_user_to_device (cairo_t *cr, double *x, double *y) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_user_to_device (cr->gstate, x, y); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -761,12 +828,14 @@ cairo_user_to_device (cairo_t *cr, double *x, double *y) void cairo_user_to_device_distance (cairo_t *cr, double *dx, double *dy) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_user_to_device_distance (cr->gstate, dx, dy); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -782,12 +851,14 @@ cairo_user_to_device_distance (cairo_t *cr, double *dx, double *dy) void cairo_device_to_user (cairo_t *cr, double *x, double *y) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_device_to_user (cr->gstate, x, y); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -804,24 +875,25 @@ cairo_device_to_user (cairo_t *cr, double *x, double *y) void cairo_device_to_user_distance (cairo_t *cr, double *dx, double *dy) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_device_to_user_distance (cr->gstate, dx, dy); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } void cairo_new_path (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } _cairo_path_fixed_fini (&cr->path); - - CAIRO_CHECK_SANITY (cr); } slim_hidden_def(cairo_new_path); @@ -830,17 +902,18 @@ cairo_move_to (cairo_t *cr, double x, double y) { cairo_fixed_t x_fixed, y_fixed; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } _cairo_gstate_user_to_backend (cr->gstate, &x, &y); x_fixed = _cairo_fixed_from_double (x); y_fixed = _cairo_fixed_from_double (y); cr->status = _cairo_path_fixed_move_to (&cr->path, x_fixed, y_fixed); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } slim_hidden_def(cairo_move_to); @@ -849,17 +922,18 @@ cairo_line_to (cairo_t *cr, double x, double y) { cairo_fixed_t x_fixed, y_fixed; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } _cairo_gstate_user_to_backend (cr->gstate, &x, &y); x_fixed = _cairo_fixed_from_double (x); y_fixed = _cairo_fixed_from_double (y); cr->status = _cairo_path_fixed_line_to (&cr->path, x_fixed, y_fixed); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } void @@ -872,9 +946,10 @@ cairo_curve_to (cairo_t *cr, cairo_fixed_t x2_fixed, y2_fixed; cairo_fixed_t x3_fixed, y3_fixed; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } _cairo_gstate_user_to_backend (cr->gstate, &x1, &y1); _cairo_gstate_user_to_backend (cr->gstate, &x2, &y2); @@ -893,8 +968,8 @@ cairo_curve_to (cairo_t *cr, x1_fixed, y1_fixed, x2_fixed, y2_fixed, x3_fixed, y3_fixed); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -936,9 +1011,10 @@ cairo_arc (cairo_t *cr, double radius, double angle1, double angle2) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } /* Do nothing, successfully, if radius is <= 0 */ if (radius <= 0.0) @@ -953,8 +1029,6 @@ cairo_arc (cairo_t *cr, _cairo_arc_path (cr, xc, yc, radius, angle1, angle2); - - CAIRO_CHECK_SANITY (cr); } /** @@ -977,9 +1051,10 @@ cairo_arc_negative (cairo_t *cr, double radius, double angle1, double angle2) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } /* Do nothing, successfully, if radius is <= 0 */ if (radius <= 0.0) @@ -994,8 +1069,6 @@ cairo_arc_negative (cairo_t *cr, _cairo_arc_path_negative (cr, xc, yc, radius, angle1, angle2); - - CAIRO_CHECK_SANITY (cr); } /* XXX: NYI @@ -1020,17 +1093,18 @@ cairo_rel_move_to (cairo_t *cr, double dx, double dy) { cairo_fixed_t dx_fixed, dy_fixed; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } _cairo_gstate_user_to_device_distance (cr->gstate, &dx, &dy); dx_fixed = _cairo_fixed_from_double (dx); dy_fixed = _cairo_fixed_from_double (dy); cr->status = _cairo_path_fixed_rel_move_to (&cr->path, dx_fixed, dy_fixed); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } void @@ -1038,17 +1112,18 @@ cairo_rel_line_to (cairo_t *cr, double dx, double dy) { cairo_fixed_t dx_fixed, dy_fixed; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } _cairo_gstate_user_to_device_distance (cr->gstate, &dx, &dy); dx_fixed = _cairo_fixed_from_double (dx); dy_fixed = _cairo_fixed_from_double (dy); cr->status = _cairo_path_fixed_rel_line_to (&cr->path, dx_fixed, dy_fixed); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } slim_hidden_def(cairo_rel_line_to); @@ -1062,9 +1137,10 @@ cairo_rel_curve_to (cairo_t *cr, cairo_fixed_t dx2_fixed, dy2_fixed; cairo_fixed_t dx3_fixed, dy3_fixed; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } _cairo_gstate_user_to_device_distance (cr->gstate, &dx1, &dy1); _cairo_gstate_user_to_device_distance (cr->gstate, &dx2, &dy2); @@ -1083,8 +1159,8 @@ cairo_rel_curve_to (cairo_t *cr, dx1_fixed, dy1_fixed, dx2_fixed, dy2_fixed, dx3_fixed, dy3_fixed); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } void @@ -1092,16 +1168,16 @@ cairo_rectangle (cairo_t *cr, double x, double y, double width, double height) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cairo_move_to (cr, x, y); cairo_rel_line_to (cr, width, 0); cairo_rel_line_to (cr, 0, height); cairo_rel_line_to (cr, -width, 0); cairo_close_path (cr); - CAIRO_CHECK_SANITY (cr); } /* XXX: NYI @@ -1112,19 +1188,22 @@ cairo_stroke_to_path (cairo_t *cr) return; cr->status = _cairo_gstate_stroke_path (cr->gstate); + if (cr->status) + _cairo_error (cr, cr->status); } */ void cairo_close_path (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_path_fixed_close_path (&cr->path); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } slim_hidden_def(cairo_close_path); @@ -1138,13 +1217,14 @@ slim_hidden_def(cairo_close_path); void cairo_paint (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_paint (cr->gstate); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -1164,18 +1244,24 @@ cairo_paint_with_alpha (cairo_t *cr, cairo_color_t color; cairo_pattern_union_t pattern; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } + + if (CAIRO_ALPHA_IS_OPAQUE (alpha)) { + cairo_paint (cr); + return; + } _cairo_color_init_rgba (&color, 1., 1., 1., alpha); _cairo_pattern_init_solid (&pattern.solid, &color); cr->status = _cairo_gstate_mask (cr->gstate, &pattern.base); + if (cr->status) + _cairo_error (cr, cr->status); _cairo_pattern_fini (&pattern.base); - - CAIRO_CHECK_SANITY (cr); } /** @@ -1192,13 +1278,24 @@ void cairo_mask (cairo_t *cr, cairo_pattern_t *pattern) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } - cr->status = _cairo_gstate_mask (cr->gstate, pattern); + if (pattern == NULL) { + _cairo_error (cr, CAIRO_STATUS_NULL_POINTER); + return; + } + + if (pattern->status) { + _cairo_error (cr, pattern->status); + return; + } - CAIRO_CHECK_SANITY (cr); + cr->status = _cairo_gstate_mask (cr->gstate, pattern); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -1222,15 +1319,12 @@ cairo_mask_surface (cairo_t *cr, cairo_pattern_t *pattern; cairo_matrix_t matrix; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } pattern = cairo_pattern_create_for_surface (surface); - if (!pattern) { - cr->status = CAIRO_STATUS_NO_MEMORY; - return; - } cairo_matrix_init_translate (&matrix, - surface_x, - surface_y); cairo_pattern_set_matrix (pattern, &matrix); @@ -1275,13 +1369,14 @@ cairo_stroke (cairo_t *cr) void cairo_stroke_preserve (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_stroke (cr->gstate, &cr->path); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } slim_hidden_def(cairo_stroke_preserve); @@ -1315,36 +1410,41 @@ cairo_fill (cairo_t *cr) void cairo_fill_preserve (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_fill (cr->gstate, &cr->path); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } slim_hidden_def(cairo_fill_preserve); void cairo_copy_page (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_copy_page (cr->gstate); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } void cairo_show_page (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_show_page (cr->gstate); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } cairo_bool_t @@ -1352,18 +1452,18 @@ cairo_in_stroke (cairo_t *cr, double x, double y) { int inside; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return 0; + } cr->status = _cairo_gstate_in_stroke (cr->gstate, &cr->path, x, y, &inside); - - CAIRO_CHECK_SANITY (cr); - - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return 0; + } return inside; } @@ -1373,18 +1473,18 @@ cairo_in_fill (cairo_t *cr, double x, double y) { int inside; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return 0; + } cr->status = _cairo_gstate_in_fill (cr->gstate, &cr->path, x, y, &inside); - - CAIRO_CHECK_SANITY (cr); - - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return 0; + } return inside; } @@ -1393,28 +1493,32 @@ void cairo_stroke_extents (cairo_t *cr, double *x1, double *y1, double *x2, double *y2) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_stroke_extents (cr->gstate, &cr->path, x1, y1, x2, y2); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } void cairo_fill_extents (cairo_t *cr, double *x1, double *y1, double *x2, double *y2) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_fill_extents (cr->gstate, &cr->path, x1, y1, x2, y2); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -1472,12 +1576,14 @@ cairo_clip (cairo_t *cr) void cairo_clip_preserve (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_clip (cr->gstate, &cr->path); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } slim_hidden_def(cairo_clip_preserve); @@ -1500,12 +1606,14 @@ slim_hidden_def(cairo_clip_preserve); void cairo_reset_clip (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_reset_clip (cr->gstate); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -1529,12 +1637,14 @@ cairo_select_font_face (cairo_t *cr, cairo_font_slant_t slant, cairo_font_weight_t weight) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_select_font_face (cr->gstate, family, slant, weight); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -1546,19 +1656,27 @@ cairo_select_font_face (cairo_t *cr, * Return value: the current font object. Can return %NULL * on out-of-memory or if the context is already in * an error state. This object is owned by cairo. To keep - * a reference to it, you must call cairo_font_reference(). + * a reference to it, you must call cairo_font_face_reference(). **/ cairo_font_face_t * cairo_get_font_face (cairo_t *cr) { cairo_font_face_t *font_face; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return NULL; + } cr->status = _cairo_gstate_get_font_face (cr->gstate, &font_face); - CAIRO_CHECK_SANITY (cr); + if (cr->status) { + _cairo_error (cr, cr->status); + /* XXX: When available: + return _cairo_font_face_create_in_error (cr->status); + */ + return NULL; + } + return font_face; } @@ -1574,12 +1692,14 @@ void cairo_font_extents (cairo_t *cr, cairo_font_extents_t *extents) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_get_font_extents (cr->gstate, extents); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -1595,12 +1715,14 @@ void cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_font_face (cr->gstate, font_face); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -1617,12 +1739,14 @@ cairo_set_font_face (cairo_t *cr, void cairo_set_font_size (cairo_t *cr, double size) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_font_size (cr->gstate, size); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -1642,12 +1766,14 @@ void cairo_set_font_matrix (cairo_t *cr, const cairo_matrix_t *matrix) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_font_matrix (cr->gstate, matrix); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -1661,7 +1787,6 @@ cairo_set_font_matrix (cairo_t *cr, void cairo_get_font_matrix (cairo_t *cr, cairo_matrix_t *matrix) { - CAIRO_CHECK_SANITY (cr); _cairo_gstate_get_font_matrix (cr->gstate, matrix); } @@ -1694,9 +1819,10 @@ cairo_text_extents (cairo_t *cr, int num_glyphs; double x, y; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } if (utf8 == NULL) { extents->x_bearing = 0.0; @@ -1713,19 +1839,20 @@ cairo_text_extents (cairo_t *cr, cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, x, y, &glyphs, &num_glyphs); - CAIRO_CHECK_SANITY (cr); if (cr->status) { if (glyphs) free (glyphs); + _cairo_error (cr, cr->status); return; } cr->status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs, extents); - CAIRO_CHECK_SANITY (cr); - if (glyphs) free (glyphs); + + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -1752,13 +1879,15 @@ cairo_glyph_extents (cairo_t *cr, int num_glyphs, cairo_text_extents_t *extents) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs, extents); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } void @@ -1768,9 +1897,10 @@ cairo_show_text (cairo_t *cr, const char *utf8) int num_glyphs; double x, y; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } if (utf8 == NULL) return; @@ -1780,30 +1910,34 @@ cairo_show_text (cairo_t *cr, const char *utf8) cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, x, y, &glyphs, &num_glyphs); - CAIRO_CHECK_SANITY (cr); if (cr->status) { if (glyphs) free (glyphs); + _cairo_error (cr, cr->status); return; } cr->status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, num_glyphs); - CAIRO_CHECK_SANITY (cr); if (glyphs) free (glyphs); + + if (cr->status) + _cairo_error (cr, cr->status); } void cairo_show_glyphs (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, num_glyphs); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } void @@ -1813,44 +1947,48 @@ cairo_text_path (cairo_t *cr, const char *utf8) int num_glyphs; double x, y; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cairo_get_current_point (cr, &x, &y); cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, x, y, &glyphs, &num_glyphs); - CAIRO_CHECK_SANITY (cr); if (cr->status) { if (glyphs) free (glyphs); + _cairo_error (cr, cr->status); return; } cr->status = _cairo_gstate_glyph_path (cr->gstate, glyphs, num_glyphs, &cr->path); - CAIRO_CHECK_SANITY (cr); - if (glyphs) free (glyphs); + + if (cr->status) + _cairo_error (cr, cr->status); + } void cairo_glyph_path (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } cr->status = _cairo_gstate_glyph_path (cr->gstate, glyphs, num_glyphs, &cr->path); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } /** @@ -1864,7 +2002,6 @@ cairo_glyph_path (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs) cairo_operator_t cairo_get_operator (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); return _cairo_gstate_get_operator (cr->gstate); } @@ -1879,7 +2016,6 @@ cairo_get_operator (cairo_t *cr) double cairo_get_tolerance (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); return _cairo_gstate_get_tolerance (cr->gstate); } @@ -1911,8 +2047,6 @@ cairo_get_current_point (cairo_t *cr, double *x_ret, double *y_ret) cairo_fixed_t x_fixed, y_fixed; double x, y; - CAIRO_CHECK_SANITY (cr); - status = _cairo_path_fixed_get_current_point (&cr->path, &x_fixed, &y_fixed); if (status == CAIRO_STATUS_NO_CURRENT_POINT) { x = 0.0; @@ -1927,8 +2061,6 @@ cairo_get_current_point (cairo_t *cr, double *x_ret, double *y_ret) *x_ret = x; if (y_ret) *y_ret = y; - - CAIRO_CHECK_SANITY (cr); } slim_hidden_def(cairo_get_current_point); @@ -1943,7 +2075,6 @@ slim_hidden_def(cairo_get_current_point); cairo_fill_rule_t cairo_get_fill_rule (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); return _cairo_gstate_get_fill_rule (cr->gstate); } @@ -1958,7 +2089,6 @@ cairo_get_fill_rule (cairo_t *cr) double cairo_get_line_width (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); return _cairo_gstate_get_line_width (cr->gstate); } @@ -1973,7 +2103,6 @@ cairo_get_line_width (cairo_t *cr) cairo_line_cap_t cairo_get_line_cap (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); return _cairo_gstate_get_line_cap (cr->gstate); } @@ -1988,7 +2117,6 @@ cairo_get_line_cap (cairo_t *cr) cairo_line_join_t cairo_get_line_join (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); return _cairo_gstate_get_line_join (cr->gstate); } @@ -2003,7 +2131,6 @@ cairo_get_line_join (cairo_t *cr) double cairo_get_miter_limit (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); return _cairo_gstate_get_miter_limit (cr->gstate); } @@ -2017,7 +2144,6 @@ cairo_get_miter_limit (cairo_t *cr) void cairo_get_matrix (cairo_t *cr, cairo_matrix_t *matrix) { - CAIRO_CHECK_SANITY (cr); _cairo_gstate_get_matrix (cr->gstate, matrix); } @@ -2030,14 +2156,18 @@ cairo_get_matrix (cairo_t *cr, cairo_matrix_t *matrix) * * Return value: the target surface, (or NULL if @cr is in an error * state). This object is owned by cairo. To keep a reference to it, - * you must call cairo_pattern_reference(). + * you must call cairo_surface_reference(). **/ cairo_surface_t * cairo_get_target (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); + /* XXX: Should be as follows when available: + return _cairo_surface_create_in_error (); + */ return NULL; + } return _cairo_gstate_get_target (cr->gstate); } @@ -2053,13 +2183,25 @@ cairo_get_target (cairo_t *cr) * Return value: the copy of the current path. The caller owns the * returned object and should call cairo_path_destroy() when finished * with it. + * + * This function will always return a valid pointer, but the result + * will have no data, (data==NULL and num_data==0), if either of the + * following conditions hold: + * + * 1) If there is insufficient memory to copy the path. In this case + * path->status will be set to CAIRO_STATUS_NO_MEMORY. + * + * 2) If @cr is already in an error state. In this case path->status + * will contain the same status that would be returned by + * cairo_status(cr). **/ cairo_path_t * cairo_copy_path (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) - return &_cairo_path_nil; + if (cr->status) { + _cairo_error (cr, cr->status); + return _cairo_path_data_create_in_error (cr->status); + } return _cairo_path_data_create (&cr->path, cr->gstate); } @@ -2082,15 +2224,25 @@ cairo_copy_path (cairo_t *cr) * Return value: the copy of the current path. The caller owns the * returned object and should call cairo_path_destroy() when finished * with it. + * + * This function will always return a valid pointer, but the result + * will have no data, (data==NULL and num_data==0), if either of the + * following conditions hold: + * + * 1) If there is insufficient memory to copy the path. In this case + * path->status will be set to CAIRO_STATUS_NO_MEMORY. + * + * 2) If @cr is already in an error state. In this case path->status + * will contain the same status that would be returned by + * cairo_status(cr). **/ cairo_path_t * cairo_copy_path_flat (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); if (cr->status) - return &_cairo_path_nil; - - return _cairo_path_data_create_flat (&cr->path, cr->gstate); + return _cairo_path_data_create_in_error (cr->status); + else + return _cairo_path_data_create_flat (&cr->path, cr->gstate); } /** @@ -2098,43 +2250,47 @@ cairo_copy_path_flat (cairo_t *cr) * @cr: a cairo context * @path: path to be appended * - * Append the @path onto the current path. See #cairo_path_t - * for details on how the path data structure must be initialized. + * Append the @path onto the current path. The @path may be either the + * return value from one of cairo_copy_path() or + * cairo_copy_path_flat() or it may be constructed manually. See + * #cairo_path_t for details on how the path data structure should be + * initialized, and note that path->status must be initialized to + * CAIRO_STATUS_SUCCESS. **/ void cairo_append_path (cairo_t *cr, cairo_path_t *path) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_error (cr, cr->status); return; + } if (path == NULL || path->data == NULL) { - cr->status = CAIRO_STATUS_NULL_POINTER; + _cairo_error (cr, CAIRO_STATUS_NULL_POINTER); return; } - if (path == &_cairo_path_nil) { - cr->status = CAIRO_STATUS_NO_MEMORY; + if (path->status) { + _cairo_error (cr, path->status); return; } cr->status = _cairo_path_data_append_to_context (path, cr); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_error (cr, cr->status); } cairo_status_t cairo_status (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); return cr->status; } const char * -cairo_status_string (cairo_t *cr) +cairo_status_to_string (cairo_status_t status) { - switch (cr->status) { + switch (status) { case CAIRO_STATUS_SUCCESS: return "success"; case CAIRO_STATUS_NO_MEMORY: @@ -2163,8 +2319,8 @@ cairo_status_string (cairo_t *cr) return "the target surface has been finished"; case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: return "the surface type is not appropriate for the operation"; - case CAIRO_STATUS_BAD_NESTING: - return "drawing operations interleaved for two contexts for the same surface"; + case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: + return "the pattern type is not appropriate for the operation"; } return "<unknown error status>"; diff --git a/src/cairo.h b/src/cairo.h index 4cb3a023e..0fcd85602 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -130,6 +130,7 @@ typedef struct _cairo_user_data_key { * @CAIRO_STATUS_NO_MEMORY: * @CAIRO_STATUS_INVALID_RESTORE: * @CAIRO_STATUS_INVALID_POP_GROUP: + * @CAIRO_STATUS_NO_CURRENT_POINT: * @CAIRO_STATUS_INVALID_MATRIX: * @CAIRO_STATUS_NO_TARGET_SURFACE: * @CAIRO_STATUS_NULL_POINTER: @@ -139,11 +140,6 @@ typedef struct _cairo_user_data_key { * @CAIRO_STATUS_WRITE_ERROR: * @CAIRO_STATUS_SURFACE_FINISHED: * @CAIRO_STATUS_SURFACE_TYPE_MISMATCH: - * @CAIRO_STATUS_BAD_NESTING: the same surface was used as the - * target surface for two different cairo contexts at once, - * and more drawing was done on the first context before the - * surface was unset as the target for the second context. - * See the documentation for cairo_create(). * * #cairo_status_t is used to indicate errors that can occur when * using Cairo. In some cases it is returned directly by functions. @@ -165,7 +161,7 @@ typedef enum cairo_status { CAIRO_STATUS_WRITE_ERROR, CAIRO_STATUS_SURFACE_FINISHED, CAIRO_STATUS_SURFACE_TYPE_MISMATCH, - CAIRO_STATUS_BAD_NESTING + CAIRO_STATUS_PATTERN_TYPE_MISMATCH } cairo_status_t; /** @@ -767,8 +763,6 @@ cairo_get_miter_limit (cairo_t *cr); void cairo_get_matrix (cairo_t *cr, cairo_matrix_t *matrix); -/* XXX: Need to decide the memory management semantics of this - function. Should it reference the surface again? */ cairo_surface_t * cairo_get_target (cairo_t *cr); @@ -830,14 +824,16 @@ cairo_get_target (cairo_t *cr); * cairo_path_destroy (path); * </programlisting></informalexample> */ +typedef enum cairo_path_data_type { + CAIRO_PATH_MOVE_TO, + CAIRO_PATH_LINE_TO, + CAIRO_PATH_CURVE_TO, + CAIRO_PATH_CLOSE_PATH +} cairo_path_data_type_t; + typedef union { struct { - enum { - CAIRO_PATH_MOVE_TO, - CAIRO_PATH_LINE_TO, - CAIRO_PATH_CURVE_TO, - CAIRO_PATH_CLOSE_PATH - } type; + cairo_path_data_type_t type; int length; } header; struct { @@ -862,6 +858,7 @@ typedef union { * includes both headers and coordinates for each portion. **/ typedef struct cairo_path { + cairo_status_t status; cairo_path_data_t *data; int num_data; } cairo_path_t; @@ -885,7 +882,7 @@ cairo_status_t cairo_status (cairo_t *cr); const char * -cairo_status_string (cairo_t *cr); +cairo_status_to_string (cairo_status_t status); /* Surface manipulation */ @@ -1013,21 +1010,24 @@ void cairo_pattern_destroy (cairo_pattern_t *pattern); cairo_status_t +cairo_pattern_status (cairo_pattern_t *pattern); + +void cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, double offset, double red, double green, double blue); -cairo_status_t +void cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, double offset, double red, double green, double blue, double alpha); -cairo_status_t +void cairo_pattern_set_matrix (cairo_pattern_t *pattern, const cairo_matrix_t *matrix); -cairo_status_t +void cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix); @@ -1037,7 +1037,7 @@ typedef enum { CAIRO_EXTEND_REFLECT } cairo_extend_t; -cairo_status_t +void cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend); cairo_extend_t @@ -1052,7 +1052,7 @@ typedef enum { CAIRO_FILTER_GAUSSIAN } cairo_filter_t; -cairo_status_t +void cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter); cairo_filter_t @@ -1139,7 +1139,6 @@ cairo_matrix_transform_point (const cairo_matrix_t *matrix, #define cairo_current_matrix cairo_current_matrix_REPLACED_BY_cairo_get_matrix #define cairo_current_target_surface cairo_current_target_surface_REPLACED_BY_cairo_get_target #define cairo_get_status cairo_get_status_REPLACED_BY_cairo_status -#define cairo_get_status_string cairo_get_status_string_REPLACED_BY_cairo_status_string #define cairo_concat_matrix cairo_concat_matrix_REPLACED_BY_cairo_transform #define cairo_scale_font cairo_scale_font_REPLACED_BY_cairo_set_font_size #define cairo_select_font cairo_select_font_REPLACED_BY_cairo_select_font_face @@ -1188,6 +1187,8 @@ cairo_matrix_transform_point (const cairo_matrix_t *matrix, #define cairo_set_target_win32 cairo_set_target_win32_DEPRECATED_BY_cairo_win32_surface_create #define cairo_set_target_xcb cairo_set_target_xcb_DEPRECATED_BY_cairo_xcb_surface_create #define cairo_set_target_drawable cairo_set_target_drawable_DEPRECATED_BY_cairo_xlib_surface_create +#define cairo_get_status_string cairo_get_status_string_DEPRECATED_BY_cairo_status_AND_cairo_status_to_string +#define cairo_status_string cairo_status_string_DEPRECATED_BY_cairo_status_AND_cairo_status_to_string #endif diff --git a/src/cairoint.h b/src/cairoint.h index 90d59b2cb..1b21228d7 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -147,6 +147,8 @@ typedef cairo_fixed_16_16_t cairo_fixed_t; #define CAIRO_MAXSHORT SHRT_MAX #define CAIRO_MINSHORT SHRT_MIN +#define CAIRO_ALPHA_IS_OPAQUE(alpha) ((alpha) >= ((double)0xff00 / (double)0xffff)) + typedef struct _cairo_point { cairo_fixed_t x; cairo_fixed_t y; @@ -191,8 +193,6 @@ typedef enum cairo_int_status { CAIRO_INT_STATUS_UNSUPPORTED } cairo_int_status_t; -#define CAIRO_OK(status) ((status) == CAIRO_STATUS_SUCCESS) - typedef enum cairo_direction { CAIRO_DIRECTION_FORWARD, CAIRO_DIRECTION_REVERSE @@ -289,7 +289,7 @@ cairo_private void _cairo_user_data_array_init (cairo_user_data_array_t *array); cairo_private void -_cairo_user_data_array_destroy (cairo_user_data_array_t *array); +_cairo_user_data_array_fini (cairo_user_data_array_t *array); cairo_private void * _cairo_user_data_array_get_data (cairo_user_data_array_t *array, @@ -356,7 +356,6 @@ typedef struct { #undef CAIRO_MEASURE_CACHE_PERFORMANCE typedef struct { - unsigned long refcount; const cairo_cache_backend_t *backend; const cairo_cache_arrangement_t *arrangement; cairo_cache_entry_base_t **entries; @@ -568,7 +567,6 @@ typedef struct _cairo_surface_backend { cairo_surface_t * (*create_similar) (void *surface, cairo_format_t format, - int drawable, int width, int height); @@ -646,10 +644,43 @@ typedef struct _cairo_surface_backend { cairo_int_status_t (*show_page) (void *surface); + /* Set given region as the clip region for the surface, replacing + * any previously set clip region. Passing in a NULL region will + * clear the surface clip region. + * + * The surface is expected to store the clip region and clip all + * following drawing operations against it until the clip region + * is cleared of replaced by another clip region. + * + * Cairo will call this function whenever a clip path can be + * represented as a device pixel aligned set of rectangles. When + * this is not possible, cairo will use mask surfaces for + * clipping. + */ cairo_int_status_t (*set_clip_region) (void *surface, pixman_region16_t *region); + /* Intersect the given path against the clip path currently set in + * the surface, using the given fill_rule and tolerance, and set + * the result as the new clipping path for the surface. Passing + * in a NULL path will clear the surface clipping path. + * + * The surface is expected to store the resulting clip path and + * clip all following drawing operations against it until the clip + * path cleared or intersected with a new path. + * + * If a surface implements this function, set_clip_region() will + * never be called and should not be implemented. If this + * function is not implemented cairo will use set_clip_region() + * (if available) and mask surfaces for clipping. + */ + cairo_int_status_t + (*intersect_clip_path) (void *dst, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance); + /* Get the extents of the current surface. For many surface types * this will be as simple as { x=0, y=0, width=surface->width, * height=surface->height}. @@ -687,7 +718,9 @@ typedef struct _cairo_surface_backend { (*fill_path) (cairo_operator_t operator, cairo_pattern_t *pattern, void *dst, - cairo_path_fixed_t *path); + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance); } cairo_surface_backend_t; @@ -699,7 +732,11 @@ typedef struct _cairo_format_masks { unsigned long blue_mask; } cairo_format_masks_t; -typedef struct _cairo_surface_save cairo_surface_save_t; +typedef enum _cairo_clip_mode { + CAIRO_CLIP_MODE_PATH, + CAIRO_CLIP_MODE_REGION, + CAIRO_CLIP_MODE_MASK +} cairo_clip_mode_t; struct _cairo_surface { const cairo_surface_backend_t *backend; @@ -708,17 +745,24 @@ struct _cairo_surface { cairo_bool_t finished; cairo_user_data_array_t user_data; - cairo_matrix_t matrix; - cairo_filter_t filter; - int repeat; - double device_x_offset; double device_y_offset; - cairo_surface_save_t *saves; /* Stack of saved states from cairo_surface_begin/end() */ - int level; /* Number saved states */ - - pixman_region16_t *clip_region; + /* + * Each time a clip region is modified, it gets the next value in this + * sequence. This means that clip regions for this surface are uniquely + * identified andupdates to the clip can be readily identified + */ + unsigned int next_clip_serial; + /* + * The serial number of the current clip. This is set when + * the surface clipping is set. The gstate can then cheaply + * check whether the surface clipping is already correct before + * performing a rendering operation. + * + * The special value '0' is reserved for the unclipped case. + */ + unsigned int current_clip_serial; }; struct _cairo_image_surface { @@ -779,6 +823,7 @@ typedef struct _cairo_color_stop { struct _cairo_pattern { cairo_pattern_type_t type; unsigned int ref_count; + cairo_status_t status; cairo_matrix_t matrix; cairo_filter_t filter; cairo_extend_t extend; @@ -840,7 +885,6 @@ typedef struct _cairo_surface_attributes { int x_offset; int y_offset; cairo_bool_t acquired; - cairo_bool_t clip_saved; void *extra; } cairo_surface_attributes_t; @@ -854,19 +898,23 @@ typedef struct _cairo_traps { #define CAIRO_FONT_SLANT_DEFAULT CAIRO_FONT_SLANT_NORMAL #define CAIRO_FONT_WEIGHT_DEFAULT CAIRO_FONT_WEIGHT_NORMAL +#define CAIRO_WIN32_FONT_FAMILY_DEFAULT "Arial" +#define CAIRO_ATSUI_FONT_FAMILY_DEFAULT "Monaco" +#define CAIRO_FT_FONT_FAMILY_DEFAULT "" + #if CAIRO_HAS_WIN32_FONT -#define CAIRO_FONT_FAMILY_DEFAULT "Arial" +#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_WIN32_FONT_FAMILY_DEFAULT #define CAIRO_FONT_BACKEND_DEFAULT &cairo_win32_scaled_font_backend #elif CAIRO_HAS_ATSUI_FONT -#define CAIRO_FONT_FAMILY_DEFAULT "Monaco" +#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_ATSUI_FONT_FAMILY_DEFAULT #define CAIRO_FONT_BACKEND_DEFAULT &cairo_atsui_scaled_font_backend #elif CAIRO_HAS_FT_FONT -#define CAIRO_FONT_FAMILY_DEFAULT "serif" +#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_FT_FONT_FAMILY_DEFAULT #define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_scaled_font_backend #endif @@ -880,13 +928,6 @@ typedef struct _cairo_traps { #define CAIRO_GSTATE_MITER_LIMIT_DEFAULT 10.0 #define CAIRO_GSTATE_DEFAULT_FONT_SIZE 10.0 -/* Need a name distinct from the cairo_clip function */ -typedef struct _cairo_clip_rec { - cairo_rectangle_t rect; - pixman_region16_t *region; - cairo_surface_t *surface; -} cairo_clip_rec_t; - typedef struct _cairo_gstate cairo_gstate_t; typedef struct _cairo_stroke_face { @@ -930,16 +971,6 @@ _cairo_fixed_integer_ceil (cairo_fixed_t f); cairo_private cairo_gstate_t * _cairo_gstate_create (cairo_surface_t *target); -cairo_private cairo_status_t -_cairo_gstate_init (cairo_gstate_t *gstate, - cairo_surface_t *target); - -cairo_private cairo_status_t -_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other); - -cairo_private void -_cairo_gstate_fini (cairo_gstate_t *gstate); - cairo_private void _cairo_gstate_destroy (cairo_gstate_t *gstate); @@ -947,9 +978,6 @@ cairo_private cairo_gstate_t * _cairo_gstate_clone (cairo_gstate_t *gstate); cairo_private cairo_status_t -_cairo_gstate_copy (cairo_gstate_t *dest, cairo_gstate_t *src); - -cairo_private cairo_status_t _cairo_gstate_begin_group (cairo_gstate_t *gstate); cairo_private cairo_status_t @@ -961,10 +989,6 @@ _cairo_gstate_get_target (cairo_gstate_t *gstate); cairo_private cairo_status_t _cairo_gstate_set_source (cairo_gstate_t *gstate, cairo_pattern_t *source); -cairo_status_t -_cairo_gstate_set_source_solid (cairo_gstate_t *gstate, - const cairo_color_t *color); - cairo_private cairo_pattern_t * _cairo_gstate_get_source (cairo_gstate_t *gstate); @@ -1378,11 +1402,10 @@ _cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps); -/* cairo_surface.c */ +/* cairo-surface.c */ cairo_private cairo_surface_t * _cairo_surface_create_similar_scratch (cairo_surface_t *other, cairo_format_t format, - int drawable, int width, int height); @@ -1397,14 +1420,8 @@ cairo_private void _cairo_surface_init (cairo_surface_t *surface, const cairo_surface_backend_t *backend); -cairo_private cairo_status_t -_cairo_surface_begin (cairo_surface_t *surface); - -cairo_private cairo_status_t -_cairo_surface_begin_reset_clip (cairo_surface_t *surface); - -cairo_private cairo_status_t -_cairo_surface_end (cairo_surface_t *surface); +cairo_private cairo_clip_mode_t +_cairo_surface_get_clip_mode (cairo_surface_t *surface); cairo_private cairo_status_t _cairo_surface_fill_rectangle (cairo_surface_t *surface, @@ -1437,10 +1454,12 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface, int num_rects); cairo_private cairo_int_status_t -_cairo_surface_fill_path (cairo_operator_t operator, - cairo_pattern_t *pattern, - cairo_surface_t *dst, - cairo_path_fixed_t *path); +_cairo_surface_fill_path (cairo_operator_t operator, + cairo_pattern_t *pattern, + cairo_surface_t *dst, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance); cairo_private cairo_status_t _cairo_surface_composite_trapezoids (cairo_operator_t operator, @@ -1490,13 +1509,30 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, cairo_surface_t *src, cairo_surface_t **clone_out); +cairo_private unsigned int +_cairo_surface_get_current_clip_serial (cairo_surface_t *surface); + +cairo_private unsigned int +_cairo_surface_allocate_clip_serial (cairo_surface_t *surface); + +cairo_private cairo_status_t +_cairo_surface_reset_clip (cairo_surface_t *surface); + +cairo_private cairo_status_t +_cairo_surface_set_clip_region (cairo_surface_t *surface, + pixman_region16_t *region, + unsigned int serial); + +typedef struct _cairo_clip_path cairo_clip_path_t; + cairo_private cairo_status_t -_cairo_surface_set_clip_region (cairo_surface_t *surface, - pixman_region16_t *region); +_cairo_surface_set_clip_path (cairo_surface_t *surface, + cairo_clip_path_t *clip_path, + unsigned int serial); cairo_private cairo_status_t -_cairo_surface_get_clip_extents (cairo_surface_t *surface, - cairo_rectangle_t *rectangle); +_cairo_surface_get_extents (cairo_surface_t *surface, + cairo_rectangle_t *rectangle); cairo_private cairo_status_t _cairo_surface_show_glyphs (cairo_scaled_font_t *scaled_font, @@ -1524,18 +1560,6 @@ _cairo_image_surface_create_with_masks (unsigned char *data, cairo_private void _cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface); -cairo_private cairo_status_t -_cairo_image_surface_set_matrix (cairo_image_surface_t *surface, - const cairo_matrix_t *matrix); - -cairo_private cairo_status_t -_cairo_image_surface_set_filter (cairo_image_surface_t *surface, - cairo_filter_t filter); - -cairo_private cairo_status_t -_cairo_image_surface_set_repeat (cairo_image_surface_t *surface, - int repeat); - cairo_private cairo_int_status_t _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface, pixman_region16_t *region); @@ -1689,8 +1713,9 @@ _cairo_slope_counter_clockwise (cairo_slope_t *a, cairo_slope_t *b); /* cairo_pattern.c */ -cairo_private cairo_status_t -_cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other); +cairo_private void +_cairo_pattern_init_copy (cairo_pattern_t *pattern, + const cairo_pattern_t *other); cairo_private void _cairo_pattern_init_solid (cairo_solid_pattern_t *pattern, @@ -1715,6 +1740,9 @@ _cairo_pattern_fini (cairo_pattern_t *pattern); cairo_private cairo_pattern_t * _cairo_pattern_create_solid (const cairo_color_t *color); +cairo_pattern_t * +_cairo_pattern_create_in_error (cairo_status_t status); + cairo_private void _cairo_pattern_transform (cairo_pattern_t *pattern, const cairo_matrix_t *ctm_inverse); diff --git a/test/.cvsignore b/test/.cvsignore index beaae22b7..0b4c1531c 100644 --- a/test/.cvsignore +++ b/test/.cvsignore @@ -20,6 +20,8 @@ move-to-show-surface paint paint-with-alpha path-data +pdf-clip +pdf-clip.pdf pdf-surface pdf-surface.pdf ps-surface @@ -29,6 +31,7 @@ rel-path scale-source-surface-paint select-font-no-show-text self-copy +self-intersecting set-source source-clip source-surface-scale-paint diff --git a/test/Makefile.am b/test/Makefile.am index 0ab593678..48204192d 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -20,6 +20,7 @@ pixman-rotate \ scale-source-surface-paint \ select-font-no-show-text \ self-copy \ +self-intersecting \ set-source \ source-clip \ source-surface-scale-paint \ @@ -34,7 +35,7 @@ user-data \ rel-path if CAIRO_HAS_PDF_SURFACE -TESTS += pdf-surface +TESTS += pdf-surface pdf-clip endif if CAIRO_HAS_PS_SURFACE @@ -67,6 +68,7 @@ path-data-ref.png \ pixman-rotate-ref.png \ romedalen.png \ self-copy-ref.png \ +self-intersecting-ref.png \ scale-source-surface-paint-ref.png \ set-source-ref.png \ source-clip-ref.png \ @@ -93,7 +95,7 @@ rel-path-ref.png XFAIL_TESTS = \ filter-nearest-offset \ pixman-rotate \ -self-copy \ +self-intersecting \ source-surface-scale-paint \ text-rotate @@ -103,7 +105,12 @@ check_PROGRAMS = $(TESTS) # not be the most portable approach, but it is pragmatic and I'm # willing to do something cleaner as soon as it causes someone a # problem. -INCLUDES = -D_GNU_SOURCE -I$(srcdir) $(CAIRO_CFLAGS) -I$(top_srcdir)/src +INCLUDES = \ + -D_GNU_SOURCE \ + $(CAIRO_CFLAGS) \ + -I$(srcdir) \ + -I$(top_srcdir)/src \ + -I$(top_builddir)/src noinst_LTLIBRARIES = libcairotest.la @@ -141,11 +148,13 @@ paint_LDADD = $(LDADDS) paint_with_alpha_LDADD = $(LDADDS) path_data_LDADD = $(LDADDS) pdf_surface_LDADD = $(LDADDS) +pdf_clip_LDADD = $(LDADDS) ps_surface_LDADD = $(LDADDS) pixman_rotate_LDADD = $(LDADDS) scale_source_surface_paint_LDADD = $(LDADDS) select_font_no_show_text_LDADD = $(LDADDS) self_copy_LDADD = $(LDADDS) +self_intersecting_LDADD = $(LDADDS) set_source_LDADD = $(LDADDS) source_clip_LDADD = $(LDADDS) source_surface_scale_paint_LDADD = $(LDADDS) @@ -163,4 +172,10 @@ xlib_surface_LDADD = $(LDADDS) noinst_PROGRAMS = imagediff imagediff_LDADD = $(LDADDS) -CLEANFILES = *-out.png *-diff.png *.log ps-surface.ps pdf-surface.pdf +CLEANFILES = \ + *-out.png \ + *-diff.png \ + *.log \ + ps-surface.ps \ + pdf-surface.pdf \ + pdf-clip.pdf diff --git a/test/cairo-test.c b/test/cairo-test.c index d8ce6800f..a17cd6f8b 100644 --- a/test/cairo-test.c +++ b/test/cairo-test.c @@ -440,7 +440,8 @@ cairo_test_for_target (cairo_test_t *test, } if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) { - cairo_test_log ("Error: Function under test left cairo status in an error state: %s\n", cairo_status_string (cr)); + cairo_test_log ("Error: Function under test left cairo status in an error state: %s\n", + cairo_status_to_string (cairo_status (cr))); return CAIRO_TEST_FAILURE; } diff --git a/test/clip-twice-ref.png b/test/clip-twice-ref.png Binary files differindex ab0ae1aeb..bd3e3dbec 100644 --- a/test/clip-twice-ref.png +++ b/test/clip-twice-ref.png diff --git a/test/clip-twice.c b/test/clip-twice.c index eebfec944..446447c68 100644 --- a/test/clip-twice.c +++ b/test/clip-twice.c @@ -63,6 +63,12 @@ draw (cairo_t *cr, int width, int height) cairo_close_path (cr); cairo_fill (cr); + cairo_new_path (cr); + cairo_arc (cr, WIDTH / 2, HEIGHT / 2, WIDTH / 5, 0, 2 * M_PI); + cairo_clip (cr); + cairo_set_source_rgb (cr, 1, 1, 0); + cairo_paint (cr); + return CAIRO_TEST_SUCCESS; } diff --git a/test/pdf-clip.c b/test/pdf-clip.c new file mode 100644 index 000000000..4d6d75cf8 --- /dev/null +++ b/test/pdf-clip.c @@ -0,0 +1,134 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * 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 + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Kristian Høgsberg <krh@redhat.com> + */ + +#include <stdio.h> + +#include <cairo-pdf.h> +#include "cairo-test.h" + +/* Test PDF clipping */ + +#define WIDTH_IN_POINTS 600 +#define HEIGHT_IN_POINTS 600 + +static void +test_clip (cairo_t *cr, double width, double height) +{ + cairo_t *cr2; + + /* Basic test; set a square clip and draw a circle to be clipped + * against it.*/ + + cairo_rectangle (cr, 100, 100, 400, 400); + cairo_clip (cr); + cairo_arc (cr, 300, 300, 210, 0, 2 * M_PI); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill (cr); + + /* Add a plus shaped clip path to the square clip and draw a big + * green square to test the new clip path. */ + + cairo_save (cr); + + cairo_rectangle (cr, 250, 100, 100, 400); + cairo_rectangle (cr, 100, 250, 400, 100); + cairo_clip (cr); + + cairo_rectangle (cr, 0, 0, 600, 600); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_fill (cr); + + cairo_restore (cr); + + /* Set a bezier shape in addition to the rectangle clip set before + * the cairo_save() to verify that we successfully removed the + * plus shaped clip path and can set a new clip.*/ + + cairo_move_to (cr, 600, 0); + cairo_curve_to (cr, 300, 600, 0, 300, 600, 0); + cairo_clip (cr); + + cairo_rectangle (cr, 0, 0, 600, 600); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_fill (cr); + + /* Create a new context for this surface to test overlapped + * drawing from two contexts */ + cr2 = cairo_create (cairo_get_target (cr)); + + /* Using the new context, draw a black vertical line, which should + * appear unclipped on top of everything drawn so far. */ + cairo_move_to (cr2, 110, 0); + cairo_line_to (cr2, 110, 600); + cairo_stroke (cr2); + + /* Using the first context, draw another black vertical line. + * This line should be clipped agaist the bezier clipping path set + * earlier. */ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_move_to (cr, 400, 0); + cairo_line_to (cr, 400, 600); + cairo_stroke (cr); + + cairo_destroy (cr2); + + /* Test reset clip. Draw a transparent black circle over + * everything. Specifically, make sure the circle extends outside + * the square clip set at the top of this function. */ + cairo_reset_clip (cr); + cairo_arc (cr, 300, 300, 220, 0, 2 * M_PI); + cairo_set_source_rgba (cr, 0, 0, 0, 0.2); + cairo_fill (cr); +} + +int +main (void) +{ + cairo_t *cr; + const char *filename = "pdf-clip.pdf"; + cairo_surface_t *surface; + + printf("\n"); + + surface = cairo_pdf_surface_create (filename, + WIDTH_IN_POINTS, HEIGHT_IN_POINTS); + if (surface == NULL) { + fprintf (stderr, "Failed to create pdf surface for file %s\n", filename); + return CAIRO_TEST_FAILURE; + } + + cr = cairo_create (surface); + + test_clip (cr, WIDTH_IN_POINTS, HEIGHT_IN_POINTS); + cairo_show_page (cr); + + cairo_destroy (cr); + cairo_surface_destroy (surface); + + printf ("pdf-surface: Please check %s to make sure it looks happy.\n", + filename); + + return 0; +} diff --git a/test/self-copy.c b/test/self-copy.c index 3ad406ecc..5f4398b25 100644 --- a/test/self-copy.c +++ b/test/self-copy.c @@ -85,6 +85,5 @@ draw (cairo_t *cr, int width, int height) int main (void) { - return cairo_test_expect_failure (&test, draw, - "copying from a surface to itself doesn't handle clipping properly"); + return cairo_test (&test, draw); } diff --git a/test/self-intersecting-ref.png b/test/self-intersecting-ref.png Binary files differnew file mode 100644 index 000000000..384b0abc0 --- /dev/null +++ b/test/self-intersecting-ref.png diff --git a/test/self-intersecting.c b/test/self-intersecting.c new file mode 100644 index 000000000..2dfd79681 --- /dev/null +++ b/test/self-intersecting.c @@ -0,0 +1,89 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * 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 + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth <cworth@cworth.org> + */ + +/* Bug history + * + * 2005-06-01 Carl Worth <cworth@cworth.org> + * + * There's a long-standing bug in that self-intersecting paths give + * an incorrect result when stroked. The problem is that the + * trapezoids are generated incrementally along the stroke and as + * such, are not disjoint. The errant intersections of these + * trapezoids then leads to overfilled pixels. + * + * The test belows first creates and fills a path. Then it creates a + * second path which has a stroked boundary identical to the first + * filled path. But the results of the two operations are + * different. The most obvious difference is in the central region + * where the entire path intersects itself. But notice that every + * time the path turns there are also errors on the inside of the + * turn, (since the subsequent trapezoids along the path intersect). + */ + +#include "cairo-test.h" + +cairo_test_t test = { + "self-intersecting", + "Test strokes of self-intersecting paths", + 10, 20 +}; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_translate (cr, 1.0, 1.0); + + cairo_set_source_rgb (cr, 1, 0, 0); /* red */ + + /* First draw the desired shape with a fill */ + cairo_rectangle (cr, 0.5, 0.5, 4.0, 4.0); + cairo_rectangle (cr, 3.5, 3.5, 4.0, 4.0); + cairo_rectangle (cr, 3.5, 1.5, -2.0, 2.0); + cairo_rectangle (cr, 6.5, 4.5, -2.0, 2.0); + + cairo_fill (cr); + + /* Then try the same thing with a stroke */ + cairo_translate (cr, 0, 10); + cairo_move_to (cr, 1.0, 1.0); + cairo_rel_line_to (cr, 3.0, 0.0); + cairo_rel_line_to (cr, 0.0, 6.0); + cairo_rel_line_to (cr, 3.0, 0.0); + cairo_rel_line_to (cr, 0.0, -3.0); + cairo_rel_line_to (cr, -6.0, 0.0); + cairo_close_path (cr); + + cairo_set_line_width (cr, 1.0); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +int +main (void) +{ + return cairo_test_expect_failure (&test, draw, + "Self-intersecting strokes are wrong due to incremental trapezoidization."); +} |