diff --git a/gfx/cairo/Makefile.in b/gfx/cairo/Makefile.in index 191614012ce1..9f82c1220a91 100644 --- a/gfx/cairo/Makefile.in +++ b/gfx/cairo/Makefile.in @@ -42,7 +42,13 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -DIRS = libpixman/src cairo/src +DIRS = $(NULL) + +ifdef MOZ_ENABLE_GLITZ +DIRS += glitz/src +endif + +DIRS += libpixman/src cairo/src include $(topsrcdir)/config/rules.mk diff --git a/gfx/cairo/README b/gfx/cairo/README index f98e3073ebd7..a790f7f34c21 100644 --- a/gfx/cairo/README +++ b/gfx/cairo/README @@ -1,4 +1,4 @@ -Snapshots of cairo and libpixman for mozilla usage. Where possible, +Snapshots of cairo, libpixman, and glitz for mozilla usage. Where possible, these should be official releases from the cairo project as-is. If changes are necessary, they should be documented below and the patch file included in this directory. @@ -10,8 +10,9 @@ http://www.cairographics.org/. VERSIONS: - cairo 0.5.0 + cairo 0.9.1 libpixman 0.1.5 + glitz 0.4.0 ***** NOTE FOR VISUAL C++ 6.0 ***** @@ -34,11 +35,4 @@ PATCHES: allow-null-surface.diff - allow creating a cairo_t with a NULL target surface - - optimize-opaque-paint.diff - if cairo_paint_with_alpha is called - with alpha == 1.0, turn it into cairo_paint - - win32-extents.diff - correct text extents for general tranforms - (upstream patch) - atsui-empty.diff - prevent OS-X crash with empty string diff --git a/gfx/cairo/allow-null-surface.diff b/gfx/cairo/allow-null-surface.diff deleted file mode 100644 index bf29fc6738cd..000000000000 --- a/gfx/cairo/allow-null-surface.diff +++ /dev/null @@ -1,15 +0,0 @@ ---- ../../../../../cairo-cvs/dist/cairo-0.5.0/src/cairo.c 2005-05-11 19:59:13.000000000 -0700 -+++ cairo/src/cairo.c 2005-06-01 23:07:50.000000000 -0700 -@@ -115,12 +115,6 @@ - - _cairo_path_fixed_init (&cr->path); - -- if (target == NULL) { -- cr->gstate = NULL; -- cr->status = CAIRO_STATUS_NULL_POINTER; -- return cr; -- } -- - cr->gstate = _cairo_gstate_create (target); - if (cr->gstate == NULL) - cr->status = CAIRO_STATUS_NO_MEMORY; diff --git a/gfx/cairo/cairo/NEWS b/gfx/cairo/cairo/NEWS index 447583c45588..56181fde14af 100644 --- a/gfx/cairo/cairo/NEWS +++ b/gfx/cairo/cairo/NEWS @@ -1,3 +1,408 @@ +Release 0.9.0 (2005-08-08 Carl Worth ) +========================================================= +API additions +------------- + + * Add a new function call to set the current antialiasing mode in the + graphics state: + + cairo_set_antialias + + This call accepts the same modes recently added for font options + (NONE or GRAY) but affects the rendering of geometry other than + text. The intent of this call is to enable more precise control of + which pixels are affected by each operation, for example to allow + for full-scene antialiasing for seam-free rendering. It is not + expected that non-antialiased rendering will perform better than + anti-aliased rendering. + + * Three new functions were added to provide support for mixed cairo- + and non-cairo drawing to the same surface: + + cairo_surface_mark_dirty + cairo_surface_mark_dirty_rectangle + cairo_flush + + * The return type of the several "reference" functions was change, + (API compatibly), from void to the same type as the argument. The + affected functions are: + + cairo_font_face_reference + cairo_scaled_font_reference + cairo_pattern_reference + cairo_surface_reference + cairo_reference + + This allows a convenient way to assign and reference in a single + statement. + +cairo-win32 +----------- + * Some portability improvements, (eg. workaround for missing stdint.h). + +cairo-ft +-------- + * Updated to allow compilation with older versions of freetype. + +Bug fixes +--------- + * Fix the unbounded operators to actually produce a correct result, + (previously the results were artificially restricited to the + bounding box of whatever shape was being drawn rather than + extending out infinitely). The fixed operators are: + + CAIRO_OPERATOR_CLEAR + CAIRO_OPERATOR_SOURCE + CAIRO_OPERATOR_OUT + CAIRO_OPERATOR_IN + CAIRO_OPERATOR_DEST_IN + CAIRO_OPERATOR_DEST_ATOP + + * Fix cairo_mask and cairo_mask_surface to transform the mask by the + current transformation matrix (CTM). + + * Fix cairo_set_source to lock the CTM used to transform the pattern. + + * Workaround for X server Render bug involving repeating patterns + with a general transformation matrix. + + * cairo_get_font_face fixed to return a "nil" font face object rather + than NULL on error. + + * cairo_set_font_face fixed to not crash if given a NULL font face, + (which is the documented interface for restoring the defauly font + face). + + * Fix xlib glyphset caching to not try to free a NULL glyph. + +Snapshot 0.6.0 (2005-07-28 Carl Worth ) +========================================================== +API changes +----------- +* The prototypes of the following functions have changed: + + cairo_xlib_surface_create_with_xrender_format + cairo_xlib_surface_create_for_bitmap + + A Screen* parameter has been added to each. This allows the cairo + xlib backend to work correctly with multi-head X servers. + +* The following function has been modified: + + cairo_scaled_font_create + + to accept a cairo_font_options_t*. See below fore more details. + +* All opaque, reference-counted cairo objects have now been moved to a + standard error-handling scheme. The new objects to receive this + treatment are cairo_font_face_t, cairo_scaled_font_t, and + cairo_surface_t. (Previous snapshots already provided this scheme + for cairo_t, cairo_path_t, and cairo_pattern_t.) + + This changes two functions to have a return type of void rather than + cairo_status_t: + + cairo_scaled_font_extent + cairo_surface_finish + + And significantly, none of the create functions for any of the + objects listed above will return NULL. The pointer returned from any + function will now always be a valid pointer and should always be + passed to the corresponding destroy function when finished + + The simplest strategy for porting code is to switch from: + + object = cairo__create (); + if (object == NULL) + goto BAILOUT; + + /* act on object */ + + cairo__destroy (object); + + to: + + object = cairo__create (); + if (cairo__status (object)) + goto BAILOUT; + + /* act on object */ + + cairo__destroy (object); + + But significantly, it is not required to check for an error status + before the "act on object" portions of the code above. All + operations on an object with an error status are, by definition, + no-ops without side effect. So new code might be written in an + easier-to-read style of: + + object = cairo__create (); + + /* act on object */ + + cairo__destroy (object); + + with cairo__status checks placed only at strategic + locations. For example, passing an error object to another object, + (eg. cairo_set_source with an in-error pattern), will propagate the + error to the subsequent object (eg. the cairo_t). This means that + error checking can often be deferred even beyond the destruction of + a temporary object. + +API additions +------------- +* New functions for checking the status of objects that have been + switched to the common error-handling scheme: + + cairo_font_face_status + cairo_scaled_font_status + cairo_surface_status + +* The _cairo_error function which was added in 0.5.1 has now been made + much more useful. In 0.5.1 only errors on cairo_t objects passed + through _cairo_error. Now, an error on any object should pass + through _cairo_error making it much more reliable as a debugging + mechanism for finding when an error first occurs. + +* Added new font options support with a myriad of functions: + + cairo_font_options_create + cairo_font_options_copy + cairo_font_options_destroy + + cairo_font_options_status + + cairo_font_options_merge + cairo_font_options_equal + cairo_font_options_hash + + cairo_font_options_set_antialias + cairo_font_options_get_antialias + cairo_font_options_set_subpixel_order + cairo_font_options_get_subpixel_order + cairo_font_options_set_hint_style + cairo_font_options_get_hint_style + cairo_font_options_set_hint_metrics + cairo_font_options_get_hint_metrics + + cairo_surface_get_font_options + + cairo_ft_font_options_substitute + + cairo_set_font_options + cairo_get_font_options + + This new font options support allows the application to have much + more fine-grained control over how fonts are rendered. + Significantly, it also allows surface backends to have some + influence over the process. For example, the xlib backend now + queries existing Xft properties to set font option defaults. + +* New function: + + cairo_xlib_surface_set_drawable + + which allos the target drawable for an xlib cairo_surface_t to be + changed to another with the same format, screen, and display. This + is necessary in certain double-buffering techniques. + +New features +------------ +* Sub-pixel text antialiasing is now supported. + +Bug fixes +--------- +* Fixed assertion failure in cairo_surface_create_similar when + application commits an error by passing a cairo_format_t rather than + a cairo_content_t. + +* Avoid division by zero in various places (cairo-ft). + +* Fix infinite loop when using non-default visuals (cairo-xlib). + +* Eliminate segfault in cairo_image_surface_create_from_png_stream. + +* Prevent errant sign-extension of masks on 64-bit architectures + (cairo-xlib and cairo-xcb). + +* Other miscellaneous fixes. + +Snapshot 0.5.2 (2005-07-18 Carl Worth ) +========================================================== +API changes +----------- +* New functions for creating patterns of a single color: + + cairo_pattern_create_rgb + cairo_pattern_create_rgba + +* Change cairo_surface_create_similar to accept a new type of + cairo_content_t rather than cairo_format_t: + + typedef enum _cairo_content { + CAIRO_CONTENT_COLOR = 0x1000, + CAIRO_CONTENT_ALPHA = 0x2000, + CAIRO_CONTENT_COLOR_ALPHA = 0x3000 + } cairo_content_t; + +* Add new CAIRO_FORMAT_VALID and CAIRO_CONTENT_VALID macros. + +* Remove unused status value: + + CAIRO_STATUS_NO_TARGET_SURFACE + +* Add new status values: + + CAIRO_STATUS_INVALID_STATUS + +* Require libpixman >= 0.1.5 (for necessary bug fixes) + +Bug fixes +--------- +* Fix cairo_surface_write_to_png for RGB24 images. + +* Fix broken metrics and rendering for bitmap fonts. Add mostly + useless bitmap glyph transformation. + +* Fix glyph caches to not eject entries that might be immediately + needed, (fixing intermittent crashes when rendering text). + +* Fix all memory leaks found by running "make check-valigrind". + +ATSUI backend changes +--------------------- +* Allow building against < 10.3 SDK. + +* Prevent crash on empty strings. + +Glitz backend changes +--------------------- +* Require glitz >= 0.4.4. + +* Use frame buffer objects instead of pbuffers for accelerated + offscreen drawing. + +* Minor improvement to gradient pattern creation. + +PostScript backend fixes +------------------------ +* Rewrite of the PS backend to generate more interesting output that + the old big-image implementation. + +Win32 backend fixes +------------------- +* Implement glyph path support. + +* Fix swap of blue and green values in the fill_rectangles path. + +Xlib backend fixes +------------------ +* Add optimization to use XCopyArea rather than XRenderComposite when + transforming only with an integer translation, and using SOURCE + operator or OVER with a source pattern without alpha. + +Snapshot 0.5.1 (2005-06-20 Carl Worth ) +========================================================== +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 ) ========================================================== This is a pretty big, and fairly significant snapshot. It represents diff --git a/gfx/cairo/cairo/TODO b/gfx/cairo/cairo/TODO index ea44263ede82..7a8e1641dca8 100644 --- a/gfx/cairo/cairo/TODO +++ b/gfx/cairo/cairo/TODO @@ -1,105 +1,40 @@ -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__surface_mark_dirty - Consistent error handling for all objects +PDR C cairo_surface_mark_dirty (see below for details) +PDRTC 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) +P 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 -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 +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 +PDR C Consistent error handling for all objects +PDRTC 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_text_glyphs: -* Add support for non-antialiased rendering. API ? - -* Clean up the cache code a bit, (there is at least one redundant - level of cacheing, and there are some minor style issues). - -* Add CAIRO_FILL_RULE_INVERSE_WINDING and CAIRO_FILL_RULE_INVERSE_EVEN_ODD - -* Fix clipping to work for all operators. The equation we have come up - with is: - - ((src Op dest) In clip) Add (dest Out clip) - -* Split cairo_format_t into two things: - - - An enumeration that determines the "capabilities" of a surface - - A vs. ARGB. vs. RGB - - An enumeration that determines a specific in-memory representation - of data. (A1/A8/ARGB32/etc.. Could be extensible to things like - RGBA32_BYTES_NONPREMULTIPLIED. Some consistent naming convention would - be be good.) - - One issue here is that some interfaces, like cairo_surface_create_similar() - might be useful with either one. We might want to create an A1 surface - compatible with the backend (are there examples other than A1? Should - bilevel just be another "capability"?), or we might want to just create - an alpha surface without caring about the depth. - - If we want to support this, we could do something like: - - typedef enum cairo_pixel_format_t { - CAIRO_PIXEL_FORMAT_A8 = CAIRO_FORMAT_ALPHA, - CAIRO_PIXEL_FORMAT_RGB24 = CAIRO_FORMAT_RGB, - CAIRO_PIXEL_FORMAT_A1, - }; - - To allow passing either in. - - (I don't particularly like this idea for create_similar() because then you - aren't really saying ALPHA-dont-care, you are saying ALPHA-8. I think it - would be better to have a separate path for create_similar_with_pixel_format() - if we need that. But it might be useful for cairo_image_surface_create() ... - 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. - -* Make a more interesting PS backend, (other than the current -"giant-image for every page" approach). - -* Figure out what to do with DPI for image/png backends. - -* 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. - -* 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): + 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, @@ -118,56 +53,34 @@ toy and the real text API): > as long as the original size of glyphs/num_glyphs was large > enough. -* Implement dashing for cairo_curve_to. +* support for custom caps: -* 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 + 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. +Changes that do not affect the public API +========================================= +* Fix clipping to work for all operators. The equation we have come up + with is: + + ((src Op dest) In clip) Add (dest Out clip) + +* Change stroke code to go through one giant polygon. This will fix + problems with stroking self-intersecting paths. + +* Fix the intersection problem, (see reference to Hobby's paper + mentioned in cairo_traps.c). + +* Implement dashing for cairo_curve_to. + +* Stroking closed, degenerate paths should still draw caps. Round + caps are easy; square should probably draw an axis-aligned square. + * 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/gfx/cairo/cairo/src/Makefile.in b/gfx/cairo/cairo/src/Makefile.in index 34b2603241a5..2a30b29e3e2d 100644 --- a/gfx/cairo/cairo/src/Makefile.in +++ b/gfx/cairo/cairo/src/Makefile.in @@ -36,88 +36,97 @@ # # ***** END LICENSE BLOCK ***** -DEPTH = ../../../.. -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -MODULE = cairo -LIBRARY_NAME = mozcairo +MODULE = cairo +LIBRARY_NAME = mozcairo LIBXUL_LIBRARY = 1 -REQUIRES = $(PNG_REQUIRES) \ - $(ZLIB_REQUIRES) \ - libpixman \ - $(NULL) +REQUIRES = $(PNG_REQUIRES) \ + $(ZLIB_REQUIRES) \ + libpixman \ + $(NULL) -CSRCS = \ - cairo.c \ - cairo-arc.c \ - cairo-array.c \ - cairo-cache.c \ - cairo-color.c \ - cairo-fixed.c \ - cairo-font.c \ - cairo-gstate.c \ - cairo-hull.c \ - cairo-image-surface.c \ - cairo-matrix.c \ - cairo-output-stream.c \ - cairo-path.c \ - cairo-path-bounds.c \ - cairo-path-data.c \ - cairo-path-fill.c \ - cairo-path-stroke.c \ - cairo-pattern.c \ - cairo-pen.c \ - cairo-polygon.c \ - cairo-slope.c \ - cairo-spline.c \ - cairo-surface.c \ - cairo-traps.c \ - cairo-unicode.c \ - cairo-wideint.c \ - $(NULL) +CSRCS = \ + cairo.c \ + cairo-arc.c \ + cairo-array.c \ + cairo-cache.c \ + cairo-clip.c \ + cairo-color.c \ + cairo-debug.c \ + cairo-fixed.c \ + cairo-font.c \ + cairo-font-options.c \ + cairo-gstate.c \ + cairo-hash.c \ + cairo-hull.c \ + cairo-image-surface.c \ + cairo-matrix.c \ + cairo-meta-surface.c \ + cairo-output-stream.c \ + cairo-path.c \ + cairo-path-bounds.c \ + cairo-path-data.c \ + cairo-path-fill.c \ + cairo-path-stroke.c \ + cairo-pattern.c \ + cairo-pen.c \ + cairo-polygon.c \ + cairo-region.c \ + cairo-slope.c \ + cairo-spline.c \ + cairo-surface.c \ + cairo-traps.c \ + cairo-unicode.c \ + cairo-wideint.c \ + $(NULL) -EXPORTS = cairo.h cairo-features.h +EXPORTS = cairo.h cairo-features.h ifeq ($(MOZ_GFX_TOOLKIT),windows) -CSRCS += cairo-win32-font.c \ - cairo-win32-surface.c +CSRCS += cairo-win32-font.c \ + cairo-win32-surface.c EXPORTS += cairo-win32.h endif ifneq (,$(filter mac cocoa,$(MOZ_GFX_TOOLKIT))) -CSRCS += cairo-quartz-surface.c \ - cairo-atsui-font.c -EXPORTS += cairo-quartz.h +CSRCS += cairo-quartz-surface.c \ + cairo-atsui-font.c +EXPORTS += cairo-quartz.h cairo-atsui.h endif ifdef BUILD_CAIRO_PDF -CSRCS += cairo-pdf-surface.c \ - cairo-ps-surface.c +CSRCS += cairo-font-subset.c \ + cairo-pdf-surface.c \ + cairo-ps-surface.c EXPORTS += cairo-ps.h cairo-pdf.h endif ifdef MOZ_X11 -CSRCS += cairo-xlib-surface.c \ - cairo-ft-font.c -EXPORTS += cairo-xlib.h +CSRCS += cairo-xlib-surface.c \ + cairo-xlib-screen.c \ + cairo-ft-font.c +EXPORTS += cairo-xlib.h cairo-xlib-xrender.h cairo-ft.h LOCAL_INCLUDES += $(FT2_CFLAGS) endif -ifdef BUILD_CAIRO_GL -CSRCS += cairo-glitz-surface.c -EXPORTS += cairo-glitz.h +ifdef MOZ_ENABLE_GLITZ +REQUIRES += glitz +CSRCS += cairo-glitz-surface.c +EXPORTS += cairo-glitz.h endif -LOCAL_INCLUDES += -I$(srcdir) +LOCAL_INCLUDES += -I$(srcdir) FORCE_STATIC_LIB = 1 # This library is used by other shared libs in a static build diff --git a/gfx/cairo/cairo/src/cairo-arc-private.h b/gfx/cairo/cairo/src/cairo-arc-private.h index 1cd41cc152d8..633fbfa5a3a2 100644 --- a/gfx/cairo/cairo/src/cairo-arc-private.h +++ b/gfx/cairo/cairo/src/cairo-arc-private.h @@ -38,7 +38,7 @@ #include "cairoint.h" -void +cairo_private void _cairo_arc_path (cairo_t *cr, double xc, double yc, @@ -46,7 +46,7 @@ _cairo_arc_path (cairo_t *cr, double angle1, double angle2); -void +cairo_private void _cairo_arc_path_negative (cairo_t *cr, double xc, double yc, diff --git a/gfx/cairo/cairo/src/cairo-arc.c b/gfx/cairo/cairo/src/cairo-arc.c index 6192c7e1cf46..e9f35993e457 100644 --- a/gfx/cairo/cairo/src/cairo-arc.c +++ b/gfx/cairo/cairo/src/cairo-arc.c @@ -100,6 +100,8 @@ _arc_max_angle_for_tolerance_normalized (double tolerance) return angle; } +/* XXX: The computation here if bogus. Correct math (with proof!) is + * available in _cairo_pen_vertices_needed. */ static int _arc_segments_needed (double angle, double radius, diff --git a/gfx/cairo/cairo/src/cairo-array.c b/gfx/cairo/cairo/src/cairo-array.c index a37ea9af581d..ef7f77fcae99 100644 --- a/gfx/cairo/cairo/src/cairo-array.c +++ b/gfx/cairo/cairo/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; @@ -198,6 +198,11 @@ _cairo_user_data_array_get_data (cairo_user_data_array_t *array, int i, num_slots; cairo_user_data_slot_t *slots; + /* We allow this to support degenerate objects such as + * cairo_image_surface_nil. */ + if (array == NULL) + return NULL; + num_slots = array->num_elements; slots = (cairo_user_data_slot_t *) array->elements; for (i = 0; i < num_slots; i++) { diff --git a/gfx/cairo/cairo/src/cairo-atsui-font.c b/gfx/cairo/cairo/src/cairo-atsui-font.c index c12bf858ba28..69e375290571 100644 --- a/gfx/cairo/cairo/src/cairo-atsui-font.c +++ b/gfx/cairo/cairo/src/cairo-atsui-font.c @@ -68,7 +68,6 @@ typedef struct cairo_ATSUI_glyph_path_callback_info_t { const cairo_scaled_font_backend_t cairo_atsui_scaled_font_backend; - static CGAffineTransform CGAffineTransformMakeWithCairoFontScale(cairo_matrix_t *scale) { @@ -77,7 +76,6 @@ CGAffineTransformMakeWithCairoFontScale(cairo_matrix_t *scale) 0, 0); } - static ATSUStyle CreateSizedCopyOfStyle(ATSUStyle inStyle, cairo_matrix_t *scale) { @@ -107,12 +105,11 @@ CreateSizedCopyOfStyle(ATSUStyle inStyle, cairo_matrix_t *scale) static cairo_status_t -_cairo_atsui_font_create(const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - cairo_scaled_font_t **font_out) +_cairo_atsui_font_create_toy(cairo_toy_font_face_t *toy_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **font_out) { cairo_atsui_font_t *font = NULL; ATSUStyle style; @@ -120,11 +117,11 @@ _cairo_atsui_font_create(const char *family, OSStatus err; Boolean isItalic, isBold; cairo_matrix_t scale; + const char *family = toy_face->family; err = ATSUCreateStyle(&style); - - switch (weight) { + switch (toy_face->weight) { case CAIRO_FONT_WEIGHT_BOLD: isBold = true; break; @@ -134,7 +131,7 @@ _cairo_atsui_font_create(const char *family, break; } - switch (slant) { + switch (toy_face->slant) { case CAIRO_FONT_SLANT_ITALIC: isItalic = true; break; @@ -190,7 +187,7 @@ _cairo_atsui_font_create(const char *family, font = malloc(sizeof(cairo_atsui_font_t)); - _cairo_scaled_font_init(&font->base, font_matrix, ctm, + _cairo_scaled_font_init(&font->base, toy_face, font_matrix, ctm, options, &cairo_atsui_scaled_font_backend); cairo_matrix_multiply(&scale, font_matrix, ctm); @@ -215,13 +212,11 @@ _cairo_atsui_font_create(const char *family, return CAIRO_STATUS_SUCCESS; } - static void -_cairo_atsui_font_destroy_font(void *abstract_font) +_cairo_atsui_font_fini(void *abstract_font) { cairo_atsui_font_t *font = abstract_font; - if (font == NULL) return; @@ -501,14 +496,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 // @@ -690,10 +687,9 @@ _cairo_atsui_font_glyph_path(void *abstract_font, return CAIRO_STATUS_SUCCESS; } - const cairo_scaled_font_backend_t cairo_atsui_scaled_font_backend = { - _cairo_atsui_font_create, - _cairo_atsui_font_destroy_font, + _cairo_atsui_font_create_toy, + _cairo_atsui_font_fini, _cairo_atsui_font_font_extents, _cairo_atsui_font_text_to_glyphs, _cairo_atsui_font_glyph_extents, diff --git a/gfx/cairo/cairo/src/cairo-atsui.h b/gfx/cairo/cairo/src/cairo-atsui.h index e65e3be7c121..72e2d6d15e1b 100644 --- a/gfx/cairo/cairo/src/cairo-atsui.h +++ b/gfx/cairo/cairo/src/cairo-atsui.h @@ -38,7 +38,7 @@ #include -#ifdef CAIRO_HAS_ATSUI_FONT +#if CAIRO_HAS_ATSUI_FONT /* ATSUI platform-specific font interface */ diff --git a/gfx/cairo/cairo/src/cairo-cache.c b/gfx/cairo/cairo/src/cairo-cache.c index e95894960664..b43bccabfff5 100644 --- a/gfx/cairo/cairo/src/cairo-cache.c +++ b/gfx/cairo/cairo/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; @@ -361,31 +366,33 @@ _cairo_cache_init (cairo_cache_t *cache, return CAIRO_STATUS_SUCCESS; } -void -_cairo_cache_reference (cairo_cache_t *cache) -{ - _cache_sane_state (cache); - cache->refcount++; -} - void _cairo_cache_destroy (cairo_cache_t *cache) { unsigned long i; - if (cache != NULL) { + 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); +} + +void +_cairo_cache_shrink_to (cairo_cache_t *cache, + unsigned long max_memory) +{ + unsigned long idx; + /* Make some entries die if we're under memory pressure. */ + while (cache->live_entries > 0 && cache->used_memory > max_memory) { + idx = _random_entry (cache, NULL) - cache->entries; + assert (idx < cache->arrangement->size); + _entry_destroy (cache, idx); } } @@ -396,7 +403,6 @@ _cairo_cache_lookup (cairo_cache_t *cache, int *created_entry) { - unsigned long idx; cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_cache_entry_base_t **slot = NULL, *new_entry; @@ -446,14 +452,8 @@ _cairo_cache_lookup (cairo_cache_t *cache, /* Store the hash value in case the backend forgot. */ new_entry->hashcode = cache->backend->hash (cache, key); - /* Make some entries die if we're under memory pressure. */ - while (cache->live_entries > 0 && - cache->max_memory > 0 && - ((cache->max_memory - cache->used_memory) < new_entry->memory)) { - idx = _random_entry (cache, NULL) - cache->entries; - assert (idx < cache->arrangement->size); - _entry_destroy (cache, idx); - } + if (cache->live_entries && cache->max_memory) + _cairo_cache_shrink_to (cache, cache->max_memory); /* Can't assert this; new_entry->memory may be larger than max_memory */ /* assert(cache->max_memory >= (cache->used_memory + new_entry->memory)); */ @@ -512,7 +512,7 @@ _cairo_hash_string (const char *c) { /* This is the djb2 hash. */ unsigned long hash = 5381; - while (*c) + while (c && *c) hash = ((hash << 5) + hash) + *c++; return hash; } diff --git a/gfx/cairo/cairo/src/cairo-clip-private.h b/gfx/cairo/cairo/src/cairo-clip-private.h new file mode 100644 index 000000000000..23eb78c90a81 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-clip-private.h @@ -0,0 +1,123 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Kristian Høgsberg + */ + +#ifndef CAIRO_CLIP_PRIVATE_H +#define CAIRO_CLIP_PRIVATE_H + +#include "cairo-path-fixed-private.h" + +enum _cairo_clip_mode { + CAIRO_CLIP_MODE_PATH, + CAIRO_CLIP_MODE_REGION, + CAIRO_CLIP_MODE_MASK +}; + +struct _cairo_clip_path { + unsigned int ref_count; + cairo_path_fixed_t path; + cairo_fill_rule_t fill_rule; + double tolerance; + cairo_antialias_t antialias; + cairo_clip_path_t *prev; +}; + +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_private void +_cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target); + +cairo_private void +_cairo_clip_fini (cairo_clip_t *clip); + +cairo_private void +_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other); + +cairo_private cairo_status_t +_cairo_clip_reset (cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_clip_clip (cairo_clip_t *clip, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_surface_t *target); + +cairo_private cairo_status_t +_cairo_clip_intersect_to_rectangle (cairo_clip_t *clip, + cairo_rectangle_t *rectangle); + +cairo_private cairo_status_t +_cairo_clip_intersect_to_region (cairo_clip_t *clip, + pixman_region16_t *region); + +cairo_private cairo_status_t +_cairo_clip_combine_to_surface (cairo_clip_t *clip, + cairo_operator_t operator, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_t *extents); + +#endif /* CAIRO_CLIP_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-clip.c b/gfx/cairo/cairo/src/cairo-clip.c new file mode 100644 index 000000000000..6fad20738d69 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-clip.c @@ -0,0 +1,437 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Kristian Høgsberg + */ + +#include "cairoint.h" +#include "cairo-clip-private.h" + +static cairo_clip_path_t * +_cairo_clip_path_reference (cairo_clip_path_t *clip_path); + +static void +_cairo_clip_path_destroy (cairo_clip_path_t *clip_path); + +void +_cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target) +{ + clip->mode = _cairo_surface_get_clip_mode (target); + clip->region = NULL; + clip->surface = NULL; + clip->serial = 0; + clip->path = NULL; +} + +void +_cairo_clip_fini (cairo_clip_t *clip) +{ + if (clip->surface) + cairo_surface_destroy (clip->surface); + clip->surface = NULL; + + if (clip->path) + _cairo_clip_path_destroy (clip->path); + clip->path = NULL; + + if (clip->region) + pixman_region_destroy (clip->region); + clip->region = NULL; + clip->serial = 0; +} + +void +_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other) +{ + if (other->region) { + clip->region = pixman_region_create (); + pixman_region_copy (clip->region, other->region); + } + + cairo_surface_reference (other->surface); + clip->surface = other->surface; + _cairo_clip_path_reference (other->path); + clip->path = other->path; +} + +cairo_status_t +_cairo_clip_reset (cairo_clip_t *clip) +{ + /* destroy any existing clip-region artifacts */ + if (clip->surface) + cairo_surface_destroy (clip->surface); + clip->surface = NULL; + + if (clip->region) + pixman_region_destroy (clip->region); + clip->region = NULL; + + if (clip->path) + _cairo_clip_path_destroy (clip->path); + clip->path = NULL; + + clip->serial = 0; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_clip_intersect_to_rectangle (cairo_clip_t *clip, + cairo_rectangle_t *rectangle) +{ + if (clip->path) { + /* Intersect path extents here. */ + } + + if (clip->region) { + pixman_region16_t *intersection; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + pixman_region_status_t pixman_status; + + intersection = _cairo_region_create_from_rectangle (rectangle); + if (intersection == NULL) + return CAIRO_STATUS_NO_MEMORY; + + pixman_status = pixman_region_intersect (intersection, + clip->region, + intersection); + if (pixman_status == PIXMAN_REGION_STATUS_SUCCESS) + _cairo_region_extents_rectangle (intersection, rectangle); + else + status = CAIRO_STATUS_NO_MEMORY; + + pixman_region_destroy (intersection); + + if (status) + return status; + } + + if (clip->surface) + _cairo_rectangle_intersect (rectangle, &clip->surface_rect); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_clip_intersect_to_region (cairo_clip_t *clip, + pixman_region16_t *region) +{ + if (clip->path) { + /* Intersect clip path into region. */ + } + + if (clip->region) + pixman_region_intersect (region, clip->region, region); + + if (clip->surface) { + pixman_region16_t *clip_rect; + pixman_region_status_t pixman_status; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + clip_rect = _cairo_region_create_from_rectangle (&clip->surface_rect); + if (clip_rect == NULL) + return CAIRO_STATUS_NO_MEMORY; + + pixman_status = pixman_region_intersect (region, + clip_rect, + region); + if (pixman_status != PIXMAN_REGION_STATUS_SUCCESS) + status = CAIRO_STATUS_NO_MEMORY; + + pixman_region_destroy (clip_rect); + + if (status) + return status; + } + + return CAIRO_STATUS_SUCCESS; +} + +/* Combines the region of clip->surface given by extents in + * device backend coordinates into the given temporary surface, + * which has its origin at dst_x, dst_y in backend coordinates + */ +cairo_status_t +_cairo_clip_combine_to_surface (cairo_clip_t *clip, + cairo_operator_t operator, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_t *extents) +{ + cairo_pattern_union_t pattern; + cairo_status_t status; + + _cairo_pattern_init_for_surface (&pattern.surface, clip->surface); + + status = _cairo_surface_composite (operator, + &pattern.base, + NULL, + dst, + extents->x - clip->surface_rect.x, + extents->y - clip->surface_rect.y, + 0, 0, + extents->x - dst_x, + extents->y - dst_y, + extents->width, extents->height); + + _cairo_pattern_fini (&pattern.base); + + return status; +} + +static cairo_status_t +_cairo_clip_intersect_path (cairo_clip_t *clip, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_surface_t *target) +{ + cairo_clip_path_t *clip_path; + cairo_status_t status; + + if (clip->mode != CAIRO_CLIP_MODE_PATH) + return CAIRO_INT_STATUS_UNSUPPORTED; + + 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; + + clip_path->ref_count = 1; + clip_path->fill_rule = fill_rule; + clip_path->tolerance = tolerance; + clip_path->antialias = antialias; + clip_path->prev = clip->path; + clip->path = clip_path; + clip->serial = _cairo_surface_allocate_clip_serial (target); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_clip_path_t * +_cairo_clip_path_reference (cairo_clip_path_t *clip_path) +{ + if (clip_path == NULL) + return NULL; + + clip_path->ref_count++; + + return clip_path; +} + +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_clip_intersect_region (cairo_clip_t *clip, + cairo_traps_t *traps, + cairo_surface_t *target) +{ + pixman_region16_t *region; + cairo_status_t status; + + if (clip->mode != CAIRO_CLIP_MODE_REGION) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_traps_extract_region (traps, ®ion); + if (status) + return status; + + if (region == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = CAIRO_STATUS_SUCCESS; + if (clip->region == NULL) { + clip->region = region; + } else { + pixman_region16_t *intersection = pixman_region_create(); + + if (pixman_region_intersect (intersection, + clip->region, region) + == PIXMAN_REGION_STATUS_SUCCESS) { + pixman_region_destroy (clip->region); + clip->region = intersection; + } else { + status = CAIRO_STATUS_NO_MEMORY; + } + pixman_region_destroy (region); + } + + clip->serial = _cairo_surface_allocate_clip_serial (target); + + return status; +} + +static cairo_status_t +_cairo_clip_intersect_mask (cairo_clip_t *clip, + cairo_traps_t *traps, + cairo_antialias_t antialias, + cairo_surface_t *target) +{ + 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 (clip->surface != NULL) + _cairo_rectangle_intersect (&surface_rect, &clip->surface_rect); + + surface = _cairo_surface_create_similar_solid (target, + CAIRO_CONTENT_ALPHA, + surface_rect.width, + surface_rect.height, + CAIRO_COLOR_WHITE); + if (surface->status) + return CAIRO_STATUS_NO_MEMORY; + + /* Render the new clipping path into the new mask surface. */ + + _cairo_traps_translate (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, + surface, + antialias, + 0, 0, + 0, 0, + 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 (clip->surface != NULL) { + _cairo_pattern_init_for_surface (&pattern.surface, clip->surface); + + status = _cairo_surface_composite (CAIRO_OPERATOR_IN, + &pattern.base, + NULL, + surface, + surface_rect.x - clip->surface_rect.x, + surface_rect.y - 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 (clip->surface); + } + + clip->surface = surface; + clip->surface_rect = surface_rect; + clip->serial = _cairo_surface_allocate_clip_serial (target); + + return status; +} + +cairo_status_t +_cairo_clip_clip (cairo_clip_t *clip, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_surface_t *target) +{ + cairo_status_t status; + cairo_traps_t traps; + + status = _cairo_clip_intersect_path (clip, + path, fill_rule, tolerance, + antialias, target); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + _cairo_traps_init (&traps); + status = _cairo_path_fixed_fill_to_traps (path, + fill_rule, + tolerance, + &traps); + if (status) + goto bail; + + status = _cairo_clip_intersect_region (clip, &traps, target); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + goto bail; + + status = _cairo_clip_intersect_mask (clip, &traps, antialias, target); + + bail: + _cairo_traps_fini (&traps); + + return status; +} diff --git a/gfx/cairo/cairo/src/cairo-color.c b/gfx/cairo/cairo/src/cairo-color.c index beb4a3474b04..e202af249eee 100644 --- a/gfx/cairo/cairo/src/cairo-color.c +++ b/gfx/cairo/cairo/src/cairo-color.c @@ -89,29 +89,19 @@ _cairo_color_init_rgb (cairo_color_t *color, _cairo_color_init_rgba (color, red, green, blue, 1.0); } +/* We multiply colors by (0x10000 - epsilon), such that we get a uniform + * range even for 0xffff. In other words, (1.0 - epsilon) would convert + * to 0xffff, not 0xfffe. + */ +#define CAIRO_COLOR_ONE_MINUS_EPSILON (65536.0 - 1e-5) -/* XXX: The calculation of: - - channel * 0xffff - - isn't really what we want since: - - (1.0 - epsilon) * 0xffff = 0xfffe - - In other words, given an input range of [0.0, 1.0], we have an - infinitely small range tha maps to the output value 0xffff, - (while having large, uniformly sized input ranges for all - other output values). This is undesirable, particularly when - we want to do optimizations for "opaque" colors specfied as - floating-point. -*/ static void _cairo_color_compute_shorts (cairo_color_t *color) { - color->red_short = color->red * color->alpha * 0xffff; - color->green_short = color->green * color->alpha * 0xffff; - color->blue_short = color->blue * color->alpha * 0xffff; - color->alpha_short = color->alpha * 0xffff; + color->red_short = color->red * color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON; + color->green_short = color->green * color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON; + color->blue_short = color->blue * color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON; + color->alpha_short = color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON; } void diff --git a/gfx/cairo/cairo/src/cairo-debug.c b/gfx/cairo/cairo/src/cairo-debug.c new file mode 100644 index 000000000000..31eefc5ae5c8 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-debug.c @@ -0,0 +1,73 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" + +/** + * cairo_debug_reset_static_data: + * + * Resets all static data within cairo to its original state, + * (ie. identical to the state at the time of program invocation). For + * example, all caches within cairo will be flushed empty. + * + * This function is intended to be useful when using memory-checking + * tools such as valgrind. When valgrind's memcheck analyzes a + * cairo-using program without a call to cairo_debug_reset_static_data, + * it will report all data reachable via cairo's static objects as + * "still reachable". Calling cairo_debug_reset_static_data just prior + * to program termination will make it easier to get squeaky clean + * reports from valgrind. + * + * WARNING: It is only safe to call this function when there are no + * active cairo objects remaining, (ie. the appropriate destroy + * functions have been called as necessary). If there are active cairo + * objects, this call is likely to cause a crash, (eg. an assertion + * failure due to a hash table being destroyed when non-empty). + **/ +void +cairo_debug_reset_static_data (void) +{ +#if CAIRO_HAS_XLIB_SURFACE + _cairo_xlib_surface_reset_static_data (); + _cairo_xlib_screen_reset_static_data (); +#endif + + _cairo_font_reset_static_data (); + +#if CAIRO_HAS_FT_FONT + _cairo_ft_font_reset_static_data (); +#endif +} + diff --git a/gfx/cairo/cairo/src/cairo-debug.h b/gfx/cairo/cairo/src/cairo-debug.h new file mode 100644 index 000000000000..1dab2c74bf84 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-debug.h @@ -0,0 +1,48 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_DEBUG_H +#define CAIRO_DEBUG_H + +#include + +CAIRO_BEGIN_DECLS + +void +cairo_debug_reset_static_data (void); + +CAIRO_END_DECLS + +#endif /* CAIRO_H */ diff --git a/gfx/cairo/cairo/src/cairo-features.h.in b/gfx/cairo/cairo/src/cairo-features.h.in index a13250d974d4..aa64e8dc9ffc 100644 --- a/gfx/cairo/cairo/src/cairo-features.h.in +++ b/gfx/cairo/cairo/src/cairo-features.h.in @@ -37,28 +37,40 @@ #ifndef CAIRO_FEATURES_H #define CAIRO_FEATURES_H -#define @PS_SURFACE_FEATURE@ +#ifdef __cplusplus +# define CAIRO_BEGIN_DECLS extern "C" { +# define CAIRO_END_DECLS } +#else +# define CAIRO_BEGIN_DECLS +# define CAIRO_END_DECLS +#endif -#define @PDF_SURFACE_FEATURE@ +#define CAIRO_VERSION_MAJOR 0 +#define CAIRO_VERSION_MINOR 9 +#define CAIRO_VERSION_MICRO 1 -#define @PNG_SURFACE_FEATURE@ +#define CAIRO_VERSION_STRING "0.9.1" -#define @XLIB_SURFACE_FEATURE@ +@PS_SURFACE_FEATURE@ -#define @QUARTZ_SURFACE_FEATURE@ +@PDF_SURFACE_FEATURE@ -#define @XCB_SURFACE_FEATURE@ +@XLIB_SURFACE_FEATURE@ -#define @WIN32_SURFACE_FEATURE@ +@QUARTZ_SURFACE_FEATURE@ -#define @GLITZ_SURFACE_FEATURE@ +@XCB_SURFACE_FEATURE@ -#define @FT_FONT_FEATURE@ +@WIN32_SURFACE_FEATURE@ -#define @WIN32_FONT_FEATURE@ +@GLITZ_SURFACE_FEATURE@ -#define @ATSUI_FONT_FEATURE@ +@FT_FONT_FEATURE@ -#define @SANITY_CHECKING_FEATURE@ +@WIN32_FONT_FEATURE@ + +@ATSUI_FONT_FEATURE@ + +@PNG_FUNCTIONS_FEATURE@ #endif diff --git a/gfx/cairo/cairo/src/cairo-font-options.c b/gfx/cairo/cairo/src/cairo-font-options.c new file mode 100644 index 000000000000..d7f2529dc987 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-font-options.c @@ -0,0 +1,352 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Owen Taylor + */ + +#include "cairoint.h" + +static const cairo_font_options_t cairo_font_options_nil = { + CAIRO_ANTIALIAS_DEFAULT, + CAIRO_SUBPIXEL_ORDER_DEFAULT, + CAIRO_HINT_STYLE_DEFAULT, + CAIRO_HINT_METRICS_DEFAULT +}; + +/** + * _cairo_font_options_init_default: + * @options: a #cairo_font_options_t + * + * Initializes all fileds of the font options object to default values. + **/ +void +_cairo_font_options_init_default (cairo_font_options_t *options) +{ + if (options == (cairo_font_options_t *)&cairo_font_options_nil) + return; + + options->antialias = CAIRO_ANTIALIAS_DEFAULT; + options->subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; + options->hint_style = CAIRO_HINT_STYLE_DEFAULT; + options->hint_metrics = CAIRO_HINT_METRICS_DEFAULT; +} + +/** + * cairo_font_options_create: + * + * Allocates a new font options object with all options initialized + * to default values. + * + * Return value: a newly allocated #cairo_font_options_t. Free with + * cairo_font_options_destroy(). This function always returns a + * valid pointer; if memory cannot be allocated, then a special + * error object is returned where all operations on the object do nothing. + * You can check for this with cairo_font_options_status(). + **/ +cairo_font_options_t * +cairo_font_options_create (void) +{ + cairo_font_options_t *options = malloc (sizeof (cairo_font_options_t)); + + if (!options) + return (cairo_font_options_t *)&cairo_font_options_nil; + + _cairo_font_options_init_default (options); + + return options; +} + +/** + * cairo_font_options_copy: + * @original: a #cairo_font_options_t + * + * Allocates a new font options object copying the option values from + * @original. + * + * Return value: a newly allocated #cairo_font_options_t. Free with + * cairo_font_options_destroy(). This function always returns a + * valid pointer; if memory cannot be allocated, then a special + * error object is returned where all operations on the object do nothing. + * You can check for this with cairo_font_options_status(). + **/ +cairo_font_options_t * +cairo_font_options_copy (const cairo_font_options_t *original) +{ + cairo_font_options_t *options = malloc (sizeof (cairo_font_options_t)); + + if (!options) + return (cairo_font_options_t *)&cairo_font_options_nil; + + *options = *original; + + return options; +} + +/** + * cairo_font_options_destroy: + * @options: a #cairo_font_options_t + * + * Destroys a #cairo_font_options_t object created with with + * cairo_font_options_create() or cairo_font_options_copy(). + **/ +void +cairo_font_options_destroy (cairo_font_options_t *options) +{ + if (options == (cairo_font_options_t *)&cairo_font_options_nil) + return; + + free (options); +} + +/** + * cairo_font_options_status: + * @options: a #cairo_font_options_t + * + * Checks whether an error has previously occurred for this + * font options object + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY + **/ +cairo_status_t +cairo_font_options_status (cairo_font_options_t *options) +{ + if (options == (cairo_font_options_t *)&cairo_font_options_nil) + return CAIRO_STATUS_NO_MEMORY; + else + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_font_options_merge: + * @options: a #cairo_font_options_t + * @other: another #cairo_font_options_t + * + * Merges non-default options from @other into @options, replacing + * existing values. This operation can be thought of as somewhat + * similar to compositing @other onto @options with the operation + * of %CAIRO_OPERATION_OVER. + **/ +void +cairo_font_options_merge (cairo_font_options_t *options, + const cairo_font_options_t *other) +{ + if (options == (cairo_font_options_t *)&cairo_font_options_nil) + return; + + if (other->antialias != CAIRO_ANTIALIAS_DEFAULT) + options->antialias = other->antialias; + if (other->subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT) + options->subpixel_order = other->subpixel_order; + if (other->hint_style != CAIRO_HINT_STYLE_DEFAULT) + options->hint_style = other->hint_style; + if (other->hint_metrics != CAIRO_HINT_METRICS_DEFAULT) + options->hint_metrics = other->hint_metrics; +} + +/** + * cairo_font_options_equal: + * @options: a #cairo_font_options_t + * @other: another #cairo_font_options_t + * + * Compares two font options objects for equality. + * + * Return value: %TRUE if all fields of the two font options objects match + **/ +cairo_bool_t +cairo_font_options_equal (const cairo_font_options_t *options, + const cairo_font_options_t *other) +{ + return (options->antialias == other->antialias && + options->subpixel_order == other->subpixel_order && + options->hint_style == other->hint_style && + options->hint_metrics == other->hint_metrics); +} + +/** + * cairo_font_options_hash: + * @options: a #cairo_font_options_t + * + * Compute a hash for the font options object; this value will + * be useful when storing an object containing a cairo_font_options_t + * in a hash table. + * + * Return value: the hash value for the font options object. + * The return value can be cast to a 32-bit type if a + * 32-bit hash value is needed. + **/ +unsigned long +cairo_font_options_hash (const cairo_font_options_t *options) +{ + return ((options->antialias) | + (options->subpixel_order << 4) | + (options->hint_style << 8) | + (options->hint_metrics << 16)); +} + +/** + * cairo_font_options_set_antialias: + * @options: a #cairo_font_options_t + * @antialias: the new antialiasing mode + * + * Sets the antiliasing mode for the font options object. This + * specifies the type of antialiasing to do when rendering text. + **/ +void +cairo_font_options_set_antialias (cairo_font_options_t *options, + cairo_antialias_t antialias) +{ + if (options == (cairo_font_options_t *)&cairo_font_options_nil) + return; + + options->antialias = antialias; +} + +/** + * cairo_font_options_get_antialias: + * @options: a #cairo_font_options_t + * + * Gets the antialising mode for the font options object. + * + * Return value: the antialiasing mode + **/ +cairo_antialias_t +cairo_font_options_get_antialias (const cairo_font_options_t *options) +{ + return options->antialias; +} + +/** + * cairo_font_options_set_subpixel_order: + * @options: a #cairo_font_options_t + * @subpixel_order: the new subpixel order + * + * Sets the subpixel order for the font options object. The subpixel + * order specifies the order of color elements within each pixel on + * the display device when rendering with an antialiasing mode of + * %CAIRO_ANTIALIAS_SUBPIXEL. See the documentation for + * #cairo_subpixel_order_t for full details. + **/ +void +cairo_font_options_set_subpixel_order (cairo_font_options_t *options, + cairo_subpixel_order_t subpixel_order) +{ + if (options == (cairo_font_options_t *)&cairo_font_options_nil) + return; + + options->subpixel_order = subpixel_order; +} + +/** + * cairo_font_options_get_subpixel_order: + * @options: a #cairo_font_options_t + * + * Gets the subpixel order for the font options object. + * See the documentation for #cairo_subpixel_order_t for full details. + * + * Return value: the subpixel order for the font options object + **/ +cairo_subpixel_order_t +cairo_font_options_get_subpixel_order (const cairo_font_options_t *options) +{ + return options->subpixel_order; +} + +/** + * cairo_font_options_set_hint_style: + * @options: a #cairo_font_options_t + * @hint_style: the new hint style + * + * Sets the hint style for font outlines for the font options object. + * This controls whether to fit font outlines to the pixel grid, + * and if so, whether to optimize for fidelity or contrast. + * See the documentation for #cairo_hint_style_t for full details. + **/ +void +cairo_font_options_set_hint_style (cairo_font_options_t *options, + cairo_hint_style_t hint_style) +{ + if (options == (cairo_font_options_t *)&cairo_font_options_nil) + return; + + options->hint_style = hint_style; +} + +/** + * cairo_font_options_get_hint_style: + * @options: a #cairo_font_options_t + * + * Gets the hint style for font outlines for the font options object. + * See the documentation for #cairo_hint_style_t for full details. + * + * Return value: the hint style for the font options object + **/ +cairo_hint_style_t +cairo_font_options_get_hint_style (const cairo_font_options_t *options) +{ + return options->hint_style; +} + +/** + * cairo_font_options_set_hint_metrics: + * @options: a #cairo_font_options_t + * @hint_metrics: the new metrics hinting mode + * + * Sets the metrics hinting mode for the font options object. This + * controls whether metrics are quantized to integer values in + * device units. + * See the documentation for #cairo_hint_metrics_t for full details. + **/ +void +cairo_font_options_set_hint_metrics (cairo_font_options_t *options, + cairo_hint_metrics_t hint_metrics) +{ + if (options == (cairo_font_options_t *)&cairo_font_options_nil) + return; + + options->hint_metrics = hint_metrics; +} + +/** + * cairo_font_options_get_hint_metrics: + * @options: a #cairo_font_options_t + * + * Gets the metrics hinting mode for the font options object. + * See the documentation for #cairo_hint_metrics_t for full details. + * + * Return value: the metrics hinting mode for the font options object + **/ +cairo_hint_metrics_t +cairo_font_options_get_hint_metrics (const cairo_font_options_t *options) +{ + return options->hint_metrics; +} diff --git a/gfx/cairo/cairo/src/cairo-font-subset-private.h b/gfx/cairo/cairo/src/cairo-font-subset-private.h new file mode 100644 index 000000000000..5b43f52db0fc --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-font-subset-private.h @@ -0,0 +1,68 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Kristian Høgsberg + */ + +#include "cairoint.h" + +#ifndef CAIRO_FONT_SUBSET_PRIVATE_H +#define CAIRO_FONT_SUBSET_PRIVATE_H + +typedef struct cairo_font_subset_backend cairo_font_subset_backend_t; +typedef struct cairo_font_subset cairo_font_subset_t; +struct cairo_font_subset { + cairo_font_subset_backend_t *backend; + cairo_unscaled_font_t *unscaled_font; + unsigned int font_id; + char *base_font; + int num_glyphs; + int *widths; + long x_min, y_min, x_max, y_max; + long ascent, descent; +}; + + +cairo_private int +_cairo_font_subset_use_glyph (cairo_font_subset_t *font, int glyph); + +cairo_private cairo_status_t +_cairo_font_subset_generate (cairo_font_subset_t *font, + const char **data, unsigned long *length); + +cairo_private void +_cairo_font_subset_destroy (cairo_font_subset_t *font); + +cairo_private cairo_font_subset_t * +_cairo_font_subset_create (cairo_unscaled_font_t *unscaled_font); + +#endif /* CAIRO_FONT_SUBSET_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-font-subset.c b/gfx/cairo/cairo/src/cairo-font-subset.c new file mode 100644 index 000000000000..bd113f9862a9 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-font-subset.c @@ -0,0 +1,724 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Kristian Høgsberg + */ + +#include "cairoint.h" +#include "cairo-pdf.h" +/* XXX: Eventually, we need to handle other font backends */ +#include "cairo-font-subset-private.h" +#include "cairo-ft-private.h" + +#include +#include FT_FREETYPE_H +#include FT_OUTLINE_H +#include FT_TRUETYPE_TAGS_H +#include FT_TRUETYPE_TABLES_H + +typedef struct ft_subset_glyph ft_subset_glyph_t; +struct ft_subset_glyph { + int parent_index; + unsigned long location; +}; + +struct cairo_font_subset_backend { + int (*use_glyph) (void *abstract_font, + int glyph); + cairo_status_t (*generate) (void *abstract_font, + const char **data, + unsigned long *length); + void (*destroy) (void *abstract_font); +}; + +typedef struct cairo_pdf_ft_font cairo_pdf_ft_font_t; +struct cairo_pdf_ft_font { + cairo_font_subset_t base; + ft_subset_glyph_t *glyphs; + FT_Face face; + int checksum_index; + cairo_array_t output; + int *parent_to_subset; + cairo_status_t status; +}; + +static int +cairo_pdf_ft_font_use_glyph (void *abstract_font, int glyph); + + +#define ARRAY_LENGTH(a) ( (sizeof (a)) / (sizeof ((a)[0])) ) + +#define SFNT_VERSION 0x00010000 + +#ifdef WORDS_BIGENDIAN + +#define cpu_to_be16(v) (v) +#define be16_to_cpu(v) (v) +#define cpu_to_be32(v) (v) +#define be32_to_cpu(v) (v) + +#else + +static inline unsigned short +cpu_to_be16(unsigned short v) +{ + return (v << 8) | (v >> 8); +} + +static inline unsigned short +be16_to_cpu(unsigned short v) +{ + return cpu_to_be16 (v); +} + +static inline unsigned long +cpu_to_be32(unsigned long v) +{ + return (cpu_to_be16 (v) << 16) | cpu_to_be16 (v >> 16); +} + +static inline unsigned long +be32_to_cpu(unsigned long v) +{ + return cpu_to_be32 (v); +} + +#endif + +static cairo_font_subset_backend_t cairo_pdf_ft_font_backend; + +int +_cairo_font_subset_use_glyph (cairo_font_subset_t *font, int glyph) +{ + return font->backend->use_glyph (font, glyph); +} + +cairo_status_t +_cairo_font_subset_generate (cairo_font_subset_t *font, + const char **data, unsigned long *length) +{ + return font->backend->generate (font, data, length); +} + +void +_cairo_font_subset_destroy (cairo_font_subset_t *font) +{ + font->backend->destroy (font); +} + +cairo_font_subset_t * +_cairo_font_subset_create (cairo_unscaled_font_t *unscaled_font) +{ + cairo_ft_unscaled_font_t *ft_unscaled_font; + FT_Face face; + cairo_pdf_ft_font_t *font; + unsigned long size; + int i, j; + + /* XXX: Need to fix this to work with a general cairo_unscaled_font_t. */ + if (! _cairo_unscaled_font_is_ft (unscaled_font)) + return NULL; + + ft_unscaled_font = (cairo_ft_unscaled_font_t *) unscaled_font; + + face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font); + + /* We currently only support freetype truetype fonts. */ + size = 0; + if (!FT_IS_SFNT (face) || + FT_Load_Sfnt_Table (face, TTAG_glyf, 0, NULL, &size) != 0) + return NULL; + + font = malloc (sizeof (cairo_pdf_ft_font_t)); + if (font == NULL) + return NULL; + + font->base.unscaled_font = _cairo_unscaled_font_reference (unscaled_font); + font->base.backend = &cairo_pdf_ft_font_backend; + + _cairo_array_init (&font->output, sizeof (char)); + if (_cairo_array_grow_by (&font->output, 4096) != CAIRO_STATUS_SUCCESS) + goto fail1; + + font->glyphs = calloc (face->num_glyphs + 1, sizeof (ft_subset_glyph_t)); + if (font->glyphs == NULL) + goto fail2; + + font->parent_to_subset = calloc (face->num_glyphs, sizeof (int)); + if (font->parent_to_subset == NULL) + goto fail3; + + font->base.num_glyphs = 1; + font->base.x_min = face->bbox.xMin; + font->base.y_min = face->bbox.yMin; + font->base.x_max = face->bbox.xMax; + font->base.y_max = face->bbox.yMax; + font->base.ascent = face->ascender; + font->base.descent = face->descender; + font->base.base_font = strdup (face->family_name); + if (font->base.base_font == NULL) + goto fail4; + + for (i = 0, j = 0; font->base.base_font[j]; j++) { + if (font->base.base_font[j] == ' ') + continue; + font->base.base_font[i++] = font->base.base_font[j]; + } + font->base.base_font[i] = '\0'; + + font->base.widths = calloc (face->num_glyphs, sizeof (int)); + if (font->base.widths == NULL) + goto fail5; + + _cairo_ft_unscaled_font_unlock_face (ft_unscaled_font); + + font->status = CAIRO_STATUS_SUCCESS; + + return &font->base; + + fail5: + free (font->base.base_font); + fail4: + free (font->parent_to_subset); + fail3: + free (font->glyphs); + fail2: + _cairo_array_fini (&font->output); + fail1: + free (font); + return NULL; +} + +static void +cairo_pdf_ft_font_destroy (void *abstract_font) +{ + cairo_pdf_ft_font_t *font = abstract_font; + + _cairo_unscaled_font_destroy (font->base.unscaled_font); + free (font->base.base_font); + free (font->parent_to_subset); + free (font->glyphs); + _cairo_array_fini (&font->output); + free (font); +} + +static void * +cairo_pdf_ft_font_write (cairo_pdf_ft_font_t *font, + const void *data, size_t length) +{ + void *p; + + p = _cairo_array_append (&font->output, data, length); + if (p == NULL) + font->status = CAIRO_STATUS_NO_MEMORY; + + return p; +} + +static void +cairo_pdf_ft_font_write_be16 (cairo_pdf_ft_font_t *font, + unsigned short value) +{ + unsigned short be16_value; + + be16_value = cpu_to_be16 (value); + cairo_pdf_ft_font_write (font, &be16_value, sizeof be16_value); +} + +static void +cairo_pdf_ft_font_write_be32 (cairo_pdf_ft_font_t *font, unsigned long value) +{ + unsigned long be32_value; + + be32_value = cpu_to_be32 (value); + cairo_pdf_ft_font_write (font, &be32_value, sizeof be32_value); +} + +static unsigned long +cairo_pdf_ft_font_align_output (cairo_pdf_ft_font_t *font) +{ + int length, aligned; + static const char pad[4]; + + length = _cairo_array_num_elements (&font->output); + aligned = (length + 3) & ~3; + cairo_pdf_ft_font_write (font, pad, aligned - length); + + return aligned; +} + +static int +cairo_pdf_ft_font_write_cmap_table (cairo_pdf_ft_font_t *font, unsigned long tag) +{ + int i; + + cairo_pdf_ft_font_write_be16 (font, 0); + cairo_pdf_ft_font_write_be16 (font, 1); + + cairo_pdf_ft_font_write_be16 (font, 1); + cairo_pdf_ft_font_write_be16 (font, 0); + cairo_pdf_ft_font_write_be32 (font, 12); + + /* Output a format 6 encoding table. */ + + cairo_pdf_ft_font_write_be16 (font, 6); + cairo_pdf_ft_font_write_be16 (font, 10 + 2 * (font->base.num_glyphs - 1)); + cairo_pdf_ft_font_write_be16 (font, 0); + cairo_pdf_ft_font_write_be16 (font, 1); /* First glyph */ + cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs - 1); + for (i = 1; i < font->base.num_glyphs; i++) + cairo_pdf_ft_font_write_be16 (font, i); + + return font->status; +} + +static int +cairo_pdf_ft_font_write_generic_table (cairo_pdf_ft_font_t *font, + unsigned long tag) +{ + unsigned char *buffer; + unsigned long size; + + size = 0; + FT_Load_Sfnt_Table (font->face, tag, 0, NULL, &size); + buffer = cairo_pdf_ft_font_write (font, NULL, size); + FT_Load_Sfnt_Table (font->face, tag, 0, buffer, &size); + + return 0; +} + + +typedef struct composite_glyph composite_glyph_t; +struct composite_glyph { + unsigned short flags; + unsigned short index; + unsigned short args[7]; /* 1 to 7 arguments depending on value of flags */ +}; + +typedef struct glyph_data glyph_data_t; +struct glyph_data { + short num_contours; + char data[8]; + composite_glyph_t glyph; +}; + +/* composite_glyph_t flags */ +#define ARG_1_AND_2_ARE_WORDS 0x0001 +#define WE_HAVE_A_SCALE 0x0008 +#define MORE_COMPONENTS 0x0020 +#define WE_HAVE_AN_X_AND_Y_SCALE 0x0040 +#define WE_HAVE_A_TWO_BY_TWO 0x0080 + +static void +cairo_pdf_ft_font_remap_composite_glyph (cairo_pdf_ft_font_t *font, + unsigned char *buffer) +{ + glyph_data_t *glyph_data; + composite_glyph_t *composite_glyph; + int num_args; + int has_more_components; + unsigned short flags; + unsigned short index; + + glyph_data = (glyph_data_t *) buffer; + if ((short)be16_to_cpu (glyph_data->num_contours) >= 0) + return; + + composite_glyph = &glyph_data->glyph; + do { + flags = be16_to_cpu (composite_glyph->flags); + has_more_components = flags & MORE_COMPONENTS; + index = cairo_pdf_ft_font_use_glyph (font, be16_to_cpu (composite_glyph->index)); + composite_glyph->index = cpu_to_be16 (index); + num_args = 1; + if (flags & ARG_1_AND_2_ARE_WORDS) + num_args += 1; + if (flags & WE_HAVE_A_SCALE) + num_args += 1; + else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) + num_args += 2; + else if (flags & WE_HAVE_A_TWO_BY_TWO) + num_args += 3; + composite_glyph = (composite_glyph_t *) &(composite_glyph->args[num_args]); + } while (has_more_components); +} + +static int +cairo_pdf_ft_font_write_glyf_table (cairo_pdf_ft_font_t *font, + unsigned long tag) +{ + unsigned long start_offset, index, size; + TT_Header *header; + unsigned long begin, end; + unsigned char *buffer; + int i; + union { + unsigned char *bytes; + unsigned short *short_offsets; + unsigned long *long_offsets; + } u; + + header = FT_Get_Sfnt_Table (font->face, ft_sfnt_head); + if (header->Index_To_Loc_Format == 0) + size = sizeof (short) * (font->face->num_glyphs + 1); + else + size = sizeof (long) * (font->face->num_glyphs + 1); + + u.bytes = malloc (size); + if (u.bytes == NULL) { + font->status = CAIRO_STATUS_NO_MEMORY; + return font->status; + } + FT_Load_Sfnt_Table (font->face, TTAG_loca, 0, u.bytes, &size); + + start_offset = _cairo_array_num_elements (&font->output); + for (i = 0; i < font->base.num_glyphs; i++) { + index = font->glyphs[i].parent_index; + if (header->Index_To_Loc_Format == 0) { + begin = be16_to_cpu (u.short_offsets[index]) * 2; + end = be16_to_cpu (u.short_offsets[index + 1]) * 2; + } + else { + begin = be32_to_cpu (u.long_offsets[index]); + end = be32_to_cpu (u.long_offsets[index + 1]); + } + + size = end - begin; + + font->glyphs[i].location = + cairo_pdf_ft_font_align_output (font) - start_offset; + buffer = cairo_pdf_ft_font_write (font, NULL, size); + if (buffer == NULL) + break; + if (size != 0) { + FT_Load_Sfnt_Table (font->face, TTAG_glyf, begin, buffer, &size); + cairo_pdf_ft_font_remap_composite_glyph (font, buffer); + } + } + + font->glyphs[i].location = + cairo_pdf_ft_font_align_output (font) - start_offset; + + free (u.bytes); + + return font->status; +} + +static int +cairo_pdf_ft_font_write_head_table (cairo_pdf_ft_font_t *font, + unsigned long tag) +{ + TT_Header *head; + + head = FT_Get_Sfnt_Table (font->face, ft_sfnt_head); + + cairo_pdf_ft_font_write_be32 (font, head->Table_Version); + cairo_pdf_ft_font_write_be32 (font, head->Font_Revision); + + font->checksum_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); + + cairo_pdf_ft_font_write_be16 (font, head->Flags); + cairo_pdf_ft_font_write_be16 (font, head->Units_Per_EM); + + cairo_pdf_ft_font_write_be32 (font, head->Created[0]); + cairo_pdf_ft_font_write_be32 (font, head->Created[1]); + cairo_pdf_ft_font_write_be32 (font, head->Modified[0]); + cairo_pdf_ft_font_write_be32 (font, head->Modified[1]); + + cairo_pdf_ft_font_write_be16 (font, head->xMin); + cairo_pdf_ft_font_write_be16 (font, head->yMin); + cairo_pdf_ft_font_write_be16 (font, head->xMax); + cairo_pdf_ft_font_write_be16 (font, head->yMax); + + cairo_pdf_ft_font_write_be16 (font, head->Mac_Style); + cairo_pdf_ft_font_write_be16 (font, head->Lowest_Rec_PPEM); + + cairo_pdf_ft_font_write_be16 (font, head->Font_Direction); + cairo_pdf_ft_font_write_be16 (font, head->Index_To_Loc_Format); + cairo_pdf_ft_font_write_be16 (font, head->Glyph_Data_Format); + + return font->status; +} + +static int cairo_pdf_ft_font_write_hhea_table (cairo_pdf_ft_font_t *font, unsigned long tag) +{ + TT_HoriHeader *hhea; + + hhea = FT_Get_Sfnt_Table (font->face, ft_sfnt_hhea); + + cairo_pdf_ft_font_write_be32 (font, hhea->Version); + cairo_pdf_ft_font_write_be16 (font, hhea->Ascender); + cairo_pdf_ft_font_write_be16 (font, hhea->Descender); + cairo_pdf_ft_font_write_be16 (font, hhea->Line_Gap); + + cairo_pdf_ft_font_write_be16 (font, hhea->advance_Width_Max); + + cairo_pdf_ft_font_write_be16 (font, hhea->min_Left_Side_Bearing); + cairo_pdf_ft_font_write_be16 (font, hhea->min_Right_Side_Bearing); + cairo_pdf_ft_font_write_be16 (font, hhea->xMax_Extent); + cairo_pdf_ft_font_write_be16 (font, hhea->caret_Slope_Rise); + cairo_pdf_ft_font_write_be16 (font, hhea->caret_Slope_Run); + cairo_pdf_ft_font_write_be16 (font, hhea->caret_Offset); + + cairo_pdf_ft_font_write_be16 (font, 0); + cairo_pdf_ft_font_write_be16 (font, 0); + cairo_pdf_ft_font_write_be16 (font, 0); + cairo_pdf_ft_font_write_be16 (font, 0); + + cairo_pdf_ft_font_write_be16 (font, hhea->metric_Data_Format); + cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs); + + return font->status; +} + +static int +cairo_pdf_ft_font_write_hmtx_table (cairo_pdf_ft_font_t *font, + unsigned long tag) +{ + unsigned long entry_size; + short *p; + int i; + + for (i = 0; i < font->base.num_glyphs; i++) { + entry_size = 2 * sizeof (short); + p = cairo_pdf_ft_font_write (font, NULL, entry_size); + FT_Load_Sfnt_Table (font->face, TTAG_hmtx, + font->glyphs[i].parent_index * entry_size, + (FT_Byte *) p, &entry_size); + font->base.widths[i] = be16_to_cpu (p[0]); + } + + return font->status; +} + +static int +cairo_pdf_ft_font_write_loca_table (cairo_pdf_ft_font_t *font, + unsigned long tag) +{ + int i; + TT_Header *header; + + header = FT_Get_Sfnt_Table (font->face, ft_sfnt_head); + + if (header->Index_To_Loc_Format == 0) { + for (i = 0; i < font->base.num_glyphs + 1; i++) + cairo_pdf_ft_font_write_be16 (font, font->glyphs[i].location / 2); + } + else { + for (i = 0; i < font->base.num_glyphs + 1; i++) + cairo_pdf_ft_font_write_be32 (font, font->glyphs[i].location); + } + + return font->status; +} + +static int +cairo_pdf_ft_font_write_maxp_table (cairo_pdf_ft_font_t *font, + unsigned long tag) +{ + TT_MaxProfile *maxp; + + maxp = FT_Get_Sfnt_Table (font->face, ft_sfnt_maxp); + + cairo_pdf_ft_font_write_be32 (font, maxp->version); + cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs); + cairo_pdf_ft_font_write_be16 (font, maxp->maxPoints); + cairo_pdf_ft_font_write_be16 (font, maxp->maxContours); + cairo_pdf_ft_font_write_be16 (font, maxp->maxCompositePoints); + cairo_pdf_ft_font_write_be16 (font, maxp->maxCompositeContours); + cairo_pdf_ft_font_write_be16 (font, maxp->maxZones); + cairo_pdf_ft_font_write_be16 (font, maxp->maxTwilightPoints); + cairo_pdf_ft_font_write_be16 (font, maxp->maxStorage); + cairo_pdf_ft_font_write_be16 (font, maxp->maxFunctionDefs); + cairo_pdf_ft_font_write_be16 (font, maxp->maxInstructionDefs); + cairo_pdf_ft_font_write_be16 (font, maxp->maxStackElements); + cairo_pdf_ft_font_write_be16 (font, maxp->maxSizeOfInstructions); + cairo_pdf_ft_font_write_be16 (font, maxp->maxComponentElements); + cairo_pdf_ft_font_write_be16 (font, maxp->maxComponentDepth); + + return font->status; +} + +typedef struct table table_t; +struct table { + unsigned long tag; + int (*write) (cairo_pdf_ft_font_t *font, unsigned long tag); +}; + +static const table_t truetype_tables[] = { + /* As we write out the glyf table we remap composite glyphs. + * Remapping composite glyphs will reference the sub glyphs the + * composite glyph is made up of. That needs to be done first so + * we have all the glyphs in the subset before going further. */ + { TTAG_glyf, cairo_pdf_ft_font_write_glyf_table }, + { TTAG_cmap, cairo_pdf_ft_font_write_cmap_table }, + { TTAG_cvt, cairo_pdf_ft_font_write_generic_table }, + { TTAG_fpgm, cairo_pdf_ft_font_write_generic_table }, + { TTAG_head, cairo_pdf_ft_font_write_head_table }, + { TTAG_hhea, cairo_pdf_ft_font_write_hhea_table }, + { TTAG_hmtx, cairo_pdf_ft_font_write_hmtx_table }, + { TTAG_loca, cairo_pdf_ft_font_write_loca_table }, + { TTAG_maxp, cairo_pdf_ft_font_write_maxp_table }, + { TTAG_name, cairo_pdf_ft_font_write_generic_table }, + { TTAG_prep, cairo_pdf_ft_font_write_generic_table }, +}; + +static cairo_status_t +cairo_pdf_ft_font_write_offset_table (cairo_pdf_ft_font_t *font) +{ + unsigned short search_range, entry_selector, range_shift; + int num_tables; + + num_tables = ARRAY_LENGTH (truetype_tables); + search_range = 1; + entry_selector = 0; + while (search_range * 2 <= num_tables) { + search_range *= 2; + entry_selector++; + } + search_range *= 16; + range_shift = num_tables * 16 - search_range; + + cairo_pdf_ft_font_write_be32 (font, SFNT_VERSION); + cairo_pdf_ft_font_write_be16 (font, num_tables); + cairo_pdf_ft_font_write_be16 (font, search_range); + cairo_pdf_ft_font_write_be16 (font, entry_selector); + cairo_pdf_ft_font_write_be16 (font, range_shift); + + cairo_pdf_ft_font_write (font, NULL, ARRAY_LENGTH (truetype_tables) * 16); + + return font->status; +} + +static unsigned long +cairo_pdf_ft_font_calculate_checksum (cairo_pdf_ft_font_t *font, + unsigned long start, unsigned long end) +{ + unsigned long *padded_end; + unsigned long *p; + unsigned long checksum; + char *data; + + checksum = 0; + data = _cairo_array_index (&font->output, 0); + p = (unsigned long *) (data + start); + padded_end = (unsigned long *) (data + ((end + 3) & ~3)); + while (p < padded_end) + checksum += *p++; + + return checksum; +} + +static void +cairo_pdf_ft_font_update_entry (cairo_pdf_ft_font_t *font, int index, unsigned long tag, + unsigned long start, unsigned long end) +{ + unsigned long *entry; + + entry = _cairo_array_index (&font->output, 12 + 16 * index); + entry[0] = cpu_to_be32 (tag); + entry[1] = cpu_to_be32 (cairo_pdf_ft_font_calculate_checksum (font, start, end)); + entry[2] = cpu_to_be32 (start); + entry[3] = cpu_to_be32 (end - start); +} + +static cairo_status_t +cairo_pdf_ft_font_generate (void *abstract_font, + const char **data, unsigned long *length) +{ + cairo_ft_unscaled_font_t *ft_unscaled_font; + cairo_pdf_ft_font_t *font = abstract_font; + unsigned long start, end, next, checksum, *checksum_location; + int i; + + /* XXX: It would be cleaner to do something besides this cast + * here. Perhaps cairo_pdf_ft_font_t should just have the + * cairo_ft_unscaled_font_t rather than having the generic + * cairo_unscaled_font_t in the base class? */ + ft_unscaled_font = (cairo_ft_unscaled_font_t *) font->base.unscaled_font; + + font->face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font); + + if (cairo_pdf_ft_font_write_offset_table (font)) + goto fail; + + start = cairo_pdf_ft_font_align_output (font); + end = start; + + end = 0; + for (i = 0; i < ARRAY_LENGTH (truetype_tables); i++) { + if (truetype_tables[i].write (font, truetype_tables[i].tag)) + goto fail; + + end = _cairo_array_num_elements (&font->output); + next = cairo_pdf_ft_font_align_output (font); + cairo_pdf_ft_font_update_entry (font, i, truetype_tables[i].tag, + start, end); + start = next; + } + + checksum = + 0xb1b0afba - cairo_pdf_ft_font_calculate_checksum (font, 0, end); + 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); + + fail: + _cairo_ft_unscaled_font_unlock_face (ft_unscaled_font); + font->face = NULL; + + return font->status; +} + +static int +cairo_pdf_ft_font_use_glyph (void *abstract_font, int glyph) +{ + cairo_pdf_ft_font_t *font = abstract_font; + + if (font->parent_to_subset[glyph] == 0) { + font->parent_to_subset[glyph] = font->base.num_glyphs; + font->glyphs[font->base.num_glyphs].parent_index = glyph; + font->base.num_glyphs++; + } + + return font->parent_to_subset[glyph]; +} + +static cairo_font_subset_backend_t cairo_pdf_ft_font_backend = { + cairo_pdf_ft_font_use_glyph, + cairo_pdf_ft_font_generate, + cairo_pdf_ft_font_destroy +}; diff --git a/gfx/cairo/cairo/src/cairo-font.c b/gfx/cairo/cairo/src/cairo-font.c index 3bd1e0318378..913eb95dec4f 100644 --- a/gfx/cairo/cairo/src/cairo-font.c +++ b/gfx/cairo/cairo/src/cairo-font.c @@ -39,13 +39,27 @@ #include "cairoint.h" +/* Forward declare so we can use it as an arbitrary backend for + * _cairo_font_face_nil. + */ +static const cairo_font_face_backend_t _cairo_toy_font_face_backend; + /* cairo_font_face_t */ +const cairo_font_face_t _cairo_font_face_nil = { + { 0 }, /* hash_entry */ + CAIRO_STATUS_NO_MEMORY, /* status */ + -1, /* ref_count */ + { 0, 0, 0, NULL }, /* user_data */ + &_cairo_toy_font_face_backend +}; + void _cairo_font_face_init (cairo_font_face_t *font_face, const cairo_font_face_backend_t *backend) { - font_face->refcount = 1; + font_face->status = CAIRO_STATUS_SUCCESS; + font_face->ref_count = 1; font_face->backend = backend; _cairo_user_data_array_init (&font_face->user_data); @@ -53,16 +67,27 @@ _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. + * + * Return value: the referenced #cairo_font_face_t. **/ -void +cairo_font_face_t * cairo_font_face_reference (cairo_font_face_t *font_face) { - font_face->refcount++; + if (font_face == NULL) + return NULL; + + if (font_face->ref_count == (unsigned int)-1) + return font_face; + + font_face->ref_count++; + + return font_face; } /** @@ -76,7 +101,13 @@ cairo_font_face_reference (cairo_font_face_t *font_face) void cairo_font_face_destroy (cairo_font_face_t *font_face) { - if (--(font_face->refcount) > 0) + if (font_face == NULL) + return; + + if (font_face->ref_count == (unsigned int)-1) + return; + + if (--(font_face->ref_count) > 0) return; font_face->backend->destroy (font_face); @@ -85,14 +116,30 @@ cairo_font_face_destroy (cairo_font_face_t *font_face) * FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t * need to effectively mutually reference each other */ - if (font_face->refcount > 0) + if (font_face->ref_count > 0) return; - _cairo_user_data_array_destroy (&font_face->user_data); + _cairo_user_data_array_fini (&font_face->user_data); free (font_face); } +/** + * cairo_font_face_status: + * @font_face: a #cairo_font_face_t + * + * Checks whether an error has previously occurred for this + * font face + * + * Return value: %CAIRO_STATUS_SUCCESS or another error such as + * %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_status_t +cairo_font_face_status (cairo_font_face_t *font_face) +{ + return font_face->status; +} + /** * cairo_font_face_get_user_data: * @font_face: a #cairo_font_face_t @@ -135,233 +182,131 @@ cairo_font_face_set_user_data (cairo_font_face_t *font_face, void *user_data, cairo_destroy_func_t destroy) { + if (font_face->ref_count == -1) + return CAIRO_STATUS_NO_MEMORY; + return _cairo_user_data_array_set_data (&font_face->user_data, key, user_data, destroy); } -/* cairo_simple_font_face_t - simple family/slant/weight font faces used for - * the built-in font API - */ - -typedef struct _cairo_simple_font_face cairo_simple_font_face_t; - -struct _cairo_simple_font_face { - cairo_font_face_t base; - char *family; - cairo_font_slant_t slant; - cairo_font_weight_t weight; -}; - -static const cairo_font_face_backend_t _cairo_simple_font_face_backend; - -/* We maintain a global cache from family/weight/slant => cairo_font_face_t - * for cairo_simple_font_t. The primary purpose of this cache is to provide - * unique cairo_font_face_t values so that our cache from - * cairo_font_face_t => cairo_scaled_font_t works. For this reason, we don't need - * this cache to keep font faces alive; we just add them to the cache and - * remove them again when freed. - */ - -typedef struct { - cairo_cache_entry_base_t base; - const char *family; - cairo_font_slant_t slant; - cairo_font_weight_t weight; -} cairo_simple_cache_key_t; - -typedef struct { - cairo_simple_cache_key_t key; - cairo_simple_font_face_t *font_face; -} cairo_simple_cache_entry_t; - -static const cairo_cache_backend_t _cairo_simple_font_cache_backend; - -static void -_lock_global_simple_cache (void) -{ - /* FIXME: Perform locking here. */ -} - -static void -_unlock_global_simple_cache (void) -{ - /* FIXME: Perform locking here. */ -} - -static cairo_cache_t * -_get_global_simple_cache (void) -{ - static cairo_cache_t *global_simple_cache = NULL; - - if (global_simple_cache == NULL) - { - global_simple_cache = malloc (sizeof (cairo_cache_t)); - if (!global_simple_cache) - goto FAIL; - - if (_cairo_cache_init (global_simple_cache, - &_cairo_simple_font_cache_backend, - 0)) /* No memory limit */ - goto FAIL; - } - return global_simple_cache; - - FAIL: - if (global_simple_cache) - free (global_simple_cache); - global_simple_cache = NULL; - return NULL; -} - -static unsigned long -_cairo_simple_font_cache_hash (void *cache, void *key) -{ - cairo_simple_cache_key_t *k = (cairo_simple_cache_key_t *) key; - unsigned long hash; - - /* 1607 and 1451 are just a couple random primes. */ - hash = _cairo_hash_string (k->family); - hash += ((unsigned long) k->slant) * 1607; - hash += ((unsigned long) k->weight) * 1451; - - return hash; -} +static const cairo_font_face_backend_t _cairo_toy_font_face_backend; static int -_cairo_simple_font_cache_keys_equal (void *cache, - void *k1, - void *k2) +_cairo_toy_font_face_keys_equal (void *key_a, + void *key_b); + +/* We maintain a hash table from family/weight/slant => + * cairo_font_face_t for cairo_toy_font_t. The primary purpose of + * this mapping is to provide unique cairo_font_face_t values so that + * our cache and mapping from cairo_font_face_t => cairo_scaled_font_t + * works. Once the corresponding cairo_font_face_t objects fall out of + * downstream caches, we don't need them in this hash table anymore. + */ + +static cairo_hash_table_t *cairo_toy_font_face_hash_table = NULL; + +CAIRO_MUTEX_DECLARE (cairo_toy_font_face_hash_table_mutex); + +static cairo_hash_table_t * +_cairo_toy_font_face_hash_table_lock (void) { - cairo_simple_cache_key_t *a; - cairo_simple_cache_key_t *b; - a = (cairo_simple_cache_key_t *) k1; - b = (cairo_simple_cache_key_t *) k2; + CAIRO_MUTEX_LOCK (cairo_toy_font_face_hash_table_mutex); - return strcmp (a->family, b->family) == 0 && - a->slant == b->slant && - a->weight == b->weight; -} + if (cairo_toy_font_face_hash_table == NULL) + { + cairo_toy_font_face_hash_table = + _cairo_hash_table_create (_cairo_toy_font_face_keys_equal); -static cairo_simple_font_face_t * -_cairo_simple_font_face_create_from_cache_key (cairo_simple_cache_key_t *key) -{ - cairo_simple_font_face_t *simple_face; - - simple_face = malloc (sizeof (cairo_simple_font_face_t)); - if (!simple_face) - return NULL; - - simple_face->family = strdup (key->family); - if (!simple_face->family) { - free (simple_face); - return NULL; + if (cairo_toy_font_face_hash_table == NULL) { + CAIRO_MUTEX_UNLOCK (cairo_toy_font_face_hash_table_mutex); + return NULL; + } } - simple_face->slant = key->slant; - simple_face->weight = key->weight; + return cairo_toy_font_face_hash_table; +} - _cairo_font_face_init (&simple_face->base, &_cairo_simple_font_face_backend); +static void +_cairo_toy_font_face_hash_table_unlock (void) +{ + CAIRO_MUTEX_UNLOCK (cairo_toy_font_face_hash_table_mutex); +} - return simple_face; +/** + * _cairo_toy_font_face_init_key: + * + * Initialize those portions of cairo_toy_font_face_t needed to use + * it as a hash table key, including the hash code buried away in + * font_face->base.hash_entry. No memory allocation is performed here + * so that no fini call is needed. We do this to make it easier to use + * an automatic cairo_toy_font_face_t variable as a key. + **/ +static void +_cairo_toy_font_face_init_key (cairo_toy_font_face_t *key, + const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight) +{ + unsigned long hash; + + key->family = family; + key->owns_family = FALSE; + + key->slant = slant; + key->weight = weight; + + /* 1607 and 1451 are just a couple of arbitrary primes. */ + hash = _cairo_hash_string (family); + hash += ((unsigned long) slant) * 1607; + hash += ((unsigned long) weight) * 1451; + + key->base.hash_entry.hash = hash; } static cairo_status_t -_cairo_simple_font_cache_create_entry (void *cache, - void *key, - void **return_entry) +_cairo_toy_font_face_init (cairo_toy_font_face_t *font_face, + const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight) { - cairo_simple_cache_key_t *k = (cairo_simple_cache_key_t *) key; - cairo_simple_cache_entry_t *entry; + char *family_copy; - entry = malloc (sizeof (cairo_simple_cache_entry_t)); - if (entry == NULL) + family_copy = strdup (family); + if (family_copy == NULL) return CAIRO_STATUS_NO_MEMORY; - entry->font_face = _cairo_simple_font_face_create_from_cache_key (k); - if (!entry->font_face) { - free (entry); - return CAIRO_STATUS_NO_MEMORY; - } - - entry->key.base.memory = 0; - entry->key.family = entry->font_face->family; - entry->key.slant = entry->font_face->slant; - entry->key.weight = entry->font_face->weight; - - *return_entry = entry; + _cairo_toy_font_face_init_key (font_face, family_copy, + slant, weight); + font_face->owns_family = TRUE; + + _cairo_font_face_init (&font_face->base, &_cairo_toy_font_face_backend); return CAIRO_STATUS_SUCCESS; } -/* Entries are never spontaneously destroyed; but only when - * we remove them from the cache specifically. We free entry->font_face - * in the code that removes the entry from the cache - */ static void -_cairo_simple_font_cache_destroy_entry (void *cache, - void *entry) -{ - cairo_simple_cache_entry_t *e = (cairo_simple_cache_entry_t *) entry; - - free (e); -} - -static void -_cairo_simple_font_cache_destroy_cache (void *cache) +_cairo_toy_font_face_fini (cairo_toy_font_face_t *font_face) { - free (cache); + /* We assert here that we own font_face->family before casting + * away the const qualifer. */ + assert (font_face->owns_family); + free ((char*) font_face->family); } -static const cairo_cache_backend_t _cairo_simple_font_cache_backend = { - _cairo_simple_font_cache_hash, - _cairo_simple_font_cache_keys_equal, - _cairo_simple_font_cache_create_entry, - _cairo_simple_font_cache_destroy_entry, - _cairo_simple_font_cache_destroy_cache -}; - -static void -_cairo_simple_font_face_destroy (void *abstract_face) +static int +_cairo_toy_font_face_keys_equal (void *key_a, + void *key_b) { - cairo_simple_font_face_t *simple_face = abstract_face; - cairo_cache_t *cache; - cairo_simple_cache_key_t key; + cairo_toy_font_face_t *face_a = key_a; + cairo_toy_font_face_t *face_b = key_b; - _lock_global_simple_cache (); - cache = _get_global_simple_cache (); - assert (cache); - - key.family = simple_face->family; - key.slant = simple_face->slant; - key.weight = simple_face->weight; - - _cairo_cache_remove (cache, &key); - - _unlock_global_simple_cache (); - - free (simple_face->family); + return (strcmp (face_a->family, face_b->family) == 0 && + face_a->slant == face_b->slant && + face_a->weight == face_b->weight); } -static cairo_status_t -_cairo_simple_font_face_create_font (void *abstract_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - cairo_scaled_font_t **scaled_font) -{ - const cairo_scaled_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT; - cairo_simple_font_face_t *simple_face = abstract_face; - - return backend->create (simple_face->family, simple_face->slant, simple_face->weight, - font_matrix, ctm, scaled_font); -} - -static const cairo_font_face_backend_t _cairo_simple_font_face_backend = { - _cairo_simple_font_face_destroy, - _cairo_simple_font_face_create_font, -}; - /** - * _cairo_simple_font_face_create: + * _cairo_toy_font_face_create: * @family: a font family name, encoded in UTF-8 * @slant: the slant for the font * @weight: the weight for the font @@ -373,137 +318,254 @@ static const cairo_font_face_backend_t _cairo_simple_font_face_backend = { * Return value: a newly created #cairo_font_face_t, destroy with * cairo_font_face_destroy() **/ -cairo_private cairo_font_face_t * -_cairo_simple_font_face_create (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight) +cairo_font_face_t * +_cairo_toy_font_face_create (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight) { - cairo_simple_cache_entry_t *entry; - cairo_simple_cache_key_t key; - cairo_cache_t *cache; cairo_status_t status; - cairo_bool_t created_entry; + cairo_toy_font_face_t key, *font_face; + cairo_hash_table_t *hash_table; - key.family = family; - key.slant = slant; - key.weight = weight; + hash_table = _cairo_toy_font_face_hash_table_lock (); + if (hash_table == NULL) + goto UNWIND; + + _cairo_toy_font_face_init_key (&key, family, slant, weight); - _lock_global_simple_cache (); - cache = _get_global_simple_cache (); - if (cache == NULL) { - _unlock_global_simple_cache (); - return NULL; + /* Return existing font_face if it exists in the hash table. */ + if (_cairo_hash_table_lookup (hash_table, + &key.base.hash_entry, + (cairo_hash_entry_t **) &font_face)) + { + _cairo_toy_font_face_hash_table_unlock (); + return cairo_font_face_reference (&font_face->base); } - status = _cairo_cache_lookup (cache, &key, (void **) &entry, &created_entry); - if (CAIRO_OK (status) && !created_entry) - cairo_font_face_reference (&entry->font_face->base); - - _unlock_global_simple_cache (); - if (status) - return NULL; - return &entry->font_face->base; + /* Otherwise create it and insert into hash table. */ + font_face = malloc (sizeof (cairo_toy_font_face_t)); + if (font_face == NULL) + goto UNWIND_HASH_TABLE_LOCK; + + status = _cairo_toy_font_face_init (font_face, family, slant, weight); + if (status) + goto UNWIND_FONT_FACE_MALLOC; + + status = _cairo_hash_table_insert (hash_table, &font_face->base.hash_entry); + if (status) + goto UNWIND_FONT_FACE_INIT; + + _cairo_toy_font_face_hash_table_unlock (); + + return &font_face->base; + + UNWIND_FONT_FACE_INIT: + UNWIND_FONT_FACE_MALLOC: + free (font_face); + UNWIND_HASH_TABLE_LOCK: + _cairo_toy_font_face_hash_table_unlock (); + UNWIND: + return (cairo_font_face_t*) &_cairo_font_face_nil; } +static void +_cairo_toy_font_face_destroy (void *abstract_face) +{ + cairo_toy_font_face_t *font_face = abstract_face; + cairo_hash_table_t *hash_table; + + if (font_face == NULL) + return; + + hash_table = _cairo_toy_font_face_hash_table_lock (); + /* All created objects must have been mapped in the hash table. */ + assert (hash_table != NULL); + + _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry); + + _cairo_toy_font_face_hash_table_unlock (); + + _cairo_toy_font_face_fini (font_face); +} + +static cairo_status_t +_cairo_toy_font_face_scaled_font_create (void *abstract_font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font) +{ + cairo_toy_font_face_t *font_face = abstract_font_face; + const cairo_scaled_font_backend_t * backend = CAIRO_SCALED_FONT_BACKEND_DEFAULT; + + return backend->create_toy (font_face, + font_matrix, ctm, options, scaled_font); +} + +static const cairo_font_face_backend_t _cairo_toy_font_face_backend = { + _cairo_toy_font_face_destroy, + _cairo_toy_font_face_scaled_font_create +}; + /* cairo_scaled_font_t */ -/* Here we keep a cache from cairo_font_face_t/matrix/ctm => cairo_scaled_font_t. +static const cairo_scaled_font_t _cairo_scaled_font_nil = { + { 0 }, /* hash_entry */ + CAIRO_STATUS_NO_MEMORY, /* status */ + -1, /* ref_count */ + NULL, /* font_face */ + { 1., 0., 0., 1., 0, 0}, /* font_matrix */ + { 1., 0., 0., 1., 0, 0}, /* ctm */ + { 1., 0., 0., 1., 0, 0}, /* scale */ + { CAIRO_ANTIALIAS_DEFAULT, /* options */ + CAIRO_SUBPIXEL_ORDER_DEFAULT, + CAIRO_HINT_STYLE_DEFAULT, + CAIRO_HINT_METRICS_DEFAULT} , + CAIRO_SCALED_FONT_BACKEND_DEFAULT, +}; + +/** + * _cairo_scaled_font_set_error: + * @scaled_font: a scaled_font + * @status: a status value indicating an error, (eg. not + * CAIRO_STATUS_SUCCESS) + * + * Sets scaled_font->status to @status and calls _cairo_error; * - * The implementation is messy because we want + * All assignments of an error status to scaled_font->status should happen + * through _cairo_scaled_font_set_error() or else _cairo_error() should be + * called immediately after the assignment. * - * - All otherwise referenced cairo_scaled_font_t's to be in the cache - * - Some number of not otherwise referenced cairo_scaled_font_t's + * 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. + **/ +void +_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font, + cairo_status_t status) +{ + scaled_font->status = status; + + _cairo_error (status); +} + +/** + * cairo_scaled_font_status: + * @scaled_font: a #cairo_scaled_font_t + * + * Checks whether an error has previously occurred for this + * scaled_font. + * + * Return value: %CAIRO_STATUS_SUCCESS or another error such as + * %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_status_t +cairo_scaled_font_status (cairo_scaled_font_t *scaled_font) +{ + return scaled_font->status; +} + +/* Here we keep a unique mapping from + * cairo_font_face_t/matrix/ctm/options => cairo_scaled_font_t. * - * For this reason, we actually use *two* caches ... a finite size - * cache that references the cairo_scaled_font_t as a first level (the outer - * cache), then an infinite size cache as the second level (the inner - * cache). A single cache could be used at the cost of complicating - * cairo-cache.c + * Here are the things that we want to map: + * + * a) All otherwise referenced cairo_scaled_font_t's + * b) Some number of not otherwise referenced cairo_scaled_font_t's + * + * The implementation uses a hash table which covers (a) + * completely. Then, for (b) we have an array of otherwise + * unreferenced fonts (holdovers) which are expired in + * least-recently-used order. + * + * The cairo_scaled_font_create code gets to treat this like a regular + * hash table. All of the magic for the little holdover cache is in + * cairo_scaled_font_reference and cairo_scaled_font_destroy. */ -/* This defines the size of the outer cache ... that is, the number +/* This defines the size of the holdover array ... that is, the number * of scaled fonts we keep around even when not otherwise referenced */ -#define MAX_CACHED_FONTS 24 +#define CAIRO_SCALED_FONT_MAX_HOLDOVERS 24 + +typedef struct _cairo_scaled_font_map { + cairo_hash_table_t *hash_table; + cairo_scaled_font_t *holdovers[CAIRO_SCALED_FONT_MAX_HOLDOVERS]; + int num_holdovers; +} cairo_scaled_font_map_t; -typedef struct { - cairo_cache_entry_base_t base; - cairo_font_face_t *font_face; - const cairo_matrix_t *font_matrix; - const cairo_matrix_t *ctm; -} cairo_font_cache_key_t; +static cairo_scaled_font_map_t *cairo_scaled_font_map = NULL; -typedef struct { - cairo_font_cache_key_t key; +CAIRO_MUTEX_DECLARE (cairo_scaled_font_map_mutex); + +static int +_cairo_scaled_font_keys_equal (void *abstract_key_a, void *abstract_key_b); + +static cairo_scaled_font_map_t * +_cairo_scaled_font_map_lock (void) +{ + CAIRO_MUTEX_LOCK (cairo_scaled_font_map_mutex); + + if (cairo_scaled_font_map == NULL) + { + cairo_scaled_font_map = malloc (sizeof (cairo_scaled_font_map_t)); + if (cairo_scaled_font_map == NULL) + goto CLEANUP_MUTEX_LOCK; + + cairo_scaled_font_map->hash_table = + _cairo_hash_table_create (_cairo_scaled_font_keys_equal); + + if (cairo_scaled_font_map->hash_table == NULL) + goto CLEANUP_SCALED_FONT_MAP; + + cairo_scaled_font_map->num_holdovers = 0; + } + + return cairo_scaled_font_map; + + CLEANUP_SCALED_FONT_MAP: + free (cairo_scaled_font_map); + CLEANUP_MUTEX_LOCK: + CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex); + return NULL; +} + +static void +_cairo_scaled_font_map_unlock (void) +{ + CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex); +} + +static void +_cairo_scaled_font_map_destroy (void) +{ + int i; + cairo_scaled_font_map_t *font_map = cairo_scaled_font_map; cairo_scaled_font_t *scaled_font; -} cairo_font_cache_entry_t; -static const cairo_cache_backend_t _cairo_outer_font_cache_backend; -static const cairo_cache_backend_t _cairo_inner_font_cache_backend; + if (font_map == NULL) + return; -static void -_lock_global_font_cache (void) -{ - /* FIXME: Perform locking here. */ -} + CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex); -static void -_unlock_global_font_cache (void) -{ - /* FIXME: Perform locking here. */ -} - -static cairo_cache_t * -_get_outer_font_cache (void) -{ - static cairo_cache_t *outer_font_cache = NULL; - - if (outer_font_cache == NULL) - { - outer_font_cache = malloc (sizeof (cairo_cache_t)); - if (!outer_font_cache) - goto FAIL; - - if (_cairo_cache_init (outer_font_cache, - &_cairo_outer_font_cache_backend, - MAX_CACHED_FONTS)) - goto FAIL; + for (i = 0; i < font_map->num_holdovers; i++) { + scaled_font = font_map->holdovers[i]; + /* We should only get here through the reset_static_data path + * and there had better not be any active references at that + * point. */ + assert (scaled_font->ref_count == 0); + _cairo_hash_table_remove (font_map->hash_table, + &scaled_font->hash_entry); + _cairo_scaled_font_fini (scaled_font); + free (scaled_font); } - return outer_font_cache; - FAIL: - if (outer_font_cache) - free (outer_font_cache); - outer_font_cache = NULL; - return NULL; + _cairo_hash_table_destroy (font_map->hash_table); + + free (cairo_scaled_font_map); + cairo_scaled_font_map = NULL; } -static cairo_cache_t * -_get_inner_font_cache (void) -{ - static cairo_cache_t *inner_font_cache = NULL; - - if (inner_font_cache == NULL) - { - inner_font_cache = malloc (sizeof (cairo_cache_t)); - if (!inner_font_cache) - goto FAIL; - - if (_cairo_cache_init (inner_font_cache, - &_cairo_inner_font_cache_backend, - MAX_CACHED_FONTS)) - goto FAIL; - } - return inner_font_cache; - - FAIL: - if (inner_font_cache) - free (inner_font_cache); - inner_font_cache = NULL; - return NULL; -} - - /* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/) * * Not necessarily better than a lot of other hashes, but should be OK, and @@ -525,168 +587,85 @@ _hash_bytes_fnv (unsigned char *buffer, return hval; } -static unsigned long -_cairo_font_cache_hash (void *cache, void *key) + +static void +_cairo_scaled_font_init_key (cairo_scaled_font_t *scaled_font, + cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options) { - cairo_font_cache_key_t *k = (cairo_font_cache_key_t *) key; uint32_t hash = FNV1_32_INIT; - /* We do a bytewise hash on the font matrices */ - hash = _hash_bytes_fnv ((unsigned char *)(&k->font_matrix->xx), + scaled_font->status = CAIRO_STATUS_SUCCESS; + scaled_font->font_face = font_face; + scaled_font->font_matrix = *font_matrix; + scaled_font->ctm = *ctm; + scaled_font->options = *options; + + /* We do a bytewise hash on the font matrices, ignoring the + * translation values. */ + hash = _hash_bytes_fnv ((unsigned char *)(&scaled_font->font_matrix.xx), sizeof(double) * 4, hash); - hash = _hash_bytes_fnv ((unsigned char *)(&k->ctm->xx), + hash = _hash_bytes_fnv ((unsigned char *)(&scaled_font->ctm.xx), sizeof(double) * 4, hash); - return hash ^ (unsigned long)k->font_face; + hash ^= (unsigned long) scaled_font->font_face; + + hash ^= cairo_font_options_hash (&scaled_font->options); + + scaled_font->hash_entry.hash = hash; } -static int -_cairo_font_cache_keys_equal (void *cache, - void *k1, - void *k2) +static cairo_bool_t +_cairo_scaled_font_keys_equal (void *abstract_key_a, void *abstract_key_b) { - cairo_font_cache_key_t *a; - cairo_font_cache_key_t *b; - a = (cairo_font_cache_key_t *) k1; - b = (cairo_font_cache_key_t *) k2; + cairo_scaled_font_t *key_a = abstract_key_a; + cairo_scaled_font_t *key_b = abstract_key_b; - return (a->font_face == b->font_face && - memcmp ((unsigned char *)(&a->font_matrix->xx), - (unsigned char *)(&b->font_matrix->xx), + return (key_a->font_face == key_b->font_face && + memcmp ((unsigned char *)(&key_a->font_matrix.xx), + (unsigned char *)(&key_b->font_matrix.xx), sizeof(double) * 4) == 0 && - memcmp ((unsigned char *)(&a->ctm->xx), - (unsigned char *)(&b->ctm->xx), - sizeof(double) * 4) == 0); + memcmp ((unsigned char *)(&key_a->ctm.xx), + (unsigned char *)(&key_b->ctm.xx), + sizeof(double) * 4) == 0 && + cairo_font_options_equal (&key_a->options, &key_b->options)); } -/* The cache lookup failed in the outer cache, so we pull - * the font from the inner cache (if that in turns fails, - * it will create the font - */ -static cairo_status_t -_cairo_outer_font_cache_create_entry (void *cache, - void *key, - void **return_entry) +void +_cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, + cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + const cairo_scaled_font_backend_t *backend) { - cairo_font_cache_entry_t *entry; - cairo_font_cache_entry_t *inner_entry; - cairo_bool_t created_entry; - cairo_status_t status; + scaled_font->ref_count = 1; - entry = malloc (sizeof (cairo_font_cache_entry_t)); - if (entry == NULL) - return CAIRO_STATUS_NO_MEMORY; + _cairo_scaled_font_init_key (scaled_font, font_face, + font_matrix, ctm, options); - cache = _get_inner_font_cache (); - if (cache == NULL) { - _unlock_global_font_cache (); - return CAIRO_STATUS_NO_MEMORY; - } - - status = _cairo_cache_lookup (cache, key, (void **) &inner_entry, &created_entry); - if (!CAIRO_OK (status)) { - free (entry); - return status; - } + cairo_font_face_reference (font_face); - entry->scaled_font = inner_entry->scaled_font; - if (!created_entry) - cairo_scaled_font_reference (entry->scaled_font); - - entry->key.base.memory = 1; - entry->key.font_face = entry->scaled_font->font_face; - entry->key.font_matrix = &entry->scaled_font->font_matrix; - entry->key.ctm = &entry->scaled_font->ctm; - - *return_entry = entry; + cairo_matrix_multiply (&scaled_font->scale, + &scaled_font->font_matrix, + &scaled_font->ctm); - return CAIRO_STATUS_SUCCESS; + scaled_font->backend = backend; } -static void -_cairo_outer_font_cache_destroy_entry (void *cache, - void *entry) -{ - cairo_font_cache_entry_t *e = (cairo_font_cache_entry_t *) entry; - - cairo_scaled_font_destroy (e->scaled_font); - - free (e); -} - -/* Called when the lookup fails in the inner cache as well; there - * is no existing font, so we have to create one. - */ -static cairo_status_t -_cairo_inner_font_cache_create_entry (void *cache, - void *key, - void **return_entry) +void +_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font) { - cairo_font_cache_key_t *k = (cairo_font_cache_key_t *) key; - cairo_font_cache_entry_t *entry; - cairo_status_t status; + if (scaled_font->font_face) + cairo_font_face_destroy (scaled_font->font_face); - entry = malloc (sizeof (cairo_font_cache_entry_t)); - if (entry == NULL) - return CAIRO_STATUS_NO_MEMORY; - - status = k->font_face->backend->create_font (k->font_face, - k->font_matrix, - k->ctm, - &entry->scaled_font); - if (!CAIRO_OK (status)) { - free (entry); - return status; - } - - entry->scaled_font->font_face = k->font_face; - cairo_font_face_reference (k->font_face); - - entry->key.base.memory = 0; - entry->key.font_face = k->font_face; - entry->key.font_matrix = &entry->scaled_font->font_matrix; - entry->key.ctm = &entry->scaled_font->ctm; - - *return_entry = entry; - - return CAIRO_STATUS_SUCCESS; + scaled_font->backend->fini (scaled_font); } -/* Entries in the inner font cache are never spontaneously destroyed; - * but only when we remove them from the cache specifically. We free - * entry->scaled_font in the code that removes the entry from the cache - */ -static void -_cairo_inner_font_cache_destroy_entry (void *cache, - void *entry) -{ - free (entry); -} - -static void -_cairo_font_cache_destroy_cache (void *cache) -{ - free (cache); -} - -static const cairo_cache_backend_t _cairo_outer_font_cache_backend = { - _cairo_font_cache_hash, - _cairo_font_cache_keys_equal, - _cairo_outer_font_cache_create_entry, - _cairo_outer_font_cache_destroy_entry, - _cairo_font_cache_destroy_cache -}; - -static const cairo_cache_backend_t _cairo_inner_font_cache_backend = { - _cairo_font_cache_hash, - _cairo_font_cache_keys_equal, - _cairo_inner_font_cache_create_entry, - _cairo_inner_font_cache_destroy_entry, - _cairo_font_cache_destroy_cache -}; - /** * cairo_scaled_font_create: * @font_face: a #cairo_font_face_t @@ -697,6 +676,8 @@ static const cairo_cache_backend_t _cairo_inner_font_cache_backend = { * cairo_set_font_matrix(). * @ctm: user to device transformation matrix with which the font will * be used. + * @options: options to use when getting metrics for the font and + * rendering with it. * * Creates a #cairo_scaled_font_t object from a font face and matrices that * describe the size of the font and the environment in which it will @@ -706,49 +687,154 @@ static const cairo_cache_backend_t _cairo_inner_font_cache_backend = { * cairo_scaled_font_destroy() **/ cairo_scaled_font_t * -cairo_scaled_font_create (cairo_font_face_t *font_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm) +cairo_scaled_font_create (cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options) { - cairo_font_cache_entry_t *entry; - cairo_font_cache_key_t key; - cairo_cache_t *cache; cairo_status_t status; + cairo_scaled_font_map_t *font_map; + cairo_scaled_font_t key, *scaled_font = NULL; - key.font_face = font_face; - key.font_matrix = font_matrix; - key.ctm = ctm; + font_map = _cairo_scaled_font_map_lock (); + if (font_map == NULL) + goto UNWIND; - _lock_global_font_cache (); - cache = _get_outer_font_cache (); - if (cache == NULL) { - _unlock_global_font_cache (); - return NULL; + _cairo_scaled_font_init_key (&key, font_face, + font_matrix, ctm, options); + + /* Return existing scaled_font if it exists in the hash table. */ + if (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry, + (cairo_hash_entry_t**) &scaled_font)) + { + _cairo_scaled_font_map_unlock (); + return cairo_scaled_font_reference (scaled_font); } - - status = _cairo_cache_lookup (cache, &key, (void **) &entry, NULL); - if (CAIRO_OK (status)) - cairo_scaled_font_reference (entry->scaled_font); - - _unlock_global_font_cache (); - if (!CAIRO_OK (status)) - return NULL; - - return entry->scaled_font; + + /* Otherwise create it and insert it into the hash table. */ + status = font_face->backend->scaled_font_create (font_face, font_matrix, + ctm, options, &scaled_font); + if (status) + goto UNWIND_FONT_MAP_LOCK; + + status = _cairo_hash_table_insert (font_map->hash_table, + &scaled_font->hash_entry); + if (status) + goto UNWIND_SCALED_FONT_CREATE; + + _cairo_scaled_font_map_unlock (); + + return scaled_font; + +UNWIND_SCALED_FONT_CREATE: + /* We can't call _cairo_scaled_font_destroy here since it expects + * that the font has already been successfully inserted into the + * hash table. */ + _cairo_scaled_font_fini (scaled_font); + free (scaled_font); +UNWIND_FONT_MAP_LOCK: + _cairo_scaled_font_map_unlock (); +UNWIND: + return NULL; } -void -_cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - const cairo_scaled_font_backend_t *backend) +/** + * cairo_scaled_font_reference: + * @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 + * cairo_scaled_font_destroy() is made. + **/ +cairo_scaled_font_t * +cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font) { - scaled_font->font_matrix = *font_matrix; - scaled_font->ctm = *ctm; - cairo_matrix_multiply (&scaled_font->scale, &scaled_font->font_matrix, &scaled_font->ctm); - - scaled_font->refcount = 1; - scaled_font->backend = backend; + if (scaled_font == NULL) + return NULL; + + if (scaled_font->ref_count == (unsigned int)-1) + return scaled_font; + + /* If the original reference count is 0, then this font must have + * been found in font_map->holdovers, (which means this caching is + * actually working). So now we remove it from the holdovers + * array. */ + if (scaled_font->ref_count == 0) { + cairo_scaled_font_map_t *font_map; + int i; + + font_map = _cairo_scaled_font_map_lock (); + { + for (i = 0; i < font_map->num_holdovers; i++) + if (font_map->holdovers[i] == scaled_font) + break; + assert (i < font_map->num_holdovers); + + font_map->num_holdovers--; + memmove (&font_map->holdovers[i], + &font_map->holdovers[i+1], + (font_map->num_holdovers - i) * sizeof (cairo_scaled_font_t*)); + } + _cairo_scaled_font_map_unlock (); + } + + scaled_font->ref_count++; + + return scaled_font; +} + +/** + * cairo_scaled_font_destroy: + * @scaled_font: a #cairo_scaled_font_t + * + * Decreases the reference count on @font by one. If the result + * is zero, then @font and all associated resources are freed. + * See cairo_scaled_font_reference(). + **/ +void +cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font) +{ + cairo_scaled_font_map_t *font_map; + + if (scaled_font == NULL) + return; + + if (scaled_font->ref_count == (unsigned int)-1) + return; + + if (--(scaled_font->ref_count) > 0) + return; + + font_map = _cairo_scaled_font_map_lock (); + assert (font_map != NULL); + { + /* Rather than immediately destroying this object, we put it into + * the font_map->holdovers array in case it will get used again + * soon. To make room for it, we do actually destroy the + * least-recently-used holdover. + */ + if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS) { + cairo_scaled_font_t *lru; + + lru = font_map->holdovers[0]; + assert (lru->ref_count == 0); + + _cairo_hash_table_remove (font_map->hash_table, &lru->hash_entry); + + _cairo_scaled_font_fini (lru); + free (lru); + + font_map->num_holdovers--; + memmove (&font_map->holdovers[0], + &font_map->holdovers[1], + font_map->num_holdovers * sizeof (cairo_scaled_font_t*)); + } + + font_map->holdovers[font_map->num_holdovers] = scaled_font; + font_map->num_holdovers++; + } + _cairo_scaled_font_map_unlock (); } cairo_status_t @@ -757,6 +843,9 @@ _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, cairo_glyph_t **glyphs, int *num_glyphs) { + if (scaled_font->status) + return scaled_font->status; + return scaled_font->backend->text_to_glyphs (scaled_font, utf8, glyphs, num_glyphs); } @@ -766,6 +855,9 @@ _cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font, int num_glyphs, cairo_text_extents_t *extents) { + if (scaled_font->status) + return scaled_font->status; + return scaled_font->backend->glyph_extents (scaled_font, glyphs, num_glyphs, extents); } @@ -776,6 +868,9 @@ _cairo_scaled_font_glyph_bbox (cairo_scaled_font_t *scaled_font, int num_glyphs, cairo_box_t *bbox) { + if (scaled_font->status) + return scaled_font->status; + return scaled_font->backend->glyph_bbox (scaled_font, glyphs, num_glyphs, bbox); } @@ -795,6 +890,9 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, { cairo_status_t status; + if (scaled_font->status) + return scaled_font->status; + status = _cairo_surface_show_glyphs (scaled_font, operator, pattern, surface, source_x, source_y, @@ -819,20 +917,31 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, int num_glyphs, cairo_path_fixed_t *path) { + if (scaled_font->status) + return scaled_font->status; + return scaled_font->backend->glyph_path (scaled_font, glyphs, num_glyphs, path); } -void +cairo_status_t _cairo_scaled_font_get_glyph_cache_key (cairo_scaled_font_t *scaled_font, cairo_glyph_cache_key_t *key) { + if (scaled_font->status) + return scaled_font->status; + scaled_font->backend->get_glyph_cache_key (scaled_font, key); + + return CAIRO_STATUS_SUCCESS; } cairo_status_t _cairo_scaled_font_font_extents (cairo_scaled_font_t *scaled_font, cairo_font_extents_t *extents) { + if (scaled_font->status) + return scaled_font->status; + return scaled_font->backend->font_extents (scaled_font, extents); } @@ -840,20 +949,28 @@ void _cairo_unscaled_font_init (cairo_unscaled_font_t *unscaled_font, const cairo_unscaled_font_backend_t *backend) { - unscaled_font->refcount = 1; + unscaled_font->ref_count = 1; unscaled_font->backend = backend; } -void +cairo_unscaled_font_t * _cairo_unscaled_font_reference (cairo_unscaled_font_t *unscaled_font) { - unscaled_font->refcount++; + if (unscaled_font == NULL) + return NULL; + + unscaled_font->ref_count++; + + return unscaled_font; } void _cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font) { - if (--(unscaled_font->refcount) > 0) + if (unscaled_font == NULL) + return; + + if (--(unscaled_font->ref_count) > 0) return; unscaled_font->backend->destroy (unscaled_font); @@ -861,82 +978,32 @@ _cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font) free (unscaled_font); } - - /* Public font API follows. */ -/** - * cairo_scaled_font_reference: - * @scaled_font: a #cairo_scaled_font_t - * - * Increases the reference count on @scaled_font by one. This prevents - * @scaled_font from being destroyed until a matching call to - * cairo_scaled_font_destroy() is made. - **/ -void -cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font) -{ - scaled_font->refcount++; -} - -/** - * cairo_scaled_font_destroy: - * @scaled_font: a #cairo_scaled_font_t - * - * Decreases the reference count on @font by one. If the result - * is zero, then @font and all associated resources are freed. - * See cairo_scaled_font_reference(). - **/ -void -cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font) -{ - cairo_font_cache_key_t key; - cairo_cache_t *cache; - - if (--(scaled_font->refcount) > 0) - return; - - if (scaled_font->font_face) { - _lock_global_font_cache (); - cache = _get_inner_font_cache (); - assert (cache); - - key.font_face = scaled_font->font_face; - key.font_matrix = &scaled_font->font_matrix; - key.ctm = &scaled_font->ctm; - - _cairo_cache_remove (cache, &key); - _unlock_global_font_cache (); - - cairo_font_face_destroy (scaled_font->font_face); - } - - scaled_font->backend->destroy (scaled_font); - - free (scaled_font); -} - /** * cairo_scaled_font_extents: * @scaled_font: a #cairo_scaled_font_t * @extents: a #cairo_font_extents_t which to store the retrieved extents. * * Gets the metrics for a #cairo_scaled_font_t. - * - * Return value: %CAIRO_STATUS_SUCCESS on success. Otherwise, an - * error such as %CAIRO_STATUS_NO_MEMORY. **/ -cairo_status_t +void cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font, cairo_font_extents_t *extents) { cairo_int_status_t status; double font_scale_x, font_scale_y; + + if (scaled_font->status) { + _cairo_scaled_font_set_error (scaled_font, scaled_font->status); + return; + } status = _cairo_scaled_font_font_extents (scaled_font, extents); - - if (!CAIRO_OK (status)) - return status; + if (status) { + _cairo_scaled_font_set_error (scaled_font, status); + return; + } _cairo_matrix_compute_scale_factors (&scaled_font->font_matrix, &font_scale_x, &font_scale_y, @@ -952,8 +1019,6 @@ cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font, extents->height *= font_scale_y; extents->max_x_advance *= font_scale_x; extents->max_y_advance *= font_scale_y; - - return status; } /** @@ -980,6 +1045,11 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font, double x_pos = 0.0, y_pos = 0.0; int set = 0; + if (scaled_font->status) { + _cairo_scaled_font_set_error (scaled_font, scaled_font->status); + return; + } + if (!num_glyphs) { extents->x_bearing = 0.0; @@ -1154,21 +1224,27 @@ static const cairo_cache_backend_t cairo_image_cache_backend = { _image_glyph_cache_destroy_cache }; +CAIRO_MUTEX_DECLARE(_global_image_glyph_cache_mutex); + +static cairo_cache_t * +_global_image_glyph_cache = NULL; + void _cairo_lock_global_image_glyph_cache() { - /* FIXME: implement locking. */ + CAIRO_MUTEX_LOCK (_global_image_glyph_cache_mutex); } void _cairo_unlock_global_image_glyph_cache() { - /* FIXME: implement locking. */ + if (_global_image_glyph_cache) { + _cairo_cache_shrink_to (_global_image_glyph_cache, + CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT); + } + CAIRO_MUTEX_UNLOCK (_global_image_glyph_cache_mutex); } -static cairo_cache_t * -_global_image_glyph_cache = NULL; - cairo_cache_t * _cairo_get_global_image_glyph_cache () { @@ -1180,7 +1256,7 @@ _cairo_get_global_image_glyph_cache () if (_cairo_cache_init (_global_image_glyph_cache, &cairo_image_cache_backend, - CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT)) + 0)) goto FAIL; } @@ -1192,3 +1268,19 @@ _cairo_get_global_image_glyph_cache () _global_image_glyph_cache = NULL; return NULL; } + +void +_cairo_font_reset_static_data (void) +{ + _cairo_scaled_font_map_destroy (); + + _cairo_lock_global_image_glyph_cache(); + _cairo_cache_destroy (_global_image_glyph_cache); + _global_image_glyph_cache = NULL; + _cairo_unlock_global_image_glyph_cache(); + + CAIRO_MUTEX_LOCK (cairo_toy_font_face_hash_table_mutex); + _cairo_hash_table_destroy (cairo_toy_font_face_hash_table); + cairo_toy_font_face_hash_table = NULL; + CAIRO_MUTEX_UNLOCK (cairo_toy_font_face_hash_table_mutex); +} diff --git a/gfx/cairo/cairo/src/cairo-ft-font.c b/gfx/cairo/cairo/src/cairo-ft-font.c index c02cd61e5ef3..15180c9879f3 100644 --- a/gfx/cairo/cairo/src/cairo-ft-font.c +++ b/gfx/cairo/cairo/src/cairo-ft-font.c @@ -1,5 +1,6 @@ /* cairo - a vector graphics library with display and print output * + * Copyright © 2000 Keith Packard * Copyright © 2005 Red Hat, Inc * * This library is free software; you can redistribute it and/or @@ -32,8 +33,12 @@ * Contributor(s): * Graydon Hoare * Owen Taylor + * Keith Packard + * Carl Worth */ +#include + #include "cairo-ft-private.h" #include @@ -49,6 +54,19 @@ #define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) #define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0) +/* We pack some of our own information into the bits unused + * by FreeType's load flags. If FreeType ever uses up all + * the load flag bits, we'll have to do something else. + * (probably just store what we care about in load_flags + * then convert into FreeType terms. + */ +#define PRIVATE_FLAG_HINT_METRICS (0x01 << 24) +#define PRIVATE_FLAGS_MASK (0xff << 24) + + /* This is the max number of FT_face objects we keep open at once + */ + #define MAX_OPEN_FACES 10 + /* This is the max number of FT_face objects we keep open at once */ #define MAX_OPEN_FACES 10 @@ -58,310 +76,410 @@ * factors so that hinting works right */ -typedef struct { +typedef struct _cairo_ft_font_transform { double x_scale, y_scale; double shape[2][2]; -} ft_font_transform_t; +} cairo_ft_font_transform_t; /* * We create an object that corresponds to a single font on the disk; * (identified by a filename/id pair) these are shared between all - * fonts using that file. For cairo_ft_scaled_font_create_for_ft_face(), we + * fonts using that file. For cairo_ft_font_face_create_for_ft_face(), we * just create a one-off version with a permanent face value. */ +typedef struct _cairo_ft_font_face cairo_ft_font_face_t; -typedef struct _ft_font_face ft_font_face_t; - -typedef struct { +struct _cairo_ft_unscaled_font { cairo_unscaled_font_t base; - cairo_bool_t from_face; /* from cairo_ft_scaled_font_create_for_ft_face()? */ + cairo_bool_t from_face; /* from cairo_ft_font_face_create_for_ft_face()? */ FT_Face face; /* provided or cached face */ /* only set if from_face is false */ char *filename; int id; - /* We temporarily scale the unscaled font as neede */ - int have_scale; + /* We temporarily scale the unscaled font as needed */ + cairo_bool_t have_scale; cairo_matrix_t current_scale; double x_scale; /* Extracted X scale factor */ double y_scale; /* Extracted Y scale factor */ + cairo_bool_t have_shape; /* true if the current scale has a non-scale component*/ int lock; /* count of how many times this font has been locked */ - ft_font_face_t *faces; /* Linked list of faces for this font */ -} ft_unscaled_font_t; + cairo_ft_font_face_t *faces; /* Linked list of faces for this font */ +}; -struct _ft_font_face { +static int +_cairo_ft_unscaled_font_keys_equal (void *key_a, + void *key_b); + +static void +_cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled); + +struct _cairo_ft_font_face { cairo_font_face_t base; - ft_unscaled_font_t *unscaled; + cairo_ft_unscaled_font_t *unscaled; int load_flags; - ft_font_face_t *next_face; + cairo_ft_font_face_t *next; }; const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend; -static ft_unscaled_font_t * -_ft_unscaled_font_create_from_face (FT_Face face) -{ - ft_unscaled_font_t *unscaled = malloc (sizeof(ft_unscaled_font_t)); - if (!unscaled) - return NULL; - - unscaled->from_face = 1; - unscaled->face = face; - - unscaled->filename = NULL; - unscaled->id = 0; - - unscaled->have_scale = 0; - unscaled->lock = 0; - - unscaled->faces = NULL; - - _cairo_unscaled_font_init (&unscaled->base, - &cairo_ft_unscaled_font_backend); - return unscaled; -} - -static ft_unscaled_font_t * -_ft_unscaled_font_create_from_filename (const char *filename, - int id) -{ - ft_unscaled_font_t *unscaled; - char *new_filename; - - new_filename = strdup (filename); - if (!new_filename) - return NULL; - - unscaled = malloc (sizeof (ft_unscaled_font_t)); - if (!unscaled) { - free (new_filename); - return NULL; - } - - unscaled->from_face = 0; - unscaled->face = NULL; - - unscaled->filename = new_filename; - unscaled->id = id; - - unscaled->have_scale = 0; - unscaled->lock = 0; - - unscaled->faces = NULL; - - _cairo_unscaled_font_init (&unscaled->base, - &cairo_ft_unscaled_font_backend); - return unscaled; -} - /* - * We keep a global cache from [file/id] => [ft_unscaled_font_t]. This - * hash isn't limited in size. However, we limit the number of - * FT_Face objects we keep around; when we've exceeeded that - * limit and need to create a new FT_Face, we dump the FT_Face from - * a random ft_unscaled_font_t. + * We maintain a hash table to map file/id => cairo_ft_unscaled_font_t. + * The hash table itself isn't limited in size. However, we limit the + * number of FT_Face objects we keep around; when we've exceeeded that + * limit and need to create a new FT_Face, we dump the FT_Face from a + * random cairo_ft_unscaled_font_t which has an unlocked FT_Face, (if + * there are any). */ -typedef struct { - cairo_cache_entry_base_t base; - char *filename; - int id; -} cairo_ft_cache_key_t; +typedef struct _cairo_ft_unscaled_font_map { + cairo_hash_table_t *hash_table; + FT_Library ft_library; + int num_open_faces; +} cairo_ft_unscaled_font_map_t; -typedef struct { - cairo_ft_cache_key_t key; - ft_unscaled_font_t *unscaled; -} cairo_ft_cache_entry_t; +static cairo_ft_unscaled_font_map_t *cairo_ft_unscaled_font_map = NULL; -typedef struct { - cairo_cache_t base; - FT_Library lib; - int n_faces; /* Number of open FT_Face objects */ -} ft_cache_t; +CAIRO_MUTEX_DECLARE(cairo_ft_unscaled_font_map_mutex); -static unsigned long -_ft_font_cache_hash (void *cache, void *key) +static void +_cairo_ft_unscaled_font_map_create (void) +{ + cairo_ft_unscaled_font_map_t *font_map; + + /* This function is only intended to be called from + * _cairo_ft_unscaled_font_map_lock. So we'll crash if we can + * detect some other call path. */ + assert (cairo_ft_unscaled_font_map == NULL); + + font_map = malloc (sizeof (cairo_ft_unscaled_font_map_t)); + if (font_map == NULL) + goto FAIL; + + font_map->hash_table = + _cairo_hash_table_create (_cairo_ft_unscaled_font_keys_equal); + + if (font_map->hash_table == NULL) + goto FAIL; + + if (FT_Init_FreeType (&font_map->ft_library)) + goto FAIL; + + font_map->num_open_faces = 0; + + cairo_ft_unscaled_font_map = font_map; + return; + +FAIL: + if (font_map) { + if (font_map->hash_table) + _cairo_hash_table_destroy (font_map->hash_table); + free (font_map); + } + cairo_ft_unscaled_font_map = NULL; +} + +static void +_cairo_ft_unscaled_font_map_destroy (void) +{ + cairo_ft_unscaled_font_t *unscaled; + cairo_ft_unscaled_font_map_t *font_map; + + CAIRO_MUTEX_LOCK (cairo_ft_unscaled_font_map_mutex); + + if (cairo_ft_unscaled_font_map) { + font_map = cairo_ft_unscaled_font_map; + + /* This is rather inefficient, but destroying the hash table + * is something we only do during debugging, (during + * cairo_debug_reset_static_data), when efficiency is not + * relevant. */ + while (1) { + unscaled = _cairo_hash_table_random_entry (font_map->hash_table, + NULL); + if (unscaled == NULL) + break; + _cairo_hash_table_remove (font_map->hash_table, + &unscaled->base.hash_entry); + _cairo_ft_unscaled_font_fini (unscaled); + free (unscaled); + } + + FT_Done_FreeType (font_map->ft_library); + + _cairo_hash_table_destroy (font_map->hash_table); + + free (font_map); + + cairo_ft_unscaled_font_map = NULL; + } + + CAIRO_MUTEX_UNLOCK (cairo_ft_unscaled_font_map_mutex); +} + +static cairo_ft_unscaled_font_map_t * +_cairo_ft_unscaled_font_map_lock (void) +{ + CAIRO_MUTEX_LOCK (cairo_ft_unscaled_font_map_mutex); + + if (cairo_ft_unscaled_font_map == NULL) + { + _cairo_ft_unscaled_font_map_create (); + + if (cairo_ft_unscaled_font_map == NULL) { + CAIRO_MUTEX_UNLOCK (cairo_ft_unscaled_font_map_mutex); + return NULL; + } + } + + return cairo_ft_unscaled_font_map; +} + +static void +_cairo_ft_unscaled_font_map_unlock (void) +{ + CAIRO_MUTEX_UNLOCK (cairo_ft_unscaled_font_map_mutex); +} + +static void +_cairo_ft_unscaled_font_init_key (cairo_ft_unscaled_font_t *key, + char *filename, + int id) { - cairo_ft_cache_key_t *in = (cairo_ft_cache_key_t *) key; unsigned long hash; - /* 1607 is just a random prime. */ - hash = _cairo_hash_string (in->filename); - hash += ((unsigned long) in->id) * 1607; + key->filename = filename; + key->id = id; + + /* 1607 is just an arbitrary prime. */ + hash = _cairo_hash_string (filename); + hash += ((unsigned long) id) * 1607; - return hash; -} - -static int -_ft_font_cache_keys_equal (void *cache, - void *k1, - void *k2) -{ - cairo_ft_cache_key_t *a; - cairo_ft_cache_key_t *b; - a = (cairo_ft_cache_key_t *) k1; - b = (cairo_ft_cache_key_t *) k2; - - return strcmp (a->filename, b->filename) == 0 && - a->id == b->id; + key->base.hash_entry.hash = hash; } +/** + * _cairo_ft_unscaled_font_init: + * + * Initialize a cairo_ft_unscaled_font_t. + * + * There are two basic flavors of cairo_ft_unscaled_font_t, one + * created from an FT_Face and the other created from a filename/id + * pair. These two flavors are identified as from_face and !from_face. + * + * To initialize a from_face font, pass filename==NULL, id=0 and the + * desired face. + * + * To initialize a !from_face font, pass the filename/id as desired + * and face==NULL. + * + * Note that the code handles these two flavors in very distinct + * ways. For example there is a hash_table mapping + * filename/id->cairo_unscaled_font_t in the !from_face case, but no + * parallel in the from_face case, (where the calling code would have + * to do its own mapping to ensure similar sharing). + **/ static cairo_status_t -_ft_font_cache_create_entry (void *cache, - void *key, - void **return_entry) +_cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled, + const char *filename, + int id, + FT_Face face) { - cairo_ft_cache_key_t *k = (cairo_ft_cache_key_t *) key; - cairo_ft_cache_entry_t *entry; + _cairo_unscaled_font_init (&unscaled->base, + &cairo_ft_unscaled_font_backend); - entry = malloc (sizeof (cairo_ft_cache_entry_t)); - if (entry == NULL) - return CAIRO_STATUS_NO_MEMORY; + if (face) { + unscaled->from_face = TRUE; + unscaled->face = face; + unscaled->filename = NULL; + unscaled->id = 0; + } else { + char *filename_copy; - entry->unscaled = _ft_unscaled_font_create_from_filename (k->filename, - k->id); - if (!entry->unscaled) { - free (entry); - return CAIRO_STATUS_NO_MEMORY; + unscaled->from_face = FALSE; + unscaled->face = NULL; + + filename_copy = strdup (filename); + if (filename_copy == NULL) + return CAIRO_STATUS_NO_MEMORY; + + _cairo_ft_unscaled_font_init_key (unscaled, filename_copy, id); } + + unscaled->have_scale = 0; + unscaled->lock = 0; - entry->key.base.memory = 0; - entry->key.filename = entry->unscaled->filename; - entry->key.id = entry->unscaled->id; - - *return_entry = entry; + unscaled->faces = NULL; return CAIRO_STATUS_SUCCESS; } -/* Entries are never spontaneously destroyed; but only when - * we remove them from the cache specifically. We free entry->unscaled - * in the code that removes the entry from the cache - */ -static void -_ft_font_cache_destroy_entry (void *cache, - void *entry) -{ - cairo_ft_cache_entry_t *e = (cairo_ft_cache_entry_t *) entry; - - free (e); -} - -static void -_ft_font_cache_destroy_cache (void *cache) +cairo_bool_t +_cairo_unscaled_font_is_ft (cairo_unscaled_font_t *unscaled_font) { - ft_cache_t *fc = (ft_cache_t *) cache; - FT_Done_FreeType (fc->lib); - free (fc); -} - -static const cairo_cache_backend_t _ft_font_cache_backend = { - _ft_font_cache_hash, - _ft_font_cache_keys_equal, - _ft_font_cache_create_entry, - _ft_font_cache_destroy_entry, - _ft_font_cache_destroy_cache -}; - -static ft_cache_t *_global_ft_cache = NULL; - -static void -_lock_global_ft_cache (void) -{ - /* FIXME: Perform locking here. */ + return unscaled_font->backend == &cairo_ft_unscaled_font_backend; } static void -_unlock_global_ft_cache (void) +_cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled) { - /* FIXME: Perform locking here. */ -} - -static cairo_cache_t * -_get_global_ft_cache (void) -{ - if (_global_ft_cache == NULL) - { - _global_ft_cache = malloc (sizeof(ft_cache_t)); - if (!_global_ft_cache) - goto FAIL; - - if (_cairo_cache_init (&_global_ft_cache->base, - &_ft_font_cache_backend, - 0)) /* No memory limit */ - goto FAIL; - - if (FT_Init_FreeType (&_global_ft_cache->lib)) - goto FAIL; - _global_ft_cache->n_faces = 0; - } - return &_global_ft_cache->base; - - FAIL: - if (_global_ft_cache) - free (_global_ft_cache); - _global_ft_cache = NULL; - return NULL; -} - -/* Finds or creates a ft_unscaled_font for the filename/id from pattern. - * Returns a new reference to the unscaled font. - */ -static ft_unscaled_font_t * -_ft_unscaled_font_get_for_pattern (FcPattern *pattern) -{ - cairo_ft_cache_entry_t *entry; - cairo_ft_cache_key_t key; - cairo_cache_t *cache; - cairo_status_t status; - FcChar8 *filename; - int created_entry; - - if (FcPatternGetString (pattern, FC_FILE, 0, &filename) != FcResultMatch) - return NULL; - key.filename = (char *)filename; - - if (FcPatternGetInteger (pattern, FC_INDEX, 0, &key.id) != FcResultMatch) - return NULL; - - _lock_global_ft_cache (); - cache = _get_global_ft_cache (); - if (cache == NULL) { - _unlock_global_ft_cache (); - return NULL; + if (unscaled->filename) { + free (unscaled->filename); + unscaled->filename = NULL; } - status = _cairo_cache_lookup (cache, &key, (void **) &entry, &created_entry); - if (CAIRO_OK (status) && !created_entry) - _cairo_unscaled_font_reference (&entry->unscaled->base); - - _unlock_global_ft_cache (); - if (!CAIRO_OK (status)) - return NULL; - - return entry->unscaled; + if (unscaled->face) { + FT_Done_Face (unscaled->face); + unscaled->face = NULL; + } } static int +_cairo_ft_unscaled_font_keys_equal (void *key_a, + void *key_b) +{ + cairo_ft_unscaled_font_t *unscaled_a = key_a; + cairo_ft_unscaled_font_t *unscaled_b = key_b; + + return (strcmp (unscaled_a->filename, unscaled_b->filename) == 0 && + unscaled_a->id == unscaled_b->id); +} + +/* Finds or creates a cairo_ft_unscaled_font for the filename/id from + * pattern. Returns a new reference to the unscaled font. + */ +static cairo_ft_unscaled_font_t * +_cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern) +{ + cairo_ft_unscaled_font_t key, *unscaled; + cairo_ft_unscaled_font_map_t *font_map; + cairo_status_t status; + FcChar8 *fc_filename; + char *filename; + int id; + + if (FcPatternGetString (pattern, FC_FILE, 0, &fc_filename) != FcResultMatch) + goto UNWIND; + filename = (char *) fc_filename; + + if (FcPatternGetInteger (pattern, FC_INDEX, 0, &id) != FcResultMatch) + goto UNWIND; + + font_map = _cairo_ft_unscaled_font_map_lock (); + if (font_map == NULL) + goto UNWIND; + + _cairo_ft_unscaled_font_init_key (&key, filename, id); + + /* Return exsiting unscaled font if it exists in the hash table. */ + if (_cairo_hash_table_lookup (font_map->hash_table, &key.base.hash_entry, + (cairo_hash_entry_t **) &unscaled)) + { + _cairo_ft_unscaled_font_map_unlock (); + _cairo_unscaled_font_reference (&unscaled->base); + return unscaled; + } + + /* Otherwise create it and insert into hash table. */ + unscaled = malloc (sizeof (cairo_ft_unscaled_font_t)); + if (unscaled == NULL) + goto UNWIND_FONT_MAP_LOCK; + + status = _cairo_ft_unscaled_font_init (unscaled, filename, id, NULL); + if (status) + goto UNWIND_UNSCALED_MALLOC; + + status = _cairo_hash_table_insert (font_map->hash_table, + &unscaled->base.hash_entry); + if (status) + goto UNWIND_UNSCALED_FONT_INIT; + + _cairo_ft_unscaled_font_map_unlock (); + + return unscaled; + +UNWIND_UNSCALED_FONT_INIT: + _cairo_ft_unscaled_font_fini (unscaled); +UNWIND_UNSCALED_MALLOC: + free (unscaled); +UNWIND_FONT_MAP_LOCK: + _cairo_ft_unscaled_font_map_unlock (); +UNWIND: + return NULL; +} + +static cairo_ft_unscaled_font_t * +_cairo_ft_unscaled_font_create_from_face (FT_Face face) +{ + cairo_status_t status; + cairo_ft_unscaled_font_t *unscaled; + + unscaled = malloc (sizeof (cairo_ft_unscaled_font_t)); + if (unscaled == NULL) + return NULL; + + status = _cairo_ft_unscaled_font_init (unscaled, NULL, 0, face); + if (status) { + free (unscaled); + return NULL; + } + + return unscaled; +} + +static void +_cairo_ft_unscaled_font_destroy (void *abstract_font) +{ + cairo_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. + */ + if (unscaled->faces && !unscaled->faces->unscaled) + cairo_font_face_destroy (&unscaled->faces->base); + } else { + cairo_ft_unscaled_font_map_t *font_map; + + font_map = _cairo_ft_unscaled_font_map_lock (); + /* All created objects must have been mapped in the font map. */ + assert (font_map != NULL); + + _cairo_hash_table_remove (font_map->hash_table, + &unscaled->base.hash_entry); + + _cairo_ft_unscaled_font_map_unlock (); + + _cairo_ft_unscaled_font_fini (unscaled); + } +} + +static cairo_bool_t _has_unlocked_face (void *entry) { - cairo_ft_cache_entry_t *e = entry; + cairo_ft_unscaled_font_t *unscaled = entry; - return (e->unscaled->lock == 0 && e->unscaled->face); + return (unscaled->lock == 0 && unscaled->face); } /* Ensures that an unscaled font has a face object. If we exceed * MAX_OPEN_FACES, try to close some. + * + * This differs from _cairo_ft_scaled_font_lock_face in that it doesn't + * set the scale on the face, but just returns it at the last scale. */ -static FT_Face -_ft_unscaled_font_lock_face (ft_unscaled_font_t *unscaled) +FT_Face +_cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled) { - ft_cache_t *ftcache; + cairo_ft_unscaled_font_map_t *font_map; FT_Face face = NULL; if (unscaled->face) { @@ -369,27 +487,30 @@ _ft_unscaled_font_lock_face (ft_unscaled_font_t *unscaled) return unscaled->face; } + /* If this unscaled font was created from an FT_Face then we just + * returned it above. */ assert (!unscaled->from_face); - _lock_global_ft_cache (); - ftcache = (ft_cache_t *) _get_global_ft_cache (); - assert (ftcache != NULL); + font_map = _cairo_ft_unscaled_font_map_lock (); + assert (font_map != NULL); - while (ftcache->n_faces >= MAX_OPEN_FACES) { - cairo_ft_cache_entry_t *entry; + while (font_map->num_open_faces >= MAX_OPEN_FACES) + { + cairo_ft_unscaled_font_t *entry; - entry = _cairo_cache_random_entry ((cairo_cache_t *)ftcache, _has_unlocked_face); - if (entry) { - FT_Done_Face (entry->unscaled->face); - entry->unscaled->face = NULL; - entry->unscaled->have_scale = 0; - ftcache->n_faces--; - } else { + entry = _cairo_hash_table_random_entry (font_map->hash_table, + _has_unlocked_face); + if (entry == NULL) break; - } + + FT_Done_Face (entry->face); + entry->face = NULL; + entry->have_scale = 0; + + font_map->num_open_faces--; } - if (FT_New_Face (ftcache->lib, + if (FT_New_Face (font_map->ft_library, unscaled->filename, unscaled->id, &face) != FT_Err_Ok) @@ -397,17 +518,19 @@ _ft_unscaled_font_lock_face (ft_unscaled_font_t *unscaled) unscaled->face = face; unscaled->lock++; - ftcache->n_faces++; + + font_map->num_open_faces++; FAIL: - _unlock_global_ft_cache (); + _cairo_ft_unscaled_font_map_unlock (); + return face; } -/* Unlock unscaled font locked with _ft_unscaled_font_lock_face +/* Unlock unscaled font locked with _cairo_ft_unscaled_font_lock_face */ -static void -_ft_unscaled_font_unlock_face (ft_unscaled_font_t *unscaled) +void +_cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled) { assert (unscaled->lock > 0); @@ -415,7 +538,7 @@ _ft_unscaled_font_unlock_face (ft_unscaled_font_t *unscaled) } static void -_compute_transform (ft_font_transform_t *sf, +_compute_transform (cairo_ft_font_transform_t *sf, cairo_matrix_t *scale) { cairo_matrix_t normalized = *scale; @@ -431,22 +554,31 @@ _compute_transform (ft_font_transform_t *sf, _cairo_matrix_compute_scale_factors (&normalized, &sf->x_scale, &sf->y_scale, /* XXX */ 1); - cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale); - _cairo_matrix_get_affine (&normalized, - &sf->shape[0][0], &sf->shape[0][1], - &sf->shape[1][0], &sf->shape[1][1], - &tx, &ty); + + if (sf->x_scale != 0 && sf->y_scale != 0) { + cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale); + + _cairo_matrix_get_affine (&normalized, + &sf->shape[0][0], &sf->shape[0][1], + &sf->shape[1][0], &sf->shape[1][1], + &tx, &ty); + } else { + sf->shape[0][0] = sf->shape[1][1] = 1.0; + sf->shape[0][1] = sf->shape[1][0] = 0.0; + } } /* Temporarily scales an unscaled font to the give scale. We catch * scaling to the same size, since changing a FT_Face is expensive. */ static void -_ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled, - cairo_matrix_t *scale) +_cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled, + cairo_matrix_t *scale) { - ft_font_transform_t sf; + cairo_ft_font_transform_t sf; FT_Matrix mat; + FT_UInt pixel_width, pixel_height; + FT_Error error; assert (unscaled->face != NULL); @@ -470,99 +602,312 @@ _ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled, mat.xy = - DOUBLE_TO_16_16(sf.shape[1][0]); mat.yy = DOUBLE_TO_16_16(sf.shape[1][1]); + unscaled->have_shape = (mat.xx != 0x10000 || + mat.yx != 0x00000 || + mat.xy != 0x00000 || + mat.yy != 0x10000); + FT_Set_Transform(unscaled->face, &mat, NULL); - - FT_Set_Pixel_Sizes(unscaled->face, - (FT_UInt) sf.x_scale, - (FT_UInt) sf.y_scale); -} -static void -_cairo_ft_unscaled_font_destroy (void *abstract_font) -{ - ft_unscaled_font_t *unscaled = abstract_font; - - if (unscaled->from_face) { - /* See comments in _ft_font_face_destroy about the "zombie" state - * for a _ft_font_face. - */ - if (unscaled->faces && !unscaled->faces->unscaled) - cairo_font_face_destroy (&unscaled->faces->base); + if ((unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE) != 0) { + pixel_width = sf.x_scale; + pixel_height = sf.y_scale; + error = FT_Set_Char_Size (unscaled->face, + sf.x_scale * 64.0, + sf.y_scale * 64.0, + 0, 0); } else { - cairo_cache_t *cache; - cairo_ft_cache_key_t key; - - _lock_global_ft_cache (); - cache = _get_global_ft_cache (); - assert (cache); + double min_distance = DBL_MAX; + int i; + int best_i = 0; - key.filename = unscaled->filename; - key.id = unscaled->id; + pixel_width = pixel_height = 0; - _cairo_cache_remove (cache, &key); - - _unlock_global_ft_cache (); - - if (unscaled->filename) - free (unscaled->filename); - - if (unscaled->face) - FT_Done_Face (unscaled->face); + for (i = 0; i < unscaled->face->num_fixed_sizes; i++) { +#if HAVE_FT_BITMAP_SIZE_Y_PPEM + double size = unscaled->face->available_sizes[i].y_ppem / 64.; +#else + double size = unscaled->face->available_sizes[i].height; +#endif + double distance = fabs (size - sf.y_scale); + + if (distance <= min_distance) { + min_distance = distance; + best_i = i; + } + } +#if HAVE_FT_BITMAP_SIZE_Y_PPEM + error = FT_Set_Char_Size (unscaled->face, + unscaled->face->available_sizes[best_i].x_ppem, + unscaled->face->available_sizes[best_i].y_ppem, + 0, 0); + if (error) +#endif + error = FT_Set_Pixel_Sizes (unscaled->face, + unscaled->face->available_sizes[best_i].width, + unscaled->face->available_sizes[best_i].height); } + + assert (error == 0); } -static cairo_status_t -_cairo_ft_unscaled_font_create_glyph (void *abstract_font, - cairo_image_glyph_cache_entry_t *val) +/* Empirically-derived subpixel filtering values thanks to Keith + * Packard and libXft. */ +static const int filters[3][3] = { + /* red */ +#if 0 + { 65538*4/7,65538*2/7,65538*1/7 }, + /* green */ + { 65536*1/4, 65536*2/4, 65537*1/4 }, + /* blue */ + { 65538*1/7,65538*2/7,65538*4/7 }, +#endif + { 65538*9/13,65538*3/13,65538*1/13 }, + /* green */ + { 65538*1/6, 65538*4/6, 65538*1/6 }, + /* blue */ + { 65538*1/13,65538*3/13,65538*9/13 }, +}; + +static cairo_bool_t +_native_byte_order_lsb (void) { - ft_unscaled_font_t *unscaled = abstract_font; - FT_GlyphSlot glyphslot; - unsigned int width, height, stride; - FT_Face face; - FT_Outline *outline; - FT_BBox cbox; - FT_Bitmap bitmap; - FT_Glyph_Metrics *metrics; - cairo_status_t status = CAIRO_STATUS_SUCCESS; + int x = 1; - face = _ft_unscaled_font_lock_face (unscaled); - if (!face) - return CAIRO_STATUS_NO_MEMORY; + return *((char *) &x) == 1; +} - glyphslot = face->glyph; - metrics = &glyphslot->metrics; +/* Fills in val->image with an image surface created from @bitmap + */ +static cairo_status_t +_get_bitmap_surface (cairo_image_glyph_cache_entry_t *val, + FT_Bitmap *bitmap, + cairo_bool_t own_buffer, + int rgba) +{ + int width, height, stride; + unsigned char *data; + int format = CAIRO_FORMAT_A8; + cairo_bool_t subpixel = FALSE; + + width = bitmap->width; + height = bitmap->rows; + + if (width * height == 0) { + if (own_buffer && bitmap->buffer) + free (bitmap->buffer); + + val->image = NULL; + } else { + switch (bitmap->pixel_mode) { + case FT_PIXEL_MODE_MONO: + stride = (((width + 31) & ~31) >> 3); + if (own_buffer) { + data = bitmap->buffer; + assert (stride == bitmap->pitch); + } else { + data = malloc (stride * height); + if (!data) + return CAIRO_STATUS_NO_MEMORY; - _ft_unscaled_font_set_scale (unscaled, &val->key.scale); + if (stride == bitmap->pitch) { + memcpy (data, bitmap->buffer, stride * height); + } else { + int i; + unsigned char *source, *dest; + + source = bitmap->buffer; + dest = data; + for (i = height; i; i--) { + memcpy (dest, source, bitmap->pitch); + memset (dest + bitmap->pitch, '\0', stride - bitmap->pitch); + + source += bitmap->pitch; + dest += stride; + } + } + } + + if (_native_byte_order_lsb()) + { + unsigned char *d = data, c; + int count = stride * height; + + while (count--) { + c = *d; + c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55); + c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33); + c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f); + *d++ = c; + } + } + format = CAIRO_FORMAT_A1; + break; - if (FT_Load_Glyph (face, val->key.index, val->key.flags) != 0) { - status = CAIRO_STATUS_NO_MEMORY; - goto FAIL; + case FT_PIXEL_MODE_LCD: + case FT_PIXEL_MODE_LCD_V: + case FT_PIXEL_MODE_GRAY: + if (rgba == FC_RGBA_NONE || rgba == FC_RGBA_UNKNOWN) + { + stride = bitmap->pitch; + if (own_buffer) { + data = bitmap->buffer; + } else { + data = malloc (stride * height); + if (!data) + return CAIRO_STATUS_NO_MEMORY; + memcpy (data, bitmap->buffer, stride * height); + } + format = CAIRO_FORMAT_A8; + } else { + int x, y; + unsigned char *in_line, *out_line, *in; + unsigned int *out; + unsigned int red, green, blue; + int rf, gf, bf; + int s; + int o, os; + unsigned char *data_rgba; + unsigned int width_rgba, stride_rgba; + int vmul = 1; + int hmul = 1; + + switch (rgba) { + case FC_RGBA_RGB: + case FC_RGBA_BGR: + default: + width /= 3; + hmul = 3; + break; + case FC_RGBA_VRGB: + case FC_RGBA_VBGR: + vmul = 3; + height /= 3; + break; + } + subpixel = TRUE; + /* + * Filter the glyph to soften the color fringes + */ + width_rgba = width; + stride = bitmap->pitch; + stride_rgba = (width_rgba * 4 + 3) & ~3; + data_rgba = calloc (1, stride_rgba * height); + + os = 1; + switch (rgba) { + case FC_RGBA_VRGB: + os = stride; + case FC_RGBA_RGB: + default: + rf = 0; + gf = 1; + bf = 2; + break; + case FC_RGBA_VBGR: + os = stride; + case FC_RGBA_BGR: + bf = 0; + gf = 1; + rf = 2; + break; + } + in_line = bitmap->buffer; + out_line = data_rgba; + for (y = 0; y < height; y++) + { + in = in_line; + out = (unsigned int *) out_line; + in_line += stride * vmul; + out_line += stride_rgba; + for (x = 0; x < width * hmul; x += hmul) + { + red = green = blue = 0; + o = 0; + for (s = 0; s < 3; s++) + { + red += filters[rf][s]*in[x+o]; + green += filters[gf][s]*in[x+o]; + blue += filters[bf][s]*in[x+o]; + o += os; + } + red = red / 65536; + green = green / 65536; + blue = blue / 65536; + *out++ = (green << 24) | (red << 16) | (green << 8) | blue; + } + } + + /* Images here are stored in native format. The + * backend must convert to its own format as needed + */ + + if (own_buffer) + free (bitmap->buffer); + data = data_rgba; + stride = stride_rgba; + format = CAIRO_FORMAT_ARGB32; + } + break; + case FT_PIXEL_MODE_GRAY2: + case FT_PIXEL_MODE_GRAY4: + /* These could be triggered by very rare types of TrueType fonts */ + default: + return CAIRO_STATUS_NO_MEMORY; + } + + val->image = (cairo_image_surface_t *) + cairo_image_surface_create_for_data (data, + format, + width, height, stride); + if (val->image->base.status) { + free (data); + return CAIRO_STATUS_NO_MEMORY; + } + + if (subpixel) + pixman_image_set_component_alpha (val->image->pixman_image, TRUE); + + _cairo_image_surface_assume_ownership_of_data (val->image); } - /* - * Note: the font's coordinate system is upside down from ours, so the - * Y coordinates of the bearing and advance need to be negated. - * - * Scale metrics back to glyph space from the scaled glyph space returned - * by FreeType - */ + val->size.width = width; + val->size.height = height; - val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / unscaled->x_scale; - val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / unscaled->y_scale; + return CAIRO_STATUS_SUCCESS; +} - val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / unscaled->x_scale; - val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / unscaled->y_scale; - - /* - * use untransformed advance values - * XXX uses horizontal advance only at present; - should provide FT_LOAD_VERTICAL_LAYOUT - */ - - val->extents.x_advance = DOUBLE_FROM_26_6 (face->glyph->metrics.horiAdvance) / unscaled->x_scale; - val->extents.y_advance = 0 / unscaled->y_scale; - - outline = &glyphslot->outline; +/* Converts an outline FT_GlyphSlot into an image + * + * This could go through _render_glyph_bitmap as well, letting + * FreeType convert the outline to a bitmap, but doing it ourselves + * has two minor advantages: first, we save a copy of the bitmap + * buffer: we can directly use the buffer that FreeType renders + * into. + * + * Second, it may help when we add support for subpixel + * rendering: the Xft code does it this way. (Keith thinks that + * it may also be possible to get the subpixel rendering with + * FT_Render_Glyph: something worth looking into in more detail + * when we add subpixel support. If so, we may want to eliminate + * this version of the code path entirely. + */ +static cairo_status_t +_render_glyph_outline (FT_Face face, + cairo_image_glyph_cache_entry_t *val) +{ + int rgba = FC_RGBA_UNKNOWN; + FT_GlyphSlot glyphslot = face->glyph; + FT_Outline *outline = &glyphslot->outline; + FT_Bitmap bitmap; + FT_BBox cbox; + FT_Matrix matrix; + int hmul = 1; + int vmul = 1; + unsigned int width, height, stride; + cairo_format_t format; + cairo_bool_t subpixel = FALSE; + cairo_status_t status; FT_Outline_Get_CBox (outline, &cbox); @@ -570,47 +915,88 @@ _cairo_ft_unscaled_font_create_glyph (void *abstract_ cbox.yMin &= -64; cbox.xMax = (cbox.xMax + 63) & -64; cbox.yMax = (cbox.yMax + 63) & -64; - + width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6); height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6); - stride = (width + 3) & -4; - - if (width * height == 0) - val->image = NULL; - else - { + stride = (width * hmul + 3) & ~3; - bitmap.pixel_mode = ft_pixel_mode_grays; - bitmap.num_grays = 256; - bitmap.width = width; - bitmap.rows = height; + if (width * height == 0) { + /* Looks like fb handles zero-sized images just fine */ + if ((val->key.flags & FT_LOAD_MONOCHROME) != 0) + format = CAIRO_FORMAT_A8; + else if (FT_LOAD_TARGET_MODE (val->key.flags) == FT_RENDER_MODE_LCD || + FT_LOAD_TARGET_MODE (val->key.flags) == FT_RENDER_MODE_LCD_V) + format= CAIRO_FORMAT_ARGB32; + else + format = CAIRO_FORMAT_A8; + + val->image = (cairo_image_surface_t *) + cairo_image_surface_create_for_data (NULL, format, 0, 0, 0); + if (val->image->base.status) + return CAIRO_STATUS_NO_MEMORY; + } else { + + matrix.xx = matrix.yy = 0x10000L; + matrix.xy = matrix.yx = 0; + + if ((val->key.flags & FT_LOAD_MONOCHROME) != 0) { + bitmap.pixel_mode = FT_PIXEL_MODE_MONO; + bitmap.num_grays = 1; + stride = ((width + 31) & -32) >> 3; + } else { + /* XXX not a complete set of flags. This code + * will go away when cworth rewrites the glyph + * cache code */ + if (FT_LOAD_TARGET_MODE (val->key.flags) == FT_RENDER_MODE_LCD) + rgba = FC_RGBA_RGB; + else if (FT_LOAD_TARGET_MODE (val->key.flags) == FT_RENDER_MODE_LCD_V) + rgba = FC_RGBA_VBGR; + + switch (rgba) { + case FC_RGBA_RGB: + case FC_RGBA_BGR: + matrix.xx *= 3; + hmul = 3; + subpixel = TRUE; + break; + case FC_RGBA_VRGB: + case FC_RGBA_VBGR: + matrix.yy *= 3; + vmul = 3; + subpixel = TRUE; + break; + } + if (subpixel) + format = CAIRO_FORMAT_ARGB32; + else + format = CAIRO_FORMAT_A8; + + if (subpixel) + FT_Outline_Transform (outline, &matrix); + + bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; + bitmap.num_grays = 256; + stride = (width * hmul + 3) & -4; + } bitmap.pitch = stride; - bitmap.buffer = calloc (1, stride * height); + bitmap.width = width * hmul; + bitmap.rows = height * vmul; + bitmap.buffer = calloc (1, stride * bitmap.rows); if (bitmap.buffer == NULL) { - status = CAIRO_STATUS_NO_MEMORY; - goto FAIL; + return CAIRO_STATUS_NO_MEMORY; } - FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin); + FT_Outline_Translate (outline, -cbox.xMin*hmul, -cbox.yMin*vmul); if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) { free (bitmap.buffer); - status = CAIRO_STATUS_NO_MEMORY; - goto FAIL; + return CAIRO_STATUS_NO_MEMORY; } - - val->image = (cairo_image_surface_t *) - cairo_image_surface_create_for_data (bitmap.buffer, - CAIRO_FORMAT_A8, - width, height, stride); - if (val->image == NULL) { - free (bitmap.buffer); - status = CAIRO_STATUS_NO_MEMORY; - goto FAIL; - } - - _cairo_image_surface_assume_ownership_of_data (val->image); + + status = _get_bitmap_surface (val, &bitmap, TRUE, rgba); + if (status) + return status; } /* @@ -618,14 +1004,272 @@ _cairo_ft_unscaled_font_create_glyph (void *abstract_ * Y coordinate of the control box needs to be negated. */ - val->size.width = (unsigned short) width; - val->size.height = (unsigned short) height; val->size.x = (short) (cbox.xMin >> 6); val->size.y = - (short) (cbox.yMax >> 6); + + return CAIRO_STATUS_SUCCESS; +} + +/* Converts a bitmap (or other) FT_GlyphSlot into an image + * + * This could go through _render_glyph_bitmap as well, letting + * FreeType convert the outline to a bitmap, but doing it ourselves + * has two minor advantages: first, we save a copy of the bitmap + * buffer: we can directly use the buffer that FreeType renders + * into. + * + * Second, it may help when we add support for subpixel + * rendering: the Xft code does it this way. (Keith thinks that + * it may also be possible to get the subpixel rendering with + * FT_Render_Glyph: something worth looking into in more detail + * when we add subpixel support. If so, we may want to eliminate + * this version of the code path entirely. + */ +static cairo_status_t +_render_glyph_bitmap (FT_Face face, + cairo_image_glyph_cache_entry_t *val) +{ + FT_GlyphSlot glyphslot = face->glyph; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + FT_Error error; + + /* According to the FreeType docs, glyphslot->format could be + * something other than FT_GLYPH_FORMAT_OUTLINE or + * FT_GLYPH_FORMAT_BITMAP. Calling FT_Render_Glyph gives FreeType + * the opportunity to convert such to + * bitmap. FT_GLYPH_FORMAT_COMPOSITE will not be encountered since + * we avoid the FT_LOAD_NO_RECURSE flag. + */ + error = FT_Render_Glyph (glyphslot, FT_RENDER_MODE_NORMAL); + if (error) + return CAIRO_STATUS_NO_MEMORY; + + _get_bitmap_surface (val, &glyphslot->bitmap, FALSE, FC_RGBA_NONE); + + val->size.x = glyphslot->bitmap_left; + val->size.y = - glyphslot->bitmap_top; + return status; +} + +static cairo_status_t +_transform_glyph_bitmap (cairo_image_glyph_cache_entry_t *val) +{ + cairo_ft_font_transform_t sf; + cairo_matrix_t original_to_transformed; + cairo_matrix_t transformed_to_original; + cairo_image_surface_t *old_image; + cairo_surface_t *image; + double x[4], y[4]; + double origin_x, origin_y; + int i; + int x_min, y_min, x_max, y_max; + int width, height; + cairo_status_t status; + cairo_surface_pattern_t pattern; + + /* We want to compute a transform that takes the origin + * (val->size.x, val->size.y) to 0,0, then applies the "shape" + * portion of the font transform + */ + _compute_transform (&sf, &val->key.scale); + + cairo_matrix_init (&original_to_transformed, + sf.shape[0][0], sf.shape[0][1], + sf.shape[1][0], sf.shape[1][1], + 0, 0); + + cairo_matrix_translate (&original_to_transformed, + val->size.x, val->size.y); + + /* Find the bounding box of the original bitmap under that + * transform + */ + x[0] = 0; y[0] = 0; + x[1] = val->size.width; y[1] = 0; + x[2] = val->size.width; y[2] = val->size.height; + x[3] = 0; y[3] = val->size.height; + + for (i = 0; i < 4; i++) + cairo_matrix_transform_point (&original_to_transformed, + &x[i], &y[i]); + + x_min = floor (x[0]); y_min = floor (y[0]); + x_max = ceil (x[0]); y_max = ceil (y[0]); + + for (i = 1; i < 4; i++) { + if (x[i] < x_min) + x_min = floor (x[i]); + if (x[i] > x_max) + x_max = ceil (x[i]); + if (y[i] < y_min) + y_min = floor (y[i]); + if (y[i] > y_max) + y_max = ceil (y[i]); + } + + /* Adjust the transform so that the bounding box starts at 0,0 ... + * this gives our final transform from original bitmap to transformed + * bitmap. + */ + original_to_transformed.x0 -= x_min; + original_to_transformed.y0 -= y_min; + + /* Create the transformed bitmap + */ + width = x_max - x_min; + height = y_max - y_min; + + transformed_to_original = original_to_transformed; + status = cairo_matrix_invert (&transformed_to_original); + if (status) + return status; + + /* We need to pad out the width to 32-bit intervals for cairo-xlib-surface.c */ + width = (width + 3) & ~3; + image = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); + if (image->status) + return CAIRO_STATUS_NO_MEMORY; + + /* Initialize it to empty + */ + _cairo_surface_fill_rectangle (image, CAIRO_OPERATOR_SOURCE, + CAIRO_COLOR_TRANSPARENT, + 0, 0, + width, height); + + /* Draw the original bitmap transformed into the new bitmap + */ + _cairo_pattern_init_for_surface (&pattern, &val->image->base); + cairo_pattern_set_matrix (&pattern.base, &transformed_to_original); + + _cairo_surface_composite (CAIRO_OPERATOR_OVER, + &pattern.base, NULL, image, + 0, 0, 0, 0, 0, 0, + width, + height); + + _cairo_pattern_fini (&pattern.base); + + /* Now update the cache entry for the new bitmap, recomputing + * the origin based on the final transform. + */ + origin_x = - val->size.x; + origin_y = - val->size.y; + cairo_matrix_transform_point (&original_to_transformed, + &origin_x, &origin_y); + + old_image = val->image; + val->image = (cairo_image_surface_t *)image; + cairo_surface_destroy (&old_image->base); + + val->size.width = width; + val->size.height = height; + val->size.x = - floor (origin_x + 0.5); + val->size.y = - floor (origin_y + 0.5); + + return status; +} + +static cairo_status_t +_cairo_ft_unscaled_font_create_glyph (void *abstract_font, + cairo_image_glyph_cache_entry_t *val) +{ + cairo_ft_unscaled_font_t *unscaled = abstract_font; + FT_GlyphSlot glyphslot; + FT_Face face; + FT_Glyph_Metrics *metrics; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + double x_factor, y_factor; + + face = _cairo_ft_unscaled_font_lock_face (unscaled); + if (!face) + return CAIRO_STATUS_NO_MEMORY; + + glyphslot = face->glyph; + metrics = &glyphslot->metrics; + + _cairo_ft_unscaled_font_set_scale (unscaled, &val->key.scale); + + if (FT_Load_Glyph (face, val->key.index, val->key.flags & ~PRIVATE_FLAGS_MASK) != 0) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; + } + + if (unscaled->x_scale == 0) + x_factor = 0; + else + x_factor = 1 / unscaled->x_scale; + + if (unscaled->y_scale == 0) + y_factor = 0; + else + y_factor = 1 / unscaled->y_scale; + + /* + * Note: the font's coordinate system is upside down from ours, so the + * Y coordinates of the bearing and advance need to be negated. + * + * Scale metrics back to glyph space from the scaled glyph space returned + * by FreeType + * + * If we want hinted metrics but aren't asking for hinted glyphs from + * FreeType, then we need to do the metric hinting ourselves. + */ + + if ((val->key.flags & PRIVATE_FLAG_HINT_METRICS) && + (val->key.flags & FT_LOAD_NO_HINTING)) { + FT_Pos x1, x2; + FT_Pos y1, y2; + FT_Pos advance; + + x1 = (metrics->horiBearingX) & -64; + x2 = (metrics->horiBearingX + metrics->width + 63) & -64; + y1 = (metrics->horiBearingY) & -64; + y2 = (metrics->horiBearingY + metrics->height + 63) & -64; + + advance = ((metrics->horiAdvance + 32) & -64); + + val->extents.x_bearing = DOUBLE_FROM_26_6 (x1) * x_factor; + val->extents.y_bearing = -DOUBLE_FROM_26_6 (y1) * y_factor; + + val->extents.width = DOUBLE_FROM_26_6 (x2 - x1) * x_factor; + val->extents.height = DOUBLE_FROM_26_6 (y2 - y1) * y_factor; + + /* + * use untransformed advance values + * XXX uses horizontal advance only at present; should provide FT_LOAD_VERTICAL_LAYOUT + */ + val->extents.x_advance = DOUBLE_FROM_26_6 (advance) * x_factor; + val->extents.y_advance = 0; + } else { + val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) * x_factor; + val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) * y_factor; + + val->extents.width = DOUBLE_FROM_26_6 (metrics->width) * x_factor; + val->extents.height = DOUBLE_FROM_26_6 (metrics->height) * y_factor; + + val->extents.x_advance = DOUBLE_FROM_26_6 (face->glyph->metrics.horiAdvance) * x_factor; + val->extents.y_advance = 0 * y_factor; + } + + if (glyphslot->format == FT_GLYPH_FORMAT_OUTLINE) + status = _render_glyph_outline (face, val); + else + status = _render_glyph_bitmap (face, val); + + if (unscaled->have_shape && + (unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE) == 0) + status = _transform_glyph_bitmap (val); + FAIL: - _ft_unscaled_font_unlock_face (unscaled); - + if (status && val->image) { + cairo_surface_destroy (&val->image->base); + val->image = NULL; + } + + _cairo_ft_unscaled_font_unlock_face (unscaled); + return status; } @@ -636,46 +1280,43 @@ const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend = { /* cairo_ft_scaled_font_t */ -typedef struct { +typedef struct _cairo_ft_scaled_font { cairo_scaled_font_t base; + cairo_ft_unscaled_font_t *unscaled; int load_flags; - ft_unscaled_font_t *unscaled; } cairo_ft_scaled_font_t; const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend; -/* for compatibility with older freetype versions */ -#ifndef FT_LOAD_TARGET_MONO -#define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME -#endif - /* The load flags passed to FT_Load_Glyph control aspects like hinting and * antialiasing. Here we compute them from the fields of a FcPattern. */ static int -_get_load_flags (FcPattern *pattern) +_get_pattern_load_flags (FcPattern *pattern) { - FcBool antialias, hinting, autohint; + FcBool antialias, vertical_layout, hinting, autohint; + int rgba; #ifdef FC_HINT_STYLE int hintstyle; #endif int load_flags = 0; + int target_flags = 0; /* disable antialiasing if requested */ if (FcPatternGetBool (pattern, FC_ANTIALIAS, 0, &antialias) != FcResultMatch) antialias = FcTrue; - + if (antialias) load_flags |= FT_LOAD_NO_BITMAP; else - load_flags |= FT_LOAD_TARGET_MONO; + load_flags |= FT_LOAD_MONOCHROME; /* disable hinting if requested */ if (FcPatternGetBool (pattern, FC_HINTING, 0, &hinting) != FcResultMatch) hinting = FcTrue; - + #ifdef FC_HINT_STYLE if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) hintstyle = FC_HINT_FULL; @@ -683,19 +1324,46 @@ _get_load_flags (FcPattern *pattern) if (!hinting || hintstyle == FC_HINT_NONE) load_flags |= FT_LOAD_NO_HINTING; - switch (hintstyle) { - case FC_HINT_SLIGHT: - case FC_HINT_MEDIUM: - load_flags |= FT_LOAD_TARGET_LIGHT; - break; - default: - load_flags |= FT_LOAD_TARGET_NORMAL; - break; + if (antialias) { + switch (hintstyle) { + case FC_HINT_SLIGHT: + case FC_HINT_MEDIUM: + target_flags = FT_LOAD_TARGET_LIGHT; + break; + default: + target_flags = FT_LOAD_TARGET_NORMAL; + break; + } + } else { +#ifdef FT_LOAD_TARGET_MONO + target_flags = FT_LOAD_TARGET_MONO; +#endif } #else /* !FC_HINT_STYLE */ if (!hinting) - load_flags |= FT_LOAD_NO_HINTING; + target_flags = FT_LOAD_NO_HINTING; #endif /* FC_FHINT_STYLE */ + + if (FcPatternGetInteger (pattern, + FC_RGBA, 0, &rgba) != FcResultMatch) + rgba = FC_RGBA_UNKNOWN; + + switch (rgba) { + case FC_RGBA_UNKNOWN: + case FC_RGBA_NONE: + default: + break; + case FC_RGBA_RGB: + case FC_RGBA_BGR: + target_flags = FT_LOAD_TARGET_LCD; + break; + case FC_RGBA_VRGB: + case FC_RGBA_VBGR: + target_flags = FT_LOAD_TARGET_LCD_V; + break; + } + + load_flags |= target_flags; /* force autohinting if requested */ if (FcPatternGetBool (pattern, @@ -705,53 +1373,125 @@ _get_load_flags (FcPattern *pattern) if (autohint) load_flags |= FT_LOAD_FORCE_AUTOHINT; + if (FcPatternGetBool (pattern, + FC_VERTICAL_LAYOUT, 0, &vertical_layout) != FcResultMatch) + vertical_layout = FcFalse; + + if (vertical_layout) + load_flags |= FT_LOAD_VERTICAL_LAYOUT; + + return load_flags; +} + +static int +_get_options_load_flags (const cairo_font_options_t *options) +{ + int load_flags = 0; + + /* disable antialiasing if requested */ + switch (options->antialias) { + case CAIRO_ANTIALIAS_NONE: +#ifdef FT_LOAD_TARGET_MONO + load_flags |= FT_LOAD_TARGET_MONO; +#endif + load_flags |= FT_LOAD_MONOCHROME; + break; + case CAIRO_ANTIALIAS_SUBPIXEL: + switch (options->subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_DEFAULT: + case CAIRO_SUBPIXEL_ORDER_RGB: + case CAIRO_SUBPIXEL_ORDER_BGR: + load_flags |= FT_LOAD_TARGET_LCD; + break; + case CAIRO_SUBPIXEL_ORDER_VRGB: + case CAIRO_SUBPIXEL_ORDER_VBGR: + load_flags |= FT_LOAD_TARGET_LCD_V; + break; + } + /* fall through ... */ + case CAIRO_ANTIALIAS_DEFAULT: + case CAIRO_ANTIALIAS_GRAY: + load_flags |= FT_LOAD_NO_BITMAP; + break; + } + + /* disable hinting if requested */ + switch (options->hint_style) { + case CAIRO_HINT_STYLE_NONE: + load_flags |= FT_LOAD_NO_HINTING; + break; + case CAIRO_HINT_STYLE_SLIGHT: + case CAIRO_HINT_STYLE_MEDIUM: + load_flags |= FT_LOAD_TARGET_LIGHT; + break; + case CAIRO_HINT_STYLE_FULL: + default: + load_flags |= FT_LOAD_TARGET_NORMAL; + break; + } + return load_flags; } static cairo_scaled_font_t * -_ft_scaled_font_create (ft_unscaled_font_t *unscaled, - int load_flags, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm) +_cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled, + cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + int load_flags) { - cairo_ft_scaled_font_t *f = NULL; + cairo_ft_scaled_font_t *scaled_font = NULL; - f = malloc (sizeof(cairo_ft_scaled_font_t)); - if (f == NULL) + scaled_font = malloc (sizeof(cairo_ft_scaled_font_t)); + if (scaled_font == NULL) return NULL; - f->unscaled = unscaled; + _cairo_scaled_font_init (&scaled_font->base, + font_face, + font_matrix, ctm, options, + &cairo_ft_scaled_font_backend); + _cairo_unscaled_font_reference (&unscaled->base); - - f->load_flags = load_flags; + scaled_font->unscaled = unscaled; - _cairo_scaled_font_init (&f->base, font_matrix, ctm, &cairo_ft_scaled_font_backend); + if (options->hint_metrics != CAIRO_HINT_METRICS_OFF) + load_flags |= PRIVATE_FLAG_HINT_METRICS; - return (cairo_scaled_font_t *)f; + scaled_font->load_flags = load_flags; + + return &scaled_font->base; +} + +cairo_bool_t +_cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font) +{ + return scaled_font->backend == &cairo_ft_scaled_font_backend; } static cairo_status_t -_cairo_ft_scaled_font_create (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - cairo_scaled_font_t **font) +_cairo_ft_scaled_font_create_toy (cairo_toy_font_face_t *toy_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **font) { FcPattern *pattern, *resolved; - ft_unscaled_font_t *unscaled; - cairo_scaled_font_t *new_font; + cairo_ft_unscaled_font_t *unscaled; + cairo_scaled_font_t *new_font = NULL; FcResult result; int fcslant; int fcweight; cairo_matrix_t scale; - ft_font_transform_t sf; + cairo_ft_font_transform_t sf; + int load_flags; + unsigned char *family = (unsigned char*) toy_face->family; pattern = FcPatternCreate (); if (!pattern) return CAIRO_STATUS_NO_MEMORY; - switch (weight) + switch (toy_face->weight) { case CAIRO_FONT_WEIGHT_BOLD: fcweight = FC_WEIGHT_BOLD; @@ -762,7 +1502,7 @@ _cairo_ft_scaled_font_create (const char *family, break; } - switch (slant) + switch (toy_face->slant) { case CAIRO_FONT_SLANT_ITALIC: fcslant = FC_SLANT_ITALIC; @@ -776,7 +1516,7 @@ _cairo_ft_scaled_font_create (const char *family, break; } - if (!FcPatternAddString (pattern, FC_FAMILY, (unsigned char *) family)) + if (!FcPatternAddString (pattern, FC_FAMILY, family)) goto FREE_PATTERN; if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant)) goto FREE_PATTERN; @@ -789,41 +1529,42 @@ _cairo_ft_scaled_font_create (const char *family, FcPatternAddInteger (pattern, FC_PIXEL_SIZE, sf.y_scale); FcConfigSubstitute (NULL, pattern, FcMatchPattern); + cairo_ft_font_options_substitute (options, pattern); FcDefaultSubstitute (pattern); resolved = FcFontMatch (NULL, pattern, &result); if (!resolved) goto FREE_PATTERN; - unscaled = _ft_unscaled_font_get_for_pattern (resolved); + unscaled = _cairo_ft_unscaled_font_create_for_pattern (resolved); if (!unscaled) goto FREE_RESOLVED; - - new_font = _ft_scaled_font_create (unscaled, _get_load_flags (pattern), - font_matrix, ctm); + + load_flags = _get_pattern_load_flags (pattern); + + new_font = _cairo_ft_scaled_font_create (unscaled, + &toy_face->base, + font_matrix, ctm, + options, load_flags); + _cairo_unscaled_font_destroy (&unscaled->base); + FREE_RESOLVED: FcPatternDestroy (resolved); + + FREE_PATTERN: FcPatternDestroy (pattern); if (new_font) { *font = new_font; return CAIRO_STATUS_SUCCESS; } else { - return CAIRO_STATUS_NO_MEMORY; /* A guess */ + return CAIRO_STATUS_NO_MEMORY; } - - FREE_RESOLVED: - FcPatternDestroy (resolved); - - FREE_PATTERN: - FcPatternDestroy (pattern); - - return CAIRO_STATUS_NO_MEMORY; } static void -_cairo_ft_scaled_font_destroy (void *abstract_font) +_cairo_ft_scaled_font_fini (void *abstract_font) { cairo_ft_scaled_font_t *scaled_font = abstract_font; @@ -863,7 +1604,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); @@ -923,27 +1664,49 @@ _cairo_ft_scaled_font_font_extents (void *abstract_font, FT_Face face; FT_Size_Metrics *metrics; - face = _ft_unscaled_font_lock_face (scaled_font->unscaled); + face = _cairo_ft_unscaled_font_lock_face (scaled_font->unscaled); if (!face) return CAIRO_STATUS_NO_MEMORY; metrics = &face->size->metrics; - _ft_unscaled_font_set_scale (scaled_font->unscaled, &scaled_font->base.scale); - + _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, + &scaled_font->base.scale); + /* * Get to unscaled metrics so that the upper level can get back to * user space */ - extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / scaled_font->unscaled->y_scale; - extents->descent = DOUBLE_FROM_26_6(- metrics->descender) / scaled_font->unscaled->y_scale; - extents->height = DOUBLE_FROM_26_6(metrics->height) / scaled_font->unscaled->y_scale; - extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / scaled_font->unscaled->x_scale; + if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) { + double x_factor, y_factor; + + if (scaled_font->unscaled->x_scale == 0) + x_factor = 0; + else + x_factor = 1 / scaled_font->unscaled->x_scale; + + if (scaled_font->unscaled->y_scale == 0) + y_factor = 0; + else + y_factor = 1 / scaled_font->unscaled->y_scale; + + extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) * y_factor; + extents->descent = DOUBLE_FROM_26_6(- metrics->descender) * y_factor; + extents->height = DOUBLE_FROM_26_6(metrics->height) * y_factor; + extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) * x_factor; + } else { + double scale = face->units_per_EM; + + extents->ascent = face->ascender / scale; + extents->descent = - face->descender / scale; + extents->height = face->height / scale; + extents->max_x_advance = face->max_advance_width / scale; + } /* FIXME: this doesn't do vertical layout atm. */ extents->max_y_advance = 0.0; - _ft_unscaled_font_unlock_face (scaled_font->unscaled); + _cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled); return CAIRO_STATUS_SUCCESS; } @@ -1000,7 +1763,7 @@ _cairo_ft_scaled_font_glyph_extents (void *abstract_font, /* XXX: Need to add code here to check the font's FcPattern for FC_VERTICAL_LAYOUT and if set get vertBearingX/Y instead. This will require that - cairo_ft_scaled_font_create_for_ft_face accept an + cairo_ft_font_face_create_for_ft_face accept an FcPattern. */ glyph_min.x = glyphs[i].x + img->extents.x_bearing; glyph_min.y = glyphs[i].y + img->extents.y_bearing; @@ -1096,6 +1859,26 @@ _cairo_ft_scaled_font_glyph_bbox (void *abstract_font, return CAIRO_STATUS_SUCCESS; } +static cairo_format_t +_select_text_mask_format (cairo_bool_t have_a1_glyphs, + cairo_bool_t have_a8_glyphs, + cairo_bool_t have_argb32_glyphs) +{ + if (have_a8_glyphs) + return CAIRO_FORMAT_A8; + + if (have_a1_glyphs && have_argb32_glyphs) + return CAIRO_FORMAT_A8; + + if (have_a1_glyphs) + return CAIRO_FORMAT_A1; + + if (have_argb32_glyphs) + return CAIRO_FORMAT_ARGB32; + + /* when there are no glyphs to draw, just pick something */ + return CAIRO_FORMAT_A8; +} static cairo_status_t _cairo_ft_scaled_font_show_glyphs (void *abstract_font, @@ -1111,12 +1894,16 @@ _cairo_ft_scaled_font_show_glyphs (void *abstract_font, const cairo_glyph_t *glyphs, int num_glyphs) { - cairo_image_glyph_cache_entry_t *img; + cairo_image_glyph_cache_entry_t **entries; cairo_cache_t *cache; cairo_glyph_cache_key_t key; cairo_ft_scaled_font_t *scaled_font = abstract_font; cairo_surface_pattern_t glyph_pattern; - cairo_status_t status; + cairo_surface_t *mask; + cairo_surface_pattern_t mask_pattern; + cairo_format_t mask_format = CAIRO_FORMAT_A1; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_bool_t have_a1_glyphs, have_a8_glyphs, have_argb32_glyphs; int x, y; int i; @@ -1136,44 +1923,98 @@ _cairo_ft_scaled_font_show_glyphs (void *abstract_font, key.scale = scaled_font->base.scale; key.flags = scaled_font->load_flags; + entries = malloc (num_glyphs * sizeof (cairo_image_glyph_cache_entry_t)); + if (!entries) + goto CLEANUP_CACHE; + + have_a1_glyphs = FALSE; + have_a8_glyphs = FALSE; + have_argb32_glyphs = FALSE; + for (i = 0; i < num_glyphs; i++) { - img = NULL; + entries[i] = NULL; key.index = glyphs[i].index; - if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL) - != CAIRO_STATUS_SUCCESS - || img == NULL - || img->image == NULL) + if (_cairo_cache_lookup (cache, &key, (void **) &entries[i], NULL) != CAIRO_STATUS_SUCCESS) + continue; + + switch (entries[i]->image->format) { + case CAIRO_FORMAT_A1: + have_a1_glyphs = TRUE; + break; + case CAIRO_FORMAT_A8: + have_a8_glyphs = TRUE; + break; + case CAIRO_FORMAT_ARGB32: + have_argb32_glyphs = TRUE; + break; + default: + break; + } + } + + mask_format = _select_text_mask_format (have_a1_glyphs, have_a8_glyphs, have_argb32_glyphs); + + mask = cairo_image_surface_create (mask_format, width, height); + if (!mask) + goto CLEANUP_ENTRIES; + + status = _cairo_surface_fill_rectangle (mask, CAIRO_OPERATOR_SOURCE, + CAIRO_COLOR_TRANSPARENT, + 0, 0, width, height); + if (status) + goto CLEANUP_MASK; + + for (i = 0; i < num_glyphs; i++) + { + if (entries[i] == NULL + || entries[i]->image == NULL) continue; x = (int) floor (glyphs[i].x + 0.5); y = (int) floor (glyphs[i].y + 0.5); - _cairo_pattern_init_for_surface (&glyph_pattern, &(img->image->base)); + _cairo_pattern_init_for_surface (&glyph_pattern, &(entries[i]->image->base)); - status = _cairo_surface_composite (operator, pattern, + status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, pattern, &glyph_pattern.base, - surface, - x + img->size.x, - y + img->size.y, + mask, + x + entries[i]->size.x, + y + entries[i]->size.y, 0, 0, - x + img->size.x, - y + img->size.y, - (double) img->size.width, - (double) img->size.height); + x + entries[i]->size.x - dest_x, + y + entries[i]->size.y - dest_y, + entries[i]->size.width, + entries[i]->size.height); _cairo_pattern_fini (&glyph_pattern.base); - if (status) { - _cairo_unlock_global_image_glyph_cache (); - return status; - } - } + if (status) + goto CLEANUP_MASK; + } + _cairo_pattern_init_for_surface (&mask_pattern, mask); + + status = _cairo_surface_composite (operator, pattern, &mask_pattern.base, + surface, + source_x, source_y, + 0, 0, + dest_x, dest_y, + width, height); + + _cairo_pattern_fini (&mask_pattern.base); + + CLEANUP_MASK: + cairo_surface_destroy (mask); + + CLEANUP_ENTRIES: + free (entries); + + CLEANUP_CACHE: _cairo_unlock_global_image_glyph_cache (); - return CAIRO_STATUS_SUCCESS; + return status; } @@ -1240,7 +2081,8 @@ _conic_to (FT_Vector *control, FT_Vector *to, void *closure) } static int -_cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closure) +_cubic_to (FT_Vector *control1, FT_Vector *control2, + FT_Vector *to, void *closure) { cairo_path_fixed_t *path = closure; cairo_fixed_t x0, y0; @@ -1320,26 +2162,29 @@ _cairo_ft_scaled_font_glyph_path (void *abstract_font, } const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend = { - _cairo_ft_scaled_font_create, - _cairo_ft_scaled_font_destroy, + _cairo_ft_scaled_font_create_toy, + _cairo_ft_scaled_font_fini, _cairo_ft_scaled_font_font_extents, _cairo_ft_scaled_font_text_to_glyphs, _cairo_ft_scaled_font_glyph_extents, _cairo_ft_scaled_font_glyph_bbox, _cairo_ft_scaled_font_show_glyphs, _cairo_ft_scaled_font_glyph_path, - _cairo_ft_scaled_font_get_glyph_cache_key, + _cairo_ft_scaled_font_get_glyph_cache_key }; -/* ft_font_face_t */ +/* cairo_ft_font_face_t */ static void -_ft_font_face_destroy (void *abstract_face) +_cairo_ft_font_face_destroy (void *abstract_face) { - ft_font_face_t *font_face = abstract_face; + cairo_ft_font_face_t *font_face = abstract_face; - ft_font_face_t *tmp_face = NULL; - ft_font_face_t *last_face = NULL; + cairo_ft_font_face_t *tmp_face = NULL; + cairo_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 @@ -1357,7 +2202,8 @@ _ft_font_face_destroy (void *abstract_face) if (font_face->unscaled && font_face->unscaled->from_face && - font_face->unscaled->base.refcount > 1) { + font_face->unscaled->base.ref_count > 1) + { cairo_font_face_reference (&font_face->base); _cairo_unscaled_font_destroy (&font_face->unscaled->base); @@ -1368,12 +2214,15 @@ _ft_font_face_destroy (void *abstract_face) if (font_face->unscaled) { /* Remove face from linked list */ - for (tmp_face = font_face->unscaled->faces; tmp_face; tmp_face = tmp_face->next_face) { + for (tmp_face = font_face->unscaled->faces; + tmp_face; + tmp_face = tmp_face->next) + { if (tmp_face == font_face) { if (last_face) - last_face->next_face = tmp_face->next_face; + last_face->next = tmp_face->next; else - font_face->unscaled->faces = tmp_face->next_face; + font_face->unscaled->faces = tmp_face->next; } last_face = tmp_face; @@ -1385,43 +2234,61 @@ _ft_font_face_destroy (void *abstract_face) } static cairo_status_t -_ft_font_face_create_font (void *abstract_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - cairo_scaled_font_t **scaled_font) +_cairo_ft_font_face_scaled_font_create (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font) { - ft_font_face_t *font_face = abstract_face; + cairo_ft_font_face_t *font_face = abstract_face; + int load_flags; - *scaled_font = _ft_scaled_font_create (font_face->unscaled, - font_face->load_flags, - font_matrix, ctm); + /* The handling of font options is different depending on how the + * font face was created. When the user creates a font face with + * cairo_ft_font_face_create_for_ft_face(), then the load flags + * passed in augment the load flags for the options. But for + * cairo_ft_font_face_create_for_pattern(), the load flags are + * derived from a pattern where the user has called + * cairo_ft_font_options_substitute(), so *just* use those load + * flags and ignore the options. + */ + if (font_face->unscaled->from_face) + load_flags = _get_options_load_flags (options) | font_face->load_flags; + else + load_flags = font_face->load_flags; + + *scaled_font = _cairo_ft_scaled_font_create (font_face->unscaled, + &font_face->base, + font_matrix, ctm, + options, load_flags); if (*scaled_font) return CAIRO_STATUS_SUCCESS; else return CAIRO_STATUS_NO_MEMORY; } -static const cairo_font_face_backend_t _ft_font_face_backend = { - _ft_font_face_destroy, - _ft_font_face_create_font, +static const cairo_font_face_backend_t _cairo_ft_font_face_backend = { + _cairo_ft_font_face_destroy, + _cairo_ft_font_face_scaled_font_create }; static cairo_font_face_t * -_ft_font_face_create (ft_unscaled_font_t *unscaled, - int load_flags) +_cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled, + int load_flags) { - ft_font_face_t *font_face; + cairo_ft_font_face_t *font_face; /* Looked for an existing matching font face */ - for (font_face = unscaled->faces; font_face; font_face = font_face->next_face) { - if (font_face->load_flags == load_flags) { - cairo_font_face_reference (&font_face->base); - return &font_face->base; - } + for (font_face = unscaled->faces; + font_face; + font_face = font_face->next) + { + if (font_face->load_flags == load_flags) + return cairo_font_face_reference (&font_face->base); } /* No match found, create a new one */ - font_face = malloc (sizeof (ft_font_face_t)); + font_face = malloc (sizeof (cairo_ft_font_face_t)); if (!font_face) return NULL; @@ -1430,16 +2297,103 @@ _ft_font_face_create (ft_unscaled_font_t *unscaled, font_face->load_flags = load_flags; - font_face->next_face = unscaled->faces; + font_face->next = unscaled->faces; unscaled->faces = font_face; - _cairo_font_face_init (&font_face->base, &_ft_font_face_backend); + _cairo_font_face_init (&font_face->base, &_cairo_ft_font_face_backend); return &font_face->base; } /* implement the platform-specific interface */ +/** + * cairo_ft_font_options_substitute: + * @options: a #cairo_font_options_t object + * @pattern: an existing #FcPattern + * + * Add options to a #FcPattern based on a #cairo_font_options_t font + * options object. Options that are already in the pattern, are not overriden, + * so you should call this function after calling FcConfigSubstitute() (the + * user's settings should override options based on the surface type), but + * before calling FcDefaultSubstitute(). + **/ +void +cairo_ft_font_options_substitute (const cairo_font_options_t *options, + FcPattern *pattern) +{ + FcValue v; + + if (options->antialias != CAIRO_ANTIALIAS_DEFAULT) + { + if (FcPatternGet (pattern, FC_ANTIALIAS, 0, &v) == FcResultNoMatch) + { + FcPatternAddBool (pattern, FC_ANTIALIAS, options->antialias != CAIRO_ANTIALIAS_NONE); + } + } + + if (options->antialias != CAIRO_ANTIALIAS_DEFAULT) + { + if (FcPatternGet (pattern, FC_RGBA, 0, &v) == FcResultNoMatch) + { + int rgba; + + if (options->antialias == CAIRO_ANTIALIAS_SUBPIXEL) { + switch (options->subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_DEFAULT: + case CAIRO_SUBPIXEL_ORDER_RGB: + default: + rgba = FC_RGBA_RGB; + break; + case CAIRO_SUBPIXEL_ORDER_BGR: + rgba = FC_RGBA_BGR; + break; + case CAIRO_SUBPIXEL_ORDER_VRGB: + rgba = FC_RGBA_VRGB; + break; + case CAIRO_SUBPIXEL_ORDER_VBGR: + rgba = FC_RGBA_VBGR; + break; + } + } else { + rgba = FC_RGBA_NONE; + } + + FcPatternAddInteger (pattern, FC_RGBA, rgba); + } + } + + if (options->hint_style != CAIRO_HINT_STYLE_DEFAULT) + { + if (FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch) + { + FcPatternAddBool (pattern, FC_HINTING, options->hint_style != CAIRO_HINT_STYLE_NONE); + } + +#ifdef FC_HINT_STYLE + if (FcPatternGet (pattern, FC_HINT_STYLE, 0, &v) == FcResultNoMatch) + { + int hint_style; + + switch (options->hint_style) { + case CAIRO_HINT_STYLE_SLIGHT: + hint_style = FC_HINT_SLIGHT; + break; + case CAIRO_HINT_STYLE_MEDIUM: + hint_style = FC_HINT_MEDIUM; + break; + case CAIRO_HINT_STYLE_FULL: + default: + hint_style = FC_HINT_FULL; + break; + } + + FcPatternAddInteger (pattern, FC_HINT_STYLE, hint_style); + } +#endif + } +} + /** * cairo_ft_font_face_create_for_pattern: * @pattern: A fully resolved fontconfig @@ -1456,37 +2410,54 @@ _ft_font_face_create (ft_unscaled_font_t *unscaled, * returned from cairo_font_create() is also for the FreeType backend * and can be used with functions such as cairo_ft_font_lock_face(). * + * Font rendering options are representated both here and when you + * call cairo_scaled_font_create(). Font options that have a representation + * in a #FcPattern must be passed in here; to modify #FcPattern + * appropriately to reflect the options in a #cairo_font_options_t, call + * cairo_ft_font_options_substitute(). + * * Return value: a newly created #cairo_font_face_t. Free with * cairo_font_face_destroy() when you are done using it. **/ cairo_font_face_t * cairo_ft_font_face_create_for_pattern (FcPattern *pattern) { - ft_unscaled_font_t *unscaled; + cairo_ft_unscaled_font_t *unscaled; cairo_font_face_t *font_face; - unscaled = _ft_unscaled_font_get_for_pattern (pattern); - if (unscaled == NULL) - return NULL; + unscaled = _cairo_ft_unscaled_font_create_for_pattern (pattern); + if (unscaled == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *)&_cairo_font_face_nil; + } - font_face = _ft_font_face_create (unscaled, _get_load_flags (pattern)); + font_face = _cairo_ft_font_face_create (unscaled, + _get_pattern_load_flags (pattern)); _cairo_unscaled_font_destroy (&unscaled->base); - return font_face; + if (font_face) + return font_face; + else { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *)&_cairo_font_face_nil; + } } /** - * 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 + * be kept around until the face's ref_count drops to * zero and it is freed. Since the face may be referenced * internally to Cairo, the best way to determine when it * is safe to free the face is to pass a * #cairo_destroy_func_t to cairo_font_face_set_user_data() - * @load_flags: The flags to pass to FT_Load_Glyph when loading - * glyphs from the font. These flags control aspects of - * rendering such as hinting and antialiasing. See the FreeType - * docs for full information. + * @load_flags: flags to pass to FT_Load_Glyph when loading + * glyphs from the font. These flags are OR'ed together with + * the flags derived from the #cairo_font_options_t passed + * to cairo_scaled_font_create(), so only a few values such + * as %FT_LOAD_VERTICAL_LAYOUT, and %FT_LOAD_FORCE_AUTOHINT + * are useful. You should not pass any of the flags affecting + * the load target, such as %FT_LOAD_TARGET_LIGHT. * * Creates a new font face for the FreeType font backend from a pre-opened * FreeType face. This font can then be used with @@ -1501,17 +2472,24 @@ cairo_font_face_t * cairo_ft_font_face_create_for_ft_face (FT_Face face, int load_flags) { - ft_unscaled_font_t *unscaled; + cairo_ft_unscaled_font_t *unscaled; cairo_font_face_t *font_face; - unscaled = _ft_unscaled_font_create_from_face (face); - if (unscaled == NULL) - return NULL; + unscaled = _cairo_ft_unscaled_font_create_from_face (face); + if (unscaled == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *)&_cairo_font_face_nil; + } - font_face = _ft_font_face_create (unscaled, load_flags); + font_face = _cairo_ft_font_face_create (unscaled, load_flags); _cairo_unscaled_font_destroy (&unscaled->base); - return font_face; + if (font_face) { + return font_face; + } else { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *)&_cairo_font_face_nil; + } } /** @@ -1539,7 +2517,9 @@ cairo_ft_font_face_create_for_ft_face (FT_Face face, * implemented, so this function cannot be currently safely used in a * threaded application.) - * Return value: The #FT_Face object for @font, scaled appropriately. + * Return value: The #FT_Face object for @font, scaled appropriately, + * or %NULL if @scaled_font is in an error state (see + * cairo_scaled_font_status()) or there is insufficient memory. **/ FT_Face cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font) @@ -1547,11 +2527,17 @@ cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font) cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font; FT_Face face; - face = _ft_unscaled_font_lock_face (scaled_font->unscaled); - if (!face) + if (scaled_font->base.status) return NULL; + + face = _cairo_ft_unscaled_font_lock_face (scaled_font->unscaled); + if (face == NULL) { + _cairo_scaled_font_set_error (&scaled_font->base, CAIRO_STATUS_NO_MEMORY); + return NULL; + } - _ft_unscaled_font_set_scale (scaled_font->unscaled, &scaled_font->base.scale); + _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, + &scaled_font->base.scale); return face; } @@ -1571,7 +2557,10 @@ cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *abstract_font) { cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font; - _ft_unscaled_font_unlock_face (scaled_font->unscaled); + if (scaled_font->base.status) + return; + + _cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled); } /* We expose our unscaled font implementation internally for the the @@ -1586,17 +2575,8 @@ _cairo_ft_scaled_font_get_unscaled_font (cairo_scaled_font_t *abstract_font) return &scaled_font->unscaled->base; } -/* This differs from _cairo_ft_scaled_font_lock_face in that it doesn't - * set the scale on the face, but just returns it at the last scale. - */ -FT_Face -_cairo_ft_unscaled_font_lock_face (cairo_unscaled_font_t *unscaled_font) -{ - return _ft_unscaled_font_lock_face ((ft_unscaled_font_t *)unscaled_font); -} - void -_cairo_ft_unscaled_font_unlock_face (cairo_unscaled_font_t *unscaled_font) +_cairo_ft_font_reset_static_data (void) { - _ft_unscaled_font_unlock_face ((ft_unscaled_font_t *)unscaled_font); + _cairo_ft_unscaled_font_map_destroy (); } diff --git a/gfx/cairo/cairo/src/cairo-ft-private.h b/gfx/cairo/cairo/src/cairo-ft-private.h index b2176352eb67..b3931bec2c16 100644 --- a/gfx/cairo/cairo/src/cairo-ft-private.h +++ b/gfx/cairo/cairo/src/cairo-ft-private.h @@ -40,10 +40,18 @@ #include #include -#ifdef CAIRO_HAS_FT_FONT +#if CAIRO_HAS_FT_FONT CAIRO_BEGIN_DECLS +typedef struct _cairo_ft_unscaled_font cairo_ft_unscaled_font_t; + +cairo_private cairo_bool_t +_cairo_unscaled_font_is_ft (cairo_unscaled_font_t *unscaled_font); + +cairo_private cairo_bool_t +_cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font); + /* These functions are needed by the PDF backend, which needs to keep track of the * the different fonts-on-disk used by a document, so it can embed them */ @@ -51,10 +59,10 @@ cairo_private cairo_unscaled_font_t * _cairo_ft_scaled_font_get_unscaled_font (cairo_scaled_font_t *scaled_font); cairo_private FT_Face -_cairo_ft_unscaled_font_lock_face (cairo_unscaled_font_t *unscaled_font); +_cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled); cairo_private void -_cairo_ft_unscaled_font_unlock_face (cairo_unscaled_font_t *unscaled_font); +_cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled); CAIRO_END_DECLS diff --git a/gfx/cairo/cairo/src/cairo-ft.h b/gfx/cairo/cairo/src/cairo-ft.h index fee6bf25b50a..3bdbae1bdcc2 100644 --- a/gfx/cairo/cairo/src/cairo-ft.h +++ b/gfx/cairo/cairo/src/cairo-ft.h @@ -39,7 +39,7 @@ #include -#ifdef CAIRO_HAS_FT_FONT +#if CAIRO_HAS_FT_FONT /* Fontconfig/Freetype platform-specific font interface */ @@ -52,6 +52,10 @@ CAIRO_BEGIN_DECLS cairo_font_face_t * cairo_ft_font_face_create_for_pattern (FcPattern *pattern); +void +cairo_ft_font_options_substitute (const cairo_font_options_t *options, + FcPattern *pattern); + cairo_font_face_t * cairo_ft_font_face_create_for_ft_face (FT_Face face, int load_flags); diff --git a/gfx/cairo/cairo/src/cairo-glitz-surface.c b/gfx/cairo/cairo/src/cairo-glitz-surface.c index 673b972c396d..2684f9f0020c 100644 --- a/gfx/cairo/cairo/src/cairo-glitz-surface.c +++ b/gfx/cairo/cairo/src/cairo-glitz-surface.c @@ -52,27 +52,26 @@ _cairo_glitz_surface_finish (void *abstract_surface) } static glitz_format_name_t -_glitz_format (cairo_format_t format) +_glitz_format_from_content (cairo_content_t content) { - switch (format) { - default: - case CAIRO_FORMAT_ARGB32: - return GLITZ_STANDARD_ARGB32; - case CAIRO_FORMAT_RGB24: + switch (content) { + case CAIRO_CONTENT_COLOR: return GLITZ_STANDARD_RGB24; - case CAIRO_FORMAT_A8: + case CAIRO_CONTENT_ALPHA: return GLITZ_STANDARD_A8; - case CAIRO_FORMAT_A1: - return GLITZ_STANDARD_A1; + case CAIRO_CONTENT_COLOR_ALPHA: + return GLITZ_STANDARD_ARGB32; } + + ASSERT_NOT_REACHED; + return GLITZ_STANDARD_ARGB32; } static cairo_surface_t * _cairo_glitz_surface_create_similar (void *abstract_src, - cairo_format_t format, - int draw, - int width, - int height) + cairo_content_t content, + int width, + int height) { cairo_glitz_surface_t *src = abstract_src; cairo_surface_t *crsurface; @@ -82,13 +81,18 @@ _cairo_glitz_surface_create_similar (void *abstract_src, drawable = glitz_surface_get_drawable (src->surface); - gformat = glitz_find_standard_format (drawable, _glitz_format (format)); - if (!gformat) - return NULL; + gformat = glitz_find_standard_format (drawable, + _glitz_format_from_content (content)); + if (!gformat) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } surface = glitz_surface_create (drawable, gformat, width, height, 0, NULL); - if (!surface) - return NULL; + if (surface == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } crsurface = cairo_glitz_surface_create (surface); @@ -206,8 +210,7 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, &format, width, height, pf.bytes_per_line); - - if (!image) + if (image->base.status) { free (pixels); return CAIRO_STATUS_NO_MEMORY; @@ -215,9 +218,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; @@ -344,22 +344,25 @@ _cairo_glitz_surface_clone_similar (void *abstract_surface, cairo_glitz_surface_t *surface = abstract_surface; cairo_glitz_surface_t *clone; + if (surface->base.status) + return surface->base.status; + if (src->backend == surface->base.backend) { - *clone_out = src; - cairo_surface_reference (src); + *clone_out = cairo_surface_reference (src); return CAIRO_STATUS_SUCCESS; } else if (_cairo_surface_is_image (src)) { cairo_image_surface_t *image_src = (cairo_image_surface_t *) src; + cairo_content_t content = _cairo_content_from_format (image_src->format); clone = (cairo_glitz_surface_t *) - _cairo_glitz_surface_create_similar (surface, image_src->format, 0, + _cairo_glitz_surface_create_similar (surface, content, image_src->width, image_src->height); - if (!clone) + if (clone->base.status) return CAIRO_STATUS_NO_MEMORY; _cairo_glitz_surface_set_image (clone, image_src, 0, 0); @@ -444,73 +447,18 @@ _glitz_operator (cairo_operator_t op) return CAIRO_OPERATOR_XOR; } +#define CAIRO_GLITZ_FEATURE_OK(surface, name) \ + (glitz_drawable_get_features (glitz_surface_get_drawable (surface)) & \ + (GLITZ_FEATURE_ ## name ## _MASK)) + static glitz_status_t _glitz_ensure_target (glitz_surface_t *surface) { - glitz_drawable_t *drawable; + if (glitz_surface_get_attached_drawable (surface) || + CAIRO_GLITZ_FEATURE_OK (surface, FRAMEBUFFER_OBJECT)) + return CAIRO_STATUS_SUCCESS; - drawable = glitz_surface_get_attached_drawable (surface); - if (!drawable) { - glitz_drawable_format_t *dformat; - glitz_drawable_format_t templ; - glitz_format_t *format; - glitz_drawable_t *pbuffer; - unsigned long mask; - int i; - - format = glitz_surface_get_format (surface); - if (format->type != GLITZ_FORMAT_TYPE_COLOR) - return CAIRO_INT_STATUS_UNSUPPORTED; - - drawable = glitz_surface_get_drawable (surface); - dformat = glitz_drawable_get_format (drawable); - - templ.types.pbuffer = 1; - mask = GLITZ_FORMAT_PBUFFER_MASK; - - templ.samples = dformat->samples; - mask |= GLITZ_FORMAT_SAMPLES_MASK; - - i = 0; - do { - dformat = glitz_find_similar_drawable_format (drawable, - mask, &templ, i++); - - if (dformat) { - int sufficient = 1; - - if (format->color.red_size) { - if (dformat->color.red_size < format->color.red_size) - sufficient = 0; - } - if (format->color.alpha_size) { - if (dformat->color.alpha_size < format->color.alpha_size) - sufficient = 0; - } - - if (sufficient) - break; - } - } while (dformat); - - if (!dformat) - return CAIRO_INT_STATUS_UNSUPPORTED; - - pbuffer = - glitz_create_pbuffer_drawable (drawable, dformat, - glitz_surface_get_width (surface), - glitz_surface_get_height (surface)); - if (!pbuffer) - return CAIRO_INT_STATUS_UNSUPPORTED; - - glitz_surface_attach (surface, pbuffer, - GLITZ_DRAWABLE_BUFFER_FRONT_COLOR, - 0, 0); - - glitz_drawable_destroy (pbuffer); - } - - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_UNSUPPORTED; } typedef struct _cairo_glitz_surface_attributes { @@ -540,13 +488,26 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern, switch (pattern->type) { case CAIRO_PATTERN_LINEAR: case CAIRO_PATTERN_RADIAL: { - cairo_gradient_pattern_t *gradient = + cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern; - glitz_drawable_t *drawable; - glitz_fixed16_16_t *params; - int n_params; - int i; - unsigned short alpha; + char *data; + glitz_fixed16_16_t *params; + int n_params; + unsigned int *pixels; + int i; + unsigned char alpha; + glitz_buffer_t *buffer; + static glitz_pixel_format_t format = { + { + 32, + 0xff000000, + 0x00ff0000, + 0x0000ff00, + 0x000000ff + }, + 0, 0, 0, + GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP + }; /* XXX: the current color gradient acceleration provided by glitz is * experimental, it's been proven inappropriate in a number of ways, @@ -569,22 +530,20 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern, break; } - drawable = glitz_surface_get_drawable (dst->surface); - if (!(glitz_drawable_get_features (drawable) & - GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK)) + if (!CAIRO_GLITZ_FEATURE_OK (dst->surface, FRAGMENT_PROGRAM)) break; - + if (pattern->filter != CAIRO_FILTER_BILINEAR && pattern->filter != CAIRO_FILTER_GOOD && pattern->filter != CAIRO_FILTER_BEST) break; - alpha = (gradient->stops[0].color.alpha) * 0xffff; + alpha = gradient->stops[0].color.alpha * 0xff; for (i = 1; i < gradient->n_stops; i++) { - unsigned short a; + unsigned char a; - a = (gradient->stops[i].color.alpha) * 0xffff; + a = gradient->stops[i].color.alpha * 0xff; if (a != alpha) break; } @@ -596,35 +555,51 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern, n_params = gradient->n_stops * 3 + 4; - params = malloc (sizeof (glitz_fixed16_16_t) * n_params); - if (!params) + data = malloc (sizeof (glitz_fixed16_16_t) * n_params + + sizeof (unsigned int) * gradient->n_stops); + if (!data) return CAIRO_STATUS_NO_MEMORY; - src = (cairo_glitz_surface_t *) - _cairo_surface_create_similar_scratch (&dst->base, - CAIRO_FORMAT_ARGB32, 0, - gradient->n_stops, 1); - if (!src) + params = (glitz_fixed16_16_t *) data; + pixels = (unsigned int *) + (data + sizeof (glitz_fixed16_16_t) * n_params); + + buffer = glitz_buffer_create_for_data (pixels); + if (!buffer) { - free (params); + free (data); return CAIRO_STATUS_NO_MEMORY; } - for (i = 0; i < gradient->n_stops; i++) { - glitz_color_t color; - - color.red = gradient->stops[i].color.red * alpha; - color.green = gradient->stops[i].color.green * alpha; - color.blue = gradient->stops[i].color.blue * alpha; - color.alpha = alpha; - - glitz_set_rectangle (src->surface, &color, i, 0, 1, 1); + src = (cairo_glitz_surface_t *) + _cairo_surface_create_similar_scratch (&dst->base, + CAIRO_CONTENT_COLOR_ALPHA, + gradient->n_stops, 1); + if (src->base.status) + { + glitz_buffer_destroy (buffer); + free (data); + return CAIRO_STATUS_NO_MEMORY; + } + for (i = 0; i < gradient->n_stops; i++) + { + pixels[i] = + (((int) alpha) << 24) | + (((int) gradient->stops[i].color.red * alpha) << 16) | + (((int) gradient->stops[i].color.green * alpha) << 8) | + (((int) gradient->stops[i].color.blue * alpha)); + params[4 + 3 * i] = gradient->stops[i].offset; params[5 + 3 * i] = i << 16; params[6 + 3 * i] = 0; } + glitz_set_pixels (src->surface, 0, 0, gradient->n_stops, 1, + &format, buffer); + + glitz_buffer_destroy (buffer); + if (pattern->type == CAIRO_PATTERN_LINEAR) { cairo_linear_pattern_t *grad = (cairo_linear_pattern_t *) pattern; @@ -718,13 +693,12 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern, } static void -_cairo_glitz_pattern_release_surface (cairo_glitz_surface_t *dst, +_cairo_glitz_pattern_release_surface (cairo_pattern_t *pattern, cairo_glitz_surface_t *surface, cairo_glitz_surface_attributes_t *attr) { if (attr->acquired) - _cairo_pattern_release_surface (&dst->base, &surface->base, - &attr->base); + _cairo_pattern_release_surface (pattern, &surface->base, &attr->base); else cairo_surface_destroy (&surface->base); } @@ -790,13 +764,12 @@ _cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src, width, height, mask_out, mattr); + if (status) + _cairo_glitz_pattern_release_surface (&tmp.base, *src_out, sattr); + _cairo_pattern_fini (&tmp.base); - if (status) - { - _cairo_glitz_pattern_release_surface (dst, *src_out, sattr); - return status; - } + return status; } else { @@ -870,7 +843,7 @@ _cairo_glitz_surface_composite (cairo_operator_t op, if (mask_attr.n_params) free (mask_attr.params); - _cairo_glitz_pattern_release_surface (dst, mask, &mask_attr); + _cairo_glitz_pattern_release_surface (mask_pattern, mask, &mask_attr); } else { @@ -888,7 +861,7 @@ _cairo_glitz_surface_composite (cairo_operator_t op, if (src_attr.n_params) free (src_attr.params); - _cairo_glitz_pattern_release_surface (dst, src, &src_attr); + _cairo_glitz_pattern_release_surface (src_pattern, src, &src_attr); if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -914,10 +887,6 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, glitz_color.blue = color->blue_short; glitz_color.alpha = color->alpha_short; - if (glitz_surface_get_width (dst->surface) != 1 || - glitz_surface_get_height (dst->surface) != 1) - _glitz_ensure_target (dst->surface); - glitz_set_rectangles (dst->surface, &glitz_color, (glitz_rectangle_t *) rects, n_rects); } @@ -933,9 +902,10 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, src = (cairo_glitz_surface_t *) _cairo_surface_create_similar_solid (&dst->base, - CAIRO_FORMAT_ARGB32, 1, 1, + CAIRO_CONTENT_COLOR_ALPHA, + 1, 1, (cairo_color_t *) color); - if (!src) + if (src->base.status) return CAIRO_STATUS_NO_MEMORY; glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT); @@ -966,6 +936,7 @@ static cairo_int_status_t _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, cairo_pattern_t *pattern, void *abstract_dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, @@ -975,6 +946,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, cairo_trapezoid_t *traps, int n_traps) { + cairo_pattern_union_t tmp_src_pattern; + cairo_pattern_t *src_pattern; cairo_glitz_surface_attributes_t attributes; cairo_glitz_surface_t *dst = abstract_dst; cairo_glitz_surface_t *src; @@ -984,6 +957,9 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, cairo_int_status_t status; unsigned short alpha; + if (dst->base.status) + return dst->base.status; + if (op == CAIRO_OPERATOR_SATURATE) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -992,16 +968,13 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, if (pattern->type == CAIRO_PATTERN_SURFACE) { - cairo_pattern_union_t tmp; - - _cairo_pattern_init_copy (&tmp.base, pattern); + _cairo_pattern_init_copy (&tmp_src_pattern.base, pattern); - status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst, + status = _cairo_glitz_pattern_acquire_surface (&tmp_src_pattern.base, dst, src_x, src_y, width, height, &src, &attributes); - - _cairo_pattern_fini (&tmp.base); + src_pattern = &tmp_src_pattern.base; } else { @@ -1009,6 +982,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, src_x, src_y, width, height, &src, &attributes); + src_pattern = pattern; } alpha = 0xffff; @@ -1035,12 +1009,15 @@ _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_CONTENT_ALPHA, 2, 1); - if (!mask) + if (mask->base.status) { - _cairo_glitz_pattern_release_surface (dst, src, &attributes); - return CAIRO_INT_STATUS_UNSUPPORTED; + _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes); + if (src_pattern == &tmp_src_pattern.base) + _cairo_pattern_fini (&tmp_src_pattern.base); + + return CAIRO_STATUS_NO_MEMORY; } color.red = color.green = color.blue = color.alpha = 0xffff; @@ -1063,8 +1040,10 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, data = realloc (data, data_size); if (!data) { - _cairo_glitz_pattern_release_surface (dst, src, + _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes); + if (src_pattern == &tmp_src_pattern.base) + _cairo_pattern_fini (&tmp_src_pattern.base); return CAIRO_STATUS_NO_MEMORY; } @@ -1074,8 +1053,10 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, buffer = glitz_buffer_create_for_data (data); if (!buffer) { free (data); - _cairo_glitz_pattern_release_surface (dst, src, + _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes); + if (src_pattern == &tmp_src_pattern.base) + _cairo_pattern_fini (&tmp_src_pattern.base); return CAIRO_STATUS_NO_MEMORY; } } @@ -1109,7 +1090,9 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, data = malloc (stride * height); if (!data) { - _cairo_glitz_pattern_release_surface (dst, src, &attributes); + _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes); + if (src_pattern == &tmp_src_pattern.base) + _cairo_pattern_fini (&tmp_src_pattern.base); return CAIRO_STATUS_NO_MEMORY; } @@ -1123,7 +1106,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, CAIRO_FORMAT_A8, width, height, -stride); - if (!image) + if (image->base.status) { cairo_surface_destroy (&src->base); free (data); @@ -1135,11 +1118,11 @@ _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_CONTENT_ALPHA, width, height); - if (!mask) + if (mask->base.status) { - _cairo_glitz_pattern_release_surface (dst, src, &attributes); + _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes); free (data); cairo_surface_destroy (&image->base); return CAIRO_STATUS_NO_MEMORY; @@ -1172,7 +1155,10 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, free (data); - _cairo_glitz_pattern_release_surface (dst, src, &attributes); + _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes); + if (src_pattern == &tmp_src_pattern.base) + _cairo_pattern_fini (&tmp_src_pattern.base); + if (mask) cairo_surface_destroy (&mask->base); @@ -1289,10 +1275,13 @@ _cairo_glitz_area_move_in (cairo_glitz_area_t *area, static void _cairo_glitz_area_move_out (cairo_glitz_area_t *area) { - (*area->root->funcs->move_out) (area, area->closure); + if (area->root) + { + (*area->root->funcs->move_out) (area, area->closure); - area->closure = NULL; - area->state = CAIRO_GLITZ_AREA_AVAILABLE; + area->closure = NULL; + area->state = CAIRO_GLITZ_AREA_AVAILABLE; + } } static cairo_glitz_area_t * @@ -1328,7 +1317,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 +1379,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 +1394,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,10 +1441,11 @@ _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))) - return CAIRO_STATUS_SUCCESS; + status = _cairo_glitz_area_find (area->area[0], + width, height, + kick_out, closure); + if (status == CAIRO_STATUS_SUCCESS) + return CAIRO_STATUS_SUCCESS; } } break; case CAIRO_GLITZ_AREA_DIVIDED: { @@ -1466,9 +1459,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 +1482,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 +1495,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; @@ -1560,7 +1557,7 @@ typedef struct _cairo_glitz_glyph_cache { typedef struct { cairo_glyph_cache_key_t key; - int refcount; + int ref_count; cairo_glyph_size_t size; cairo_glitz_area_t *area; cairo_bool_t locked; @@ -1607,20 +1604,48 @@ 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) { cairo_glitz_glyph_cache_entry_t *entry; cairo_glyph_cache_key_t *key = abstract_key; - + + cairo_status_t status; + cairo_cache_t *im_cache; + cairo_image_glyph_cache_entry_t *im; + + unsigned long entry_memory = 0; + entry = malloc (sizeof (cairo_glitz_glyph_cache_entry_t)); if (!entry) return CAIRO_STATUS_NO_MEMORY; - entry->refcount = 1; + _cairo_lock_global_image_glyph_cache (); + + im_cache = _cairo_get_global_image_glyph_cache (); + if (im_cache == NULL) { + _cairo_unlock_global_image_glyph_cache (); + free (entry); + return CAIRO_STATUS_NO_MEMORY; + } + + status = _cairo_cache_lookup (im_cache, key, (void **) (&im), NULL); + if (status != CAIRO_STATUS_SUCCESS || im == NULL) { + _cairo_unlock_global_image_glyph_cache (); + free (entry); + return CAIRO_STATUS_NO_MEMORY; + } + + if (im->image) + entry_memory = im->image->width * im->image->stride; + + _cairo_unlock_global_image_glyph_cache (); + + entry->ref_count = 1; entry->key = *key; - entry->area = NULL; + entry->key.base.memory = entry_memory; + entry->area = NULL; entry->locked = FALSE; _cairo_unscaled_font_reference (entry->key.unscaled); @@ -1631,13 +1656,13 @@ _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; - entry->refcount--; - if (entry->refcount) + entry->ref_count--; + if (entry->ref_count) return; if (entry->area) @@ -1653,11 +1678,11 @@ _cairo_glitz_glyph_cache_entry_reference (void *abstract_entry) { cairo_glitz_glyph_cache_entry_t *entry = abstract_entry; - entry->refcount++; + entry->ref_count++; } 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 +1694,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; @@ -1706,7 +1731,7 @@ _cairo_glitz_get_glyph_cache (cairo_glitz_surface_t *surface) GLYPH_CACHE_TEXTURE_SIZE, GLYPH_CACHE_TEXTURE_SIZE, 0, NULL); - if (!cache->surface) + if (cache->surface == NULL) { free (cache); return NULL; @@ -1757,7 +1782,8 @@ _cairo_glitz_cache_glyph (cairo_glitz_glyph_cache_t *cache, entry->size.height > GLYPH_CACHE_MAX_HEIGHT) return CAIRO_STATUS_SUCCESS; - if (!image_entry->image) + if ((entry->size.width == 0 && entry->size.height == 0) || + !image_entry->image) { entry->area = &_empty_area; return CAIRO_STATUS_SUCCESS; @@ -1910,7 +1936,9 @@ _cairo_glitz_surface_show_glyphs (cairo_scaled_font_t *scaled_font, goto UNLOCK; } - _cairo_scaled_font_get_glyph_cache_key (scaled_font, &key); + status = _cairo_scaled_font_get_glyph_cache_key (scaled_font, &key); + if (status) + goto UNLOCK; for (i = 0; i < num_glyphs; i++) { @@ -2088,7 +2116,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); @@ -2100,7 +2128,7 @@ UNLOCK: if (attributes.n_params) free (attributes.params); - _cairo_glitz_pattern_release_surface (dst, src, &attributes); + _cairo_glitz_pattern_release_surface (pattern, src, &attributes); if (status) return status; @@ -2125,8 +2153,13 @@ 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 + _cairo_glitz_surface_show_glyphs, + NULL, /* fill_path */ + NULL, /* get_font_options */ + NULL, /* flush */ + NULL /* mark_dirty_rectangle */ }; cairo_surface_t * @@ -2134,12 +2167,14 @@ cairo_glitz_surface_create (glitz_surface_t *surface) { cairo_glitz_surface_t *crsurface; - if (!surface) - return NULL; + if (surface == NULL) + return (cairo_surface_t*) &_cairo_surface_nil; crsurface = malloc (sizeof (cairo_glitz_surface_t)); - if (crsurface == NULL) - return NULL; + if (crsurface == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } _cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend); diff --git a/gfx/cairo/cairo/src/cairo-glitz.h b/gfx/cairo/cairo/src/cairo-glitz.h index 02166f1b2932..f5b4f2815074 100644 --- a/gfx/cairo/cairo/src/cairo-glitz.h +++ b/gfx/cairo/cairo/src/cairo-glitz.h @@ -39,7 +39,7 @@ #include -#ifdef CAIRO_HAS_GLITZ_SURFACE +#if CAIRO_HAS_GLITZ_SURFACE #include diff --git a/gfx/cairo/cairo/src/cairo-gstate-private.h b/gfx/cairo/cairo/src/cairo-gstate-private.h index ad127f0640ab..489afdba4c99 100644 --- a/gfx/cairo/cairo/src/cairo-gstate-private.h +++ b/gfx/cairo/cairo/src/cairo-gstate-private.h @@ -36,10 +36,13 @@ #ifndef CAIRO_GSTATE_PRIVATE_H #define CAIRO_GSTATE_PRIVATE_H +#include "cairo-clip-private.h" + struct _cairo_gstate { cairo_operator_t operator; double tolerance; + cairo_antialias_t antialias; /* stroke style */ double line_width; @@ -52,30 +55,24 @@ struct _cairo_gstate { double *dash; int num_dashes; double dash_offset; - double max_dash_length; - double fraction_dash_lit; - - 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_font_options_t font_options; + + cairo_clip_t clip; cairo_matrix_t ctm; cairo_matrix_t ctm_inverse; + cairo_matrix_t source_ctm_inverse; /* At the time ->source was set */ cairo_pen_t pen_regular; + cairo_surface_t *target; + + cairo_pattern_t *source; + struct _cairo_gstate *next; }; diff --git a/gfx/cairo/cairo/src/cairo-gstate.c b/gfx/cairo/cairo/src/cairo-gstate.c index c99c3f811af1..83b48d133010 100644 --- a/gfx/cairo/cairo/src/cairo-gstate.c +++ b/gfx/cairo/cairo/src/cairo-gstate.c @@ -39,27 +39,31 @@ #include "cairoint.h" +#include "cairo-clip-private.h" #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, - cairo_pattern_t *src, - cairo_operator_t operator, - cairo_surface_t *dst, - cairo_traps_t *traps); - -static cairo_status_t -_cairo_gstate_ensure_font (cairo_gstate_t *gstate); + cairo_traps_t *traps); static cairo_status_t _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate); +static cairo_status_t +_cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate); + static void -_cairo_gstate_unset_font (cairo_gstate_t *gstate); +_cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate); cairo_gstate_t * _cairo_gstate_create (cairo_surface_t *target) @@ -81,15 +85,14 @@ _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; + gstate->antialias = CAIRO_ANTIALIAS_DEFAULT; gstate->line_width = CAIRO_GSTATE_LINE_WIDTH_DEFAULT; gstate->line_cap = CAIRO_GSTATE_LINE_CAP_DEFAULT; @@ -101,40 +104,35 @@ _cairo_gstate_init (cairo_gstate_t *gstate, gstate->dash = NULL; gstate->num_dashes = 0; gstate->dash_offset = 0.0; - gstate->max_dash_length = 0.0; - gstate->fraction_dash_lit = 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); + + _cairo_font_options_init_default (&gstate->font_options); - gstate->surface = NULL; - gstate->surface_level = 0; - - 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; + _cairo_clip_init (&gstate->clip, target); _cairo_gstate_identity_matrix (gstate); + cairo_matrix_init_identity (&gstate->source_ctm_inverse); _cairo_pen_init_empty (&gstate->pen_regular); - gstate->next = NULL; + gstate->target = cairo_surface_reference (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; @@ -153,11 +151,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) - { - gstate->clip.region = pixman_region_create (); - pixman_region_copy (gstate->clip.region, other->clip.region); - } + _cairo_clip_init_copy (&gstate->clip, &other->clip); if (gstate->font_face) cairo_font_face_reference (gstate->font_face); @@ -165,8 +159,7 @@ _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->clip.surface); + cairo_surface_reference (gstate->target); cairo_pattern_reference (gstate->source); @@ -174,16 +167,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; @@ -203,19 +188,12 @@ _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.region) - pixman_region_destroy (gstate->clip.region); - gstate->clip.region = NULL; + _cairo_clip_fini (&gstate->clip); cairo_pattern_destroy (gstate->source); @@ -261,30 +239,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) - return CAIRO_STATUS_NO_MEMORY; + gstate->target = cairo_surface_create (gstate->dpy); + if (gstate->target->status) + return gstate->target->status; - _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; @@ -313,104 +291,45 @@ _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; } */ -static cairo_status_t -_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface) -{ - cairo_status_t status; - - if (gstate->surface == surface) - return CAIRO_STATUS_SUCCESS; - - if (surface) { - status = _cairo_surface_begin_reset_clip (surface); - if (!CAIRO_OK (status)) - return status; - } - - _cairo_gstate_unset_font (gstate); - - if (gstate->surface) { - _cairo_surface_end (gstate->surface); - cairo_surface_destroy (gstate->surface); - } - - gstate->surface = surface; - - /* Sometimes the user wants to return to having no target surface, - * (just like after cairo_create). This can be useful for forcing - * the old surface to be destroyed. */ - if (surface == NULL) { - gstate->surface_level = 0; - return CAIRO_STATUS_SUCCESS; - } - - cairo_surface_reference (gstate->surface); - gstate->surface_level = surface->level; - - _cairo_gstate_identity_matrix (gstate); - - return CAIRO_STATUS_SUCCESS; -} - cairo_surface_t * _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); gstate->source = source; - - return CAIRO_STATUS_SUCCESS; -} - -cairo_status_t -_cairo_gstate_set_source_solid (cairo_gstate_t *gstate, - const cairo_color_t *color) -{ - cairo_status_t status; - cairo_pattern_t *source; - - source = _cairo_pattern_create_solid (color); - if (!source) - return CAIRO_STATUS_NO_MEMORY; - - status = _cairo_gstate_set_source (gstate, source); - - cairo_pattern_destroy (source); + gstate->source_ctm_inverse = gstate->ctm_inverse; return CAIRO_STATUS_SUCCESS; } @@ -511,9 +430,6 @@ _cairo_gstate_get_line_join (cairo_gstate_t *gstate) cairo_status_t _cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, double offset) { - double length = 0.0, lit = 0.0; - int i; - if (gstate->dash) { free (gstate->dash); gstate->dash = NULL; @@ -526,16 +442,6 @@ _cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, do gstate->num_dashes = 0; return CAIRO_STATUS_NO_MEMORY; } - - gstate->max_dash_length = 0.0; - for (i = 0; i < num_dashes; i++) { - gstate->max_dash_length = MAX(dash[i], gstate->max_dash_length); - - if (!(i & 1)) - lit += dash[i]; - length += dash[i]; - } - gstate->fraction_dash_lit = lit/length; } memcpy (gstate->dash, dash, gstate->num_dashes * sizeof (double)); @@ -569,7 +475,7 @@ _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty) { cairo_matrix_t tmp; - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); cairo_matrix_init_translate (&tmp, tx, ty); cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); @@ -588,7 +494,7 @@ _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy) if (sx == 0 || sy == 0) return CAIRO_STATUS_INVALID_MATRIX; - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); cairo_matrix_init_scale (&tmp, sx, sy); cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); @@ -604,7 +510,7 @@ _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle) { cairo_matrix_t tmp; - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); cairo_matrix_init_rotate (&tmp, angle); cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); @@ -621,7 +527,7 @@ _cairo_gstate_transform (cairo_gstate_t *gstate, { cairo_matrix_t tmp; - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); tmp = *matrix; cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); @@ -638,7 +544,7 @@ _cairo_gstate_set_matrix (cairo_gstate_t *gstate, { cairo_status_t status; - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); gstate->ctm = *matrix; @@ -653,7 +559,7 @@ _cairo_gstate_set_matrix (cairo_gstate_t *gstate, cairo_status_t _cairo_gstate_identity_matrix (cairo_gstate_t *gstate) { - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); cairo_matrix_init_identity (&gstate->ctm); cairo_matrix_init_identity (&gstate->ctm_inverse); @@ -699,18 +605,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); } @@ -727,19 +633,42 @@ _cairo_gstate_stroke_to_path (cairo_gstate_t *gstate) */ static void -_cairo_gstate_pattern_transform (cairo_gstate_t *gstate, - cairo_pattern_t *pattern) +_cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate, + cairo_pattern_t *pattern, + cairo_pattern_t *original, + cairo_matrix_t *ctm_inverse) { - cairo_matrix_t tmp_matrix = gstate->ctm_inverse; - - if (gstate->surface) + cairo_matrix_t tmp_matrix = *ctm_inverse; + + _cairo_pattern_init_copy (pattern, original); + + 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); } +static void +_cairo_gstate_copy_transformed_source (cairo_gstate_t *gstate, + cairo_pattern_t *pattern) +{ + _cairo_gstate_copy_transformed_pattern (gstate, pattern, + gstate->source, + &gstate->source_ctm_inverse); +} + +static void +_cairo_gstate_copy_transformed_mask (cairo_gstate_t *gstate, + cairo_pattern_t *pattern, + cairo_pattern_t *mask) +{ + _cairo_gstate_copy_transformed_pattern (gstate, pattern, + mask, + &gstate->ctm_inverse); +} + cairo_status_t _cairo_gstate_paint (cairo_gstate_t *gstate) { @@ -748,11 +677,18 @@ _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_surface_set_clip (gstate->target, &gstate->clip); + if (status) + return status; + + status = _cairo_surface_get_extents (gstate->target, &rectangle); + if (status) + return status; + status = _cairo_clip_intersect_to_rectangle (&gstate->clip, &rectangle); + if (status) return status; box.p1.x = _cairo_fixed_from_int (rectangle.x); @@ -760,137 +696,313 @@ _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, - &traps); + _cairo_gstate_clip_and_composite_trapezoids (gstate, &traps); _cairo_traps_fini (&traps); return CAIRO_STATUS_SUCCESS; } -/* Combines @gstate->clip_surface using the IN operator with - * the given intermediate surface, which corresponds to the - * rectangle of the destination space given by @extents. +/** + * _cairo_operator_bounded: + * @operator: a #cairo_operator_t + * + * A bounded operator is one where a source or mask pixel + * of zero results in no effect on the destination image. + * + * Unbounded operators often require special handling; if you, for + * example, draw trapezoids with an unbounded operator, the effect + * extends past the bounding box of the trapezoids. + * + * Return value: %TRUE if the operator is bounded + **/ +cairo_bool_t +_cairo_operator_bounded (cairo_operator_t operator) +{ + switch (operator) { + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_ATOP: + case CAIRO_OPERATOR_DEST: + case CAIRO_OPERATOR_DEST_OVER: + case CAIRO_OPERATOR_DEST_OUT: + case CAIRO_OPERATOR_XOR: + case CAIRO_OPERATOR_ADD: + case CAIRO_OPERATOR_SATURATE: + return TRUE; + case CAIRO_OPERATOR_CLEAR: + case CAIRO_OPERATOR_SOURCE: + case CAIRO_OPERATOR_OUT: + case CAIRO_OPERATOR_IN: + case CAIRO_OPERATOR_DEST_IN: + case CAIRO_OPERATOR_DEST_ATOP: + return FALSE; + } + + ASSERT_NOT_REACHED; + return FALSE; +} + +typedef cairo_status_t (*cairo_draw_func_t) (void *closure, + cairo_operator_t operator, + cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_t *extents); + +/* Handles compositing with a clip surface when the operator allows + * us to combine the clip with the mask */ static cairo_status_t -_cairo_gstate_combine_clip_surface (cairo_gstate_t *gstate, - cairo_surface_t *intermediate, - cairo_rectangle_t *extents) +_cairo_gstate_clip_and_composite_with_mask (cairo_clip_t *clip, + cairo_operator_t operator, + cairo_pattern_t *src, + cairo_draw_func_t draw_func, + void *draw_closure, + cairo_surface_t *dst, + const cairo_rectangle_t *extents) { - cairo_pattern_union_t pattern; + cairo_surface_t *intermediate; + cairo_surface_pattern_t intermediate_pattern; cairo_status_t status; - _cairo_pattern_init_for_surface (&pattern.surface, - gstate->clip.surface); + intermediate = cairo_surface_create_similar (clip->surface, + CAIRO_CONTENT_ALPHA, + extents->width, + extents->height); + if (intermediate->status) + return CAIRO_STATUS_NO_MEMORY; + + status = (*draw_func) (draw_closure, CAIRO_OPERATOR_SOURCE, + NULL, intermediate, + extents->x, extents->y, + extents); + if (status) + goto CLEANUP_SURFACE; - status = _cairo_surface_composite (CAIRO_OPERATOR_IN, - &pattern.base, - NULL, - intermediate, - extents->x - gstate->clip.rect.x, - extents->y - gstate->clip.rect.y, - 0, 0, - 0, 0, + status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_IN, + intermediate, + extents->x, extents->y, + extents); + if (status) + goto CLEANUP_SURFACE; + + _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); + + status = _cairo_surface_composite (operator, + src, &intermediate_pattern.base, dst, + extents->x, extents->y, + 0, 0, + extents->x, extents->y, extents->width, extents->height); - - _cairo_pattern_fini (&pattern.base); + + _cairo_pattern_fini (&intermediate_pattern.base); + + CLEANUP_SURFACE: + cairo_surface_destroy (intermediate); return status; } -/* Creates a region from a cairo_rectangle_t */ -static cairo_status_t -_region_new_from_rect (cairo_rectangle_t *rect, - pixman_region16_t **region) -{ - *region = pixman_region_create (); - if (pixman_region_union_rect (*region, *region, - rect->x, rect->y, - rect->width, rect->height) != PIXMAN_REGION_STATUS_SUCCESS) { - pixman_region_destroy (*region); - return CAIRO_STATUS_NO_MEMORY; - } - - return CAIRO_STATUS_SUCCESS; -} - -/* Gets the bounding box of a region as a cairo_rectangle_t */ -static void -_region_rect_extents (pixman_region16_t *region, - cairo_rectangle_t *rect) -{ - pixman_box16_t *region_extents = pixman_region_extents (region); - - rect->x = region_extents->x1; - rect->y = region_extents->y1; - rect->width = region_extents->x2 - region_extents->x1; - rect->height = region_extents->y2 - region_extents->y1; -} - -/* Intersects @region with the clipping bounds (both region - * and surface) of @gstate +/* Handles compositing with a clip surface when the operator allows + * us to combine the clip with the mask */ static cairo_status_t -_cairo_gstate_intersect_clip (cairo_gstate_t *gstate, - pixman_region16_t *region) +_cairo_gstate_clip_and_composite_combine (cairo_clip_t *clip, + cairo_operator_t operator, + cairo_pattern_t *src, + cairo_draw_func_t draw_func, + void *draw_closure, + cairo_surface_t *dst, + const cairo_rectangle_t *extents) { - if (gstate->clip.region) - pixman_region_intersect (region, gstate->clip.region, region); + cairo_surface_t *intermediate; + cairo_surface_pattern_t dst_pattern; + cairo_surface_pattern_t intermediate_pattern; + cairo_status_t status; - if (gstate->clip.surface) { - pixman_region16_t *clip_rect; - cairo_status_t status; + /* We'd be better off here creating a surface identical in format + * to dst, but we have no way of getting that information. + * A CAIRO_CONTENT_CLONE or something might be useful. + */ + intermediate = cairo_surface_create_similar (dst, + CAIRO_CONTENT_COLOR_ALPHA, + extents->width, + extents->height); + if (intermediate->status) + return CAIRO_STATUS_NO_MEMORY; + + /* Initialize the intermediate surface from the destination surface + */ + _cairo_pattern_init_for_surface (&dst_pattern, dst); + + status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, + &dst_pattern.base, NULL, intermediate, + extents->x, extents->y, + 0, 0, + 0, 0, + extents->width, extents->height); + + _cairo_pattern_fini (&dst_pattern.base); + + if (status) + goto CLEANUP_SURFACE; + + status = (*draw_func) (draw_closure, operator, + src, intermediate, + extents->x, extents->y, + extents); + if (status) + goto CLEANUP_SURFACE; + + /* Combine that with the clip + */ + status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_IN, + intermediate, + extents->x, extents->y, + extents); + if (status) + goto CLEANUP_SURFACE; + + /* Punch the clip out of the destination + */ + status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_OUT, + dst, + 0, 0, + extents); + if (status) + goto CLEANUP_SURFACE; + + /* Now add the two results together + */ + _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); - status = _region_new_from_rect (&gstate->clip.rect, &clip_rect); - if (!CAIRO_OK (status)) - return status; - - if (pixman_region_intersect (region, - clip_rect, - region) != PIXMAN_REGION_STATUS_SUCCESS) - status = CAIRO_STATUS_NO_MEMORY; + status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, + &intermediate_pattern.base, NULL, dst, + 0, 0, + 0, 0, + extents->x, extents->y, + extents->width, extents->height); - pixman_region_destroy (clip_rect); + _cairo_pattern_fini (&intermediate_pattern.base); + + CLEANUP_SURFACE: + cairo_surface_destroy (intermediate); - if (!CAIRO_OK (status)) - return status; - } - - return CAIRO_STATUS_SUCCESS; + return status; } +static int +_cairo_rectangle_empty (const cairo_rectangle_t *rect) +{ + return rect->width == 0 || rect->height == 0; +} + +/** + * _cairo_gstate_clip_and_composite: + * @gstate: a #cairo_gstate_t + * @operator: the operator to draw with + * @src: source pattern + * @draw_func: function that can be called to draw with the mask onto a surface. + * @draw_closure: data to pass to @draw_func. + * @dst: destination surface + * @extents: rectangle holding a bounding box for the operation; this + * rectangle will be used as the size for the temporary + * surface. + * + * When there is a surface clip, we typically need to create an intermediate + * surface. This function handles the logic of creating a temporary surface + * drawing to it, then compositing the result onto the target surface. + * + * @draw_func is to called to draw the mask; it will be called no more + * than once. + * + * Return value: %CAIRO_STATUS_SUCCESS if the drawing succeeded. + **/ +static cairo_status_t +_cairo_gstate_clip_and_composite (cairo_clip_t *clip, + cairo_operator_t operator, + cairo_pattern_t *src, + cairo_draw_func_t draw_func, + void *draw_closure, + cairo_surface_t *dst, + const cairo_rectangle_t *extents) +{ + if (_cairo_rectangle_empty (extents)) + /* Nothing to do */ + return CAIRO_STATUS_SUCCESS; + + if (clip->surface) + { + if (_cairo_operator_bounded (operator)) + return _cairo_gstate_clip_and_composite_with_mask (clip, operator, + src, + draw_func, draw_closure, + dst, extents); + else + return _cairo_gstate_clip_and_composite_combine (clip, operator, + src, + draw_func, draw_closure, + dst, extents); + } + else + { + return (*draw_func) (draw_closure, operator, + src, dst, + 0, 0, + extents); + } +} + + static cairo_status_t _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)) + + /* + * XXX should take mask extents into account, but + * that involves checking the transform and + * _cairo_operator_bounded (operator)... For now, + * be lazy and just use the destination extents + */ + status = _cairo_surface_get_extents (gstate->target, extents); + if (status) return status; - status = _region_new_from_rect (&clip_rect, &clip_region); - if (!CAIRO_OK (status)) - return status; + return _cairo_clip_intersect_to_rectangle (&gstate->clip, extents); +} - status = _cairo_gstate_intersect_clip (gstate, clip_region); - if (!CAIRO_OK (status)) - return status; +static cairo_status_t +_cairo_gstate_mask_draw_func (void *closure, + cairo_operator_t operator, + cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_t *extents) +{ + cairo_pattern_t *mask = closure; - _region_rect_extents (clip_region, extents); - - pixman_region_destroy (clip_region); - - return CAIRO_STATUS_SUCCESS; + if (src) + return _cairo_surface_composite (operator, + src, mask, dst, + extents->x, extents->y, + extents->x, extents->y, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + else + return _cairo_surface_composite (operator, + mask, NULL, dst, + extents->x, extents->y, + 0, 0, /* unused */ + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); } cairo_status_t @@ -898,139 +1010,67 @@ _cairo_gstate_mask (cairo_gstate_t *gstate, cairo_pattern_t *mask) { cairo_rectangle_t extents; - cairo_pattern_union_t pattern; - cairo_surface_pattern_t intermediate_pattern; - cairo_pattern_t *effective_mask; + cairo_pattern_union_t source_pattern, mask_pattern; 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_surface_set_clip (gstate->target, &gstate->clip); + if (status) + return status; + + _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); + _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask); - _get_mask_extents (gstate, mask, &extents); + _get_mask_extents (gstate, &mask_pattern.base, &extents); - if (gstate->clip.surface) { - /* When there is clip surface, we'll need to create a - * temporary surface that combines the clip and mask - */ - cairo_surface_t *intermediate; + status = _cairo_gstate_clip_and_composite (&gstate->clip, gstate->operator, + &source_pattern.base, + _cairo_gstate_mask_draw_func, &mask_pattern.base, + gstate->target, + &extents); - intermediate = cairo_surface_create_similar (gstate->clip.surface, - CAIRO_FORMAT_A8, - extents.width, - extents.height); - if (intermediate == NULL) - return CAIRO_STATUS_NO_MEMORY; - - status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, - mask, NULL, intermediate, - extents.x, extents.y, - 0, 0, - 0, 0, - extents.width, extents.height); - if (!CAIRO_OK (status)) { - cairo_surface_destroy (intermediate); - return status; - } - - status = _cairo_gstate_combine_clip_surface (gstate, intermediate, &extents); - if (!CAIRO_OK (status)) { - cairo_surface_destroy (intermediate); - return status; - } - - _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); - cairo_surface_destroy (intermediate); - - effective_mask = &intermediate_pattern.base; - mask_x = extents.x; - mask_y = extents.y; - - } else { - effective_mask = mask; - mask_x = mask_y = 0; - } - - _cairo_pattern_init_copy (&pattern.base, gstate->source); - _cairo_gstate_pattern_transform (gstate, &pattern.base); - - status = _cairo_surface_composite (gstate->operator, - &pattern.base, - effective_mask, - gstate->surface, - extents.x, extents.y, - extents.x - mask_x, extents.y - mask_y, - extents.x, extents.y, - extents.width, extents.height); - - if (gstate->clip.surface) - _cairo_pattern_fini (&intermediate_pattern.base); + _cairo_pattern_fini (&source_pattern.base); + _cairo_pattern_fini (&mask_pattern.base); return status; } -static cairo_bool_t -_dashes_invisible (cairo_gstate_t *gstate) -{ - if (gstate->dash) { - double min, max; - - _cairo_matrix_compute_expansion_factors (&gstate->ctm, &min, &max); - - /* Quick and dirty applicaton of Nyquist sampling limit */ - - if (min * gstate->max_dash_length < 0.5f) - return TRUE; - } - - return FALSE; -} - cairo_status_t _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) { cairo_status_t status; cairo_traps_t traps; - double *dash = NULL; - double alpha = 0.0; - 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; - if (_dashes_invisible(gstate)) { - dash = gstate->dash; - gstate->dash = NULL; - - /* alpha = gstate->alpha; */ - /* gstate->alpha *= gstate->fraction_dash_lit; */ - } + status = _cairo_surface_set_clip (gstate->target, &gstate->clip); + if (status) + return status; _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate); _cairo_traps_init (&traps); status = _cairo_path_fixed_stroke_to_traps (path, gstate, &traps); - if (status) - goto BAIL; - - _cairo_gstate_clip_and_composite_trapezoids (gstate, - gstate->source, - gstate->operator, - gstate->surface, - &traps); - -BAIL: - _cairo_traps_fini (&traps); - - if (dash) { - gstate->dash = dash; - /* gstate->alpha = alpha; */ + if (status) { + _cairo_traps_fini (&traps); + return status; } - return status; + _cairo_gstate_clip_and_composite_trapezoids (gstate, &traps); + + _cairo_traps_fini (&traps); + + return CAIRO_STATUS_SUCCESS; } cairo_status_t @@ -1075,7 +1115,7 @@ BAIL: * _cairo_rectangle_fixed_round. */ -static void +void _cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_t *rectangle) { rectangle->x = _cairo_fixed_integer_floor (box->p1.x); @@ -1084,7 +1124,7 @@ _cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_t *rectangle) rectangle->height = _cairo_fixed_integer_ceil (box->p2.y) - rectangle->y; } -static void +void _cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src) { int x1, y1, x2, y2; @@ -1107,400 +1147,282 @@ _cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src) } } -static int -_cairo_rectangle_empty (cairo_rectangle_t *rect) -{ - return rect->width == 0 || rect->height == 0; -} - -/* Given a region representing a set of trapezoids that will be - * drawn, clip the region according to the gstate and compute - * the overall extents. - */ -static cairo_status_t -_clip_and_compute_extents_region (cairo_gstate_t *gstate, - pixman_region16_t *trap_region, - cairo_rectangle_t *extents) -{ - cairo_status_t status; - - status = _cairo_gstate_intersect_clip (gstate, trap_region); - if (!CAIRO_OK (status)) - return status; - - _region_rect_extents (trap_region, extents); - - return CAIRO_STATUS_SUCCESS; -} - -/* Given a a set of trapezoids to draw, find a bounding box (non-exact) - * of the trapezoids clipped by the gstate - */ -static cairo_status_t -_clip_and_compute_extents_arbitrary (cairo_gstate_t *gstate, - cairo_traps_t *traps, - cairo_rectangle_t *extents) -{ - cairo_box_t trap_extents; - - _cairo_traps_extents (traps, &trap_extents); - _cairo_box_round_to_rectangle (&trap_extents, extents); - - if (gstate->clip.region) { - pixman_region16_t *intersection; - cairo_status_t status; - - status = _region_new_from_rect (extents, &intersection); - if (!CAIRO_OK (status)) - return status; - - if (pixman_region_intersect (intersection, - gstate->clip.region, - intersection) == PIXMAN_REGION_STATUS_SUCCESS) - _region_rect_extents (intersection, extents); - else - status = CAIRO_STATUS_NO_MEMORY; - - pixman_region_destroy (intersection); - - if (!CAIRO_OK (status)) - return status; - } - - if (gstate->clip.surface) - _cairo_rectangle_intersect (extents, &gstate->clip.rect); - - return CAIRO_STATUS_SUCCESS; -} - /* Composites a region representing a set of trapezoids. */ static cairo_status_t -_composite_trap_region (cairo_gstate_t *gstate, +_composite_trap_region (cairo_clip_t *clip, cairo_pattern_t *src, cairo_operator_t operator, cairo_surface_t *dst, pixman_region16_t *trap_region, cairo_rectangle_t *extents) { - cairo_status_t status, tmp_status; - cairo_pattern_union_t pattern; + cairo_status_t status; 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 (clip->mode != CAIRO_CLIP_MODE_REGION) + return CAIRO_INT_STATUS_UNSUPPORTED; + + clip_serial = _cairo_surface_allocate_clip_serial (dst); + status = _cairo_surface_set_clip_region (dst, + trap_region, + clip_serial); + if (status) return status; } - _cairo_pattern_init_copy (&pattern.base, src); - _cairo_gstate_pattern_transform (gstate, &pattern.base); - - if (gstate->clip.surface) - _cairo_pattern_init_for_surface (&mask.surface, gstate->clip.surface); + if (clip->surface) + _cairo_pattern_init_for_surface (&mask.surface, clip->surface); - status = _cairo_surface_composite (gstate->operator, - &pattern.base, - gstate->clip.surface ? &mask.base : NULL, + status = _cairo_surface_composite (operator, + src, + 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 - (clip->surface ? clip->surface_rect.x : 0), + extents->y - (clip->surface ? clip->surface_rect.y : 0), extents->x, extents->y, extents->width, extents->height); - _cairo_pattern_fini (&pattern.base); - if (gstate->clip.surface) + if (clip->surface) _cairo_pattern_fini (&mask.base); - if (num_rects > 1) { - tmp_status = _cairo_surface_set_clip_region (dst, gstate->clip.region); - if (!CAIRO_OK (tmp_status)) - status = tmp_status; - } - return status; } -static void -translate_traps (cairo_traps_t *traps, int x, int y) -{ - cairo_fixed_t xoff, yoff; - cairo_trapezoid_t *t; - int i; +typedef struct { + cairo_traps_t *traps; + cairo_antialias_t antialias; +} cairo_composite_traps_info_t; - /* Ugh. The cairo_composite/(Render) interface doesn't allow - an offset for the trapezoids. Need to manually shift all - the coordinates to align with the offset origin of the - intermediate surface. */ - - xoff = _cairo_fixed_from_int (x); - yoff = _cairo_fixed_from_int (y); - - for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) { - t->top += yoff; - t->bottom += yoff; - t->left.p1.x += xoff; - t->left.p1.y += yoff; - t->left.p2.x += xoff; - t->left.p2.y += yoff; - t->right.p1.x += xoff; - t->right.p1.y += yoff; - t->right.p2.x += xoff; - t->right.p2.y += yoff; - } -} - -/* Composites a set of trapezoids in the case where we need to create - * an intermediate surface to handle gstate->clip.surface - * - * Warning: This call modifies the coordinates of traps - */ static cairo_status_t -_composite_traps_intermediate_surface (cairo_gstate_t *gstate, - cairo_pattern_t *src, - cairo_operator_t operator, - cairo_surface_t *dst, - cairo_traps_t *traps, - cairo_rectangle_t *extents) +_composite_traps_draw_func (void *closure, + cairo_operator_t operator, + cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_t *extents) { + cairo_composite_traps_info_t *info = closure; cairo_pattern_union_t pattern; - cairo_surface_t *intermediate; - cairo_surface_pattern_t intermediate_pattern; cairo_status_t status; - - translate_traps (traps, -extents->x, -extents->y); - - intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface, - CAIRO_FORMAT_A8, - extents->width, - extents->height, - CAIRO_COLOR_TRANSPARENT); - if (intermediate == NULL) - return CAIRO_STATUS_NO_MEMORY; + if (dst_x != 0 || dst_y != 0) + _cairo_traps_translate (info->traps, - dst_x, - dst_y); + _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE); + if (!src) + src = &pattern.base; - status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD, - &pattern.base, - intermediate, - extents->x, extents->y, - 0, 0, - extents->width, - extents->height, - traps->traps, - traps->num_traps); - _cairo_pattern_fini (&pattern.base); - - if (!CAIRO_OK (status)) - goto out; - - status = _cairo_gstate_combine_clip_surface (gstate, intermediate, extents); - if (!CAIRO_OK (status)) - goto out; - - _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); - _cairo_pattern_init_copy (&pattern.base, src); - _cairo_gstate_pattern_transform (gstate, &pattern.base); - - status = _cairo_surface_composite (operator, - &pattern.base, - &intermediate_pattern.base, - dst, - extents->x, extents->y, - 0, 0, - extents->x, extents->y, - extents->width, extents->height); - - _cairo_pattern_fini (&pattern.base); - _cairo_pattern_fini (&intermediate_pattern.base); - - out: - cairo_surface_destroy (intermediate); - - return status; -} - -/* Composites a region representing a set of trapezoids in the - * case of a solid source (so we can use - * _cairo_surface_fill_rectangles). - */ -static cairo_status_t -_composite_trap_region_solid (cairo_gstate_t *gstate, - cairo_solid_pattern_t *src, - cairo_operator_t operator, - cairo_surface_t *dst, - pixman_region16_t *region) -{ - int num_rects = pixman_region_num_rects (region); - pixman_box16_t *boxes = pixman_region_rects (region); - cairo_rectangle_t *rects; - cairo_status_t status; - int i; - - if (!num_rects) - return CAIRO_STATUS_SUCCESS; - - rects = malloc (sizeof (pixman_rectangle_t) * num_rects); - if (!rects) - return CAIRO_STATUS_NO_MEMORY; - - for (i = 0; i < num_rects; i++) { - rects[i].x = boxes[i].x1; - rects[i].y = boxes[i].y1; - rects[i].width = boxes[i].x2 - boxes[i].x1; - rects[i].height = boxes[i].y2 - boxes[i].y1; - } - - status = _cairo_surface_fill_rectangles (dst, operator, - &src->color, rects, num_rects); - - free (rects); - - return status; -} - -/* Composites a set of trapezoids in the general case where - gstate->clip.surface == NULL - */ -static cairo_status_t -_composite_traps (cairo_gstate_t *gstate, - cairo_pattern_t *src, - cairo_operator_t operator, - cairo_surface_t *dst, - cairo_traps_t *traps, - cairo_rectangle_t *extents) -{ - cairo_pattern_union_t pattern; - cairo_status_t status; - - _cairo_pattern_init_copy (&pattern.base, src); - _cairo_gstate_pattern_transform (gstate, &pattern.base); - - status = _cairo_surface_composite_trapezoids (gstate->operator, - &pattern.base, dst, - extents->x, extents->y, - extents->x, extents->y, - extents->width, - extents->height, - traps->traps, - traps->num_traps); - + status = _cairo_surface_composite_trapezoids (operator, + src, dst, info->antialias, + extents->x, extents->y, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height, + info->traps->traps, + info->traps->num_traps); _cairo_pattern_fini (&pattern.base); return status; } /* Warning: This call modifies the coordinates of traps */ -static cairo_status_t -_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, - cairo_pattern_t *src, - cairo_operator_t operator, - cairo_surface_t *dst, - cairo_traps_t *traps) +cairo_status_t +_cairo_surface_clip_and_composite_trapezoids (cairo_pattern_t *src, + cairo_operator_t operator, + cairo_surface_t *dst, + cairo_traps_t *traps, + cairo_clip_t *clip, + cairo_antialias_t antialias) { cairo_status_t status; pixman_region16_t *trap_region; + pixman_region16_t *clear_region = NULL; cairo_rectangle_t extents; + cairo_composite_traps_info_t traps_info; if (traps->num_traps == 0) return CAIRO_STATUS_SUCCESS; - if (gstate->surface == 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) - status = _clip_and_compute_extents_region (gstate, trap_region, &extents); - else - status = _clip_and_compute_extents_arbitrary (gstate, traps, &extents); - - if (!CAIRO_OK (status)) - goto out; - - if (_cairo_rectangle_empty (&extents)) - /* Nothing to do */ - goto out; - - if (gstate->clip.surface) { + if (_cairo_operator_bounded (operator)) + { if (trap_region) { - /* If we are compositing a set of rectangles, we can set them as the - * clip region for the destination surface and use the clip surface - * as the mask. A clip region might not be supported, in which case - * we fall through to the next method - */ - status = _composite_trap_region (gstate, src, operator, dst, - trap_region, &extents); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - goto out; - } - - /* Handle a clip surface by creating an intermediate surface. */ - status = _composite_traps_intermediate_surface (gstate, src, operator, - dst, traps, &extents); - } else { - /* No clip surface */ - if (trap_region && src->type == CAIRO_PATTERN_SOLID) { - /* Solid rectangles are handled specially */ - status = _composite_trap_region_solid (gstate, (cairo_solid_pattern_t *)src, - operator, dst, trap_region); - } else if (trap_region && pixman_region_num_rects (trap_region) <= 1) { - /* For a simple rectangle, we can just use composite(), for more - * rectangles, we'd have to set a clip region. That might still - * be a win, but it's less obvious. (Depends on the backend) - */ - status = _composite_trap_region (gstate, src, operator, dst, - trap_region, &extents); + status = _cairo_clip_intersect_to_region (clip, trap_region); + _cairo_region_extents_rectangle (trap_region, &extents); } else { - status = _composite_traps (gstate, src, operator, - dst, traps, &extents); + cairo_box_t trap_extents; + _cairo_traps_extents (traps, &trap_extents); + _cairo_box_round_to_rectangle (&trap_extents, &extents); + status = _cairo_clip_intersect_to_rectangle (clip, &extents); } } + else + { + status = _cairo_surface_get_extents (dst, &extents); + if (status) + return status; + + if (trap_region && !clip->surface) { + /* If we optimize drawing with an unbounded operator to + * _cairo_surface_fill_rectangles() or to drawing with a + * clip region, then we have an additional region to clear. + */ + status = _cairo_surface_get_extents (dst, &extents); + if (status) + return status; + + clear_region = _cairo_region_create_from_rectangle (&extents); + status = _cairo_clip_intersect_to_region (clip, clear_region); + if (status) + return status; + + _cairo_region_extents_rectangle (clear_region, &extents); + + if (pixman_region_subtract (clear_region, clear_region, trap_region) != PIXMAN_REGION_STATUS_SUCCESS) + return CAIRO_STATUS_NO_MEMORY; + + if (!pixman_region_not_empty (clear_region)) { + pixman_region_destroy (clear_region); + clear_region = NULL; + } + } else { + status = _cairo_clip_intersect_to_rectangle (clip, &extents); + if (status) + return status; + } + } + + if (status) + goto out; + + if (trap_region) + { + if (src->type == CAIRO_PATTERN_SOLID && !clip->surface) + { + /* Solid rectangles special case */ + status = _cairo_surface_fill_region (dst, operator, + &((cairo_solid_pattern_t *)src)->color, + trap_region); + if (!status && clear_region) + status = _cairo_surface_fill_region (dst, operator, + CAIRO_COLOR_TRANSPARENT, + clear_region); + + goto out; + } + + if (_cairo_operator_bounded (operator) || !clip->surface) + { + /* 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. + * + * If we have a clip surface, we set it as the mask; this only works + * for bounded operators; for unbounded operators, clip and mask + * cannot be interchanged. + * + * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has + * more than rectangle and the destination doesn't support clip + * regions. In that case, we fall through. + */ + status = _composite_trap_region (clip, src, operator, dst, + trap_region, &extents); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + { + if (!status && clear_region) + status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + clear_region); + goto out; + } + } + } + + traps_info.traps = traps; + traps_info.antialias = antialias; + + status = _cairo_gstate_clip_and_composite (clip, operator, src, + _composite_traps_draw_func, &traps_info, + dst, &extents); out: if (trap_region) pixman_region_destroy (trap_region); + if (clear_region) + pixman_region_destroy (clear_region); return status; } +/* Warning: This call modifies the coordinates of traps */ +static cairo_status_t +_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, + cairo_traps_t *traps) +{ + cairo_pattern_union_t pattern; + cairo_status_t status; + + _cairo_gstate_copy_transformed_source (gstate, &pattern.base); + + status = _cairo_surface_clip_and_composite_trapezoids (&pattern.base, + gstate->operator, + gstate->target, + traps, + &gstate->clip, + gstate->antialias); + + _cairo_pattern_fini (&pattern.base); + + return status; +} + cairo_status_t _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_surface_set_clip (gstate->target, &gstate->clip); + 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; _cairo_traps_init (&traps); - status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps); + status = _cairo_path_fixed_fill_to_traps (path, + gstate->fill_rule, + gstate->tolerance, + &traps); if (status) { _cairo_traps_fini (&traps); return status; } - _cairo_gstate_clip_and_composite_trapezoids (gstate, - gstate->source, - gstate->operator, - gstate->surface, - &traps); + _cairo_gstate_clip_and_composite_trapezoids (gstate, &traps); _cairo_traps_fini (&traps); @@ -1521,7 +1443,10 @@ _cairo_gstate_in_fill (cairo_gstate_t *gstate, _cairo_traps_init (&traps); - status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps); + status = _cairo_path_fixed_fill_to_traps (path, + gstate->fill_rule, + gstate->tolerance, + &traps); if (status) goto BAIL; @@ -1536,19 +1461,13 @@ BAIL: cairo_status_t _cairo_gstate_copy_page (cairo_gstate_t *gstate) { - if (gstate->surface == NULL) - return CAIRO_STATUS_NO_TARGET_SURFACE; - - return _cairo_surface_copy_page (gstate->surface); + return _cairo_surface_copy_page (gstate->target); } cairo_status_t _cairo_gstate_show_page (cairo_gstate_t *gstate) { - if (gstate->surface == NULL) - return CAIRO_STATUS_NO_TARGET_SURFACE; - - return _cairo_surface_show_page (gstate->surface); + return _cairo_surface_show_page (gstate->target); } cairo_status_t @@ -1560,13 +1479,7 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate, cairo_status_t status; cairo_traps_t traps; cairo_box_t extents; - double *dash = NULL; - - if (_dashes_invisible(gstate)) { - dash = gstate->dash; - gstate->dash = NULL; - } - + _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate); _cairo_traps_init (&traps); @@ -1587,9 +1500,6 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate, BAIL: _cairo_traps_fini (&traps); - - if (dash) - gstate->dash = dash; return status; } @@ -1606,7 +1516,10 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate, _cairo_traps_init (&traps); - status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps); + status = _cairo_path_fixed_fill_to_traps (path, + gstate->fill_rule, + gstate->tolerance, + &traps); if (status) goto BAIL; @@ -1629,125 +1542,19 @@ 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); - gstate->clip.surface = NULL; - - if (gstate->clip.region) - pixman_region_destroy (gstate->clip.region); - gstate->clip.region = NULL; - - /* reset the surface's clip to the whole surface */ - if (gstate->surface) - _cairo_surface_set_clip_region (gstate->surface, - gstate->clip.region); - - return CAIRO_STATUS_SUCCESS; + return _cairo_clip_reset (&gstate->clip); } cairo_status_t _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path) { - cairo_status_t status; - cairo_pattern_union_t pattern; - cairo_traps_t traps; - cairo_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. */ - - _cairo_traps_init (&traps); - status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps); - if (!CAIRO_OK (status)) { - _cairo_traps_fini (&traps); - return status; - } - - /* Check to see if we can represent these traps as a PixRegion. */ - - status = _cairo_traps_extract_region (&traps, ®ion); - if (!CAIRO_OK (status)) { - _cairo_traps_fini (&traps); - return status; - } - - 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); - - if (status != CAIRO_INT_STATUS_UNSUPPORTED) { - _cairo_traps_fini (&traps); - return status; - } - - /* Fall through as status == CAIRO_INT_STATUS_UNSUPPORTED - means that backend doesn't support clipping regions and - mask surface clipping should be used instead. */ - } - - /* Otherwise represent the clip as a mask surface. */ - - 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; - } - - translate_traps (&traps, -gstate->clip.rect.x, -gstate->clip.rect.y); - _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE); - - status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN, - &pattern.base, - gstate->clip.surface, - 0, 0, - 0, 0, - gstate->clip.rect.width, - gstate->clip.rect.height, - traps.traps, - traps.num_traps); - - _cairo_pattern_fini (&pattern.base); - - _cairo_traps_fini (&traps); - - return CAIRO_STATUS_SUCCESS; + return _cairo_clip_clip (&gstate->clip, + path, gstate->fill_rule, gstate->tolerance, + gstate->antialias, gstate->target); } static void -_cairo_gstate_unset_font (cairo_gstate_t *gstate) +_cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate) { if (gstate->scaled_font) { cairo_scaled_font_destroy (gstate->scaled_font); @@ -1763,9 +1570,9 @@ _cairo_gstate_select_font_face (cairo_gstate_t *gstate, { cairo_font_face_t *font_face; - font_face = _cairo_simple_font_face_create (family, slant, weight); - if (!font_face) - return CAIRO_STATUS_NO_MEMORY; + font_face = _cairo_toy_font_face_create (family, slant, weight); + if (font_face->status) + return font_face->status; _cairo_gstate_set_font_face (gstate, font_face); cairo_font_face_destroy (font_face); @@ -1777,7 +1584,7 @@ cairo_status_t _cairo_gstate_set_font_size (cairo_gstate_t *gstate, double size) { - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); cairo_matrix_init_scale (&gstate->font_matrix, size, size); @@ -1788,7 +1595,7 @@ cairo_status_t _cairo_gstate_set_font_matrix (cairo_gstate_t *gstate, const cairo_matrix_t *matrix) { - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); gstate->font_matrix = *matrix; @@ -1802,6 +1609,24 @@ _cairo_gstate_get_font_matrix (cairo_gstate_t *gstate, *matrix = gstate->font_matrix; } +cairo_status_t +_cairo_gstate_set_font_options (cairo_gstate_t *gstate, + const cairo_font_options_t *options) +{ + _cairo_gstate_unset_scaled_font (gstate); + + gstate->font_options = *options; + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_gstate_get_font_options (cairo_gstate_t *gstate, + cairo_font_options_t *options) +{ + *options = gstate->font_options; +} + cairo_status_t _cairo_gstate_get_font_face (cairo_gstate_t *gstate, cairo_font_face_t **font_face) @@ -1897,20 +1722,25 @@ static cairo_status_t _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate) { if (!gstate->font_face) { - gstate->font_face = _cairo_simple_font_face_create (CAIRO_FONT_FAMILY_DEFAULT, - CAIRO_FONT_SLANT_DEFAULT, - CAIRO_FONT_WEIGHT_DEFAULT); - if (!gstate->font_face) - return CAIRO_STATUS_NO_MEMORY; + cairo_font_face_t *font_face; + + font_face = _cairo_toy_font_face_create (CAIRO_FONT_FAMILY_DEFAULT, + CAIRO_FONT_SLANT_DEFAULT, + CAIRO_FONT_WEIGHT_DEFAULT); + if (font_face->status) + return font_face->status; + else + gstate->font_face = font_face; } return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_gstate_ensure_font (cairo_gstate_t *gstate) +_cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate) { cairo_status_t status; + cairo_font_options_t options; if (gstate->scaled_font) return CAIRO_STATUS_SUCCESS; @@ -1919,9 +1749,13 @@ _cairo_gstate_ensure_font (cairo_gstate_t *gstate) if (status) return status; + cairo_surface_get_font_options (gstate->target, &options); + cairo_font_options_merge (&options, &gstate->font_options); + gstate->scaled_font = cairo_scaled_font_create (gstate->font_face, &gstate->font_matrix, - &gstate->ctm); + &gstate->ctm, + &options); if (!gstate->scaled_font) return CAIRO_STATUS_NO_MEMORY; @@ -1933,11 +1767,13 @@ cairo_status_t _cairo_gstate_get_font_extents (cairo_gstate_t *gstate, cairo_font_extents_t *extents) { - cairo_status_t status = _cairo_gstate_ensure_font (gstate); + cairo_status_t status = _cairo_gstate_ensure_scaled_font (gstate); if (status) return status; - return cairo_scaled_font_extents (gstate->scaled_font, extents); + cairo_scaled_font_extents (gstate->scaled_font, extents); + + return CAIRO_STATUS_SUCCESS; } cairo_status_t @@ -1951,7 +1787,7 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, cairo_status_t status; int i; - status = _cairo_gstate_ensure_font (gstate); + status = _cairo_gstate_ensure_scaled_font (gstate); if (status) return status; @@ -1980,15 +1816,15 @@ cairo_status_t _cairo_gstate_set_font_face (cairo_gstate_t *gstate, cairo_font_face_t *font_face) { + if (font_face && font_face->status) + return font_face->status; + if (font_face != gstate->font_face) { - if (gstate->font_face) - cairo_font_face_destroy (gstate->font_face); - gstate->font_face = font_face; - if (gstate->font_face) - cairo_font_face_reference (gstate->font_face); + cairo_font_face_destroy (gstate->font_face); + gstate->font_face = cairo_font_face_reference (font_face); } - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); return CAIRO_STATUS_SUCCESS; } @@ -2001,7 +1837,7 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate, { cairo_status_t status; - status = _cairo_gstate_ensure_font (gstate); + status = _cairo_gstate_ensure_scaled_font (gstate); if (status) return status; @@ -2012,6 +1848,58 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate, return CAIRO_STATUS_SUCCESS; } +typedef struct { + cairo_scaled_font_t *font; + cairo_glyph_t *glyphs; + int num_glyphs; +} cairo_show_glyphs_info_t; + +static cairo_status_t +_cairo_gstate_show_glyphs_draw_func (void *closure, + cairo_operator_t operator, + cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_t *extents) +{ + cairo_show_glyphs_info_t *glyph_info = closure; + cairo_pattern_union_t pattern; + cairo_status_t status; + + /* Modifying the glyph array is fine because we know that this function + * will be called only once, and we've already made a copy of the + * glyphs in the wrapper. + */ + if (dst_x != 0 || dst_y != 0) { + int i; + + for (i = 0; i < glyph_info->num_glyphs; ++i) + { + glyph_info->glyphs[i].x -= dst_x; + glyph_info->glyphs[i].y -= dst_y; + } + } + + _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE); + if (!src) + src = &pattern.base; + + status = _cairo_scaled_font_show_glyphs (glyph_info->font, + operator, + src, dst, + extents->x, extents->y, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height, + glyph_info->glyphs, + glyph_info->num_glyphs); + + if (src == &pattern.base) + _cairo_pattern_fini (&pattern.base); + + return status; +} + cairo_status_t _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, cairo_glyph_t *glyphs, @@ -2023,11 +1911,16 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, cairo_pattern_union_t pattern; cairo_box_t bbox; cairo_rectangle_t extents; + cairo_show_glyphs_info_t glyph_info; - if (gstate->surface->level != gstate->surface_level) - return CAIRO_STATUS_BAD_NESTING; - - status = _cairo_gstate_ensure_font (gstate); + if (gstate->source->status) + return gstate->source->status; + + status = _cairo_surface_set_clip (gstate->target, &gstate->clip); + if (status) + return status; + + status = _cairo_gstate_ensure_scaled_font (gstate); if (status) return status; @@ -2042,114 +1935,42 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, &transformed_glyphs[i].x, &transformed_glyphs[i].y); } - - status = _cairo_scaled_font_glyph_bbox (gstate->scaled_font, - transformed_glyphs, num_glyphs, - &bbox); - _cairo_box_round_to_rectangle (&bbox, &extents); - if (status) - goto CLEANUP_GLYPHS; - - if (gstate->clip.surface) + if (_cairo_operator_bounded (gstate->operator)) { - cairo_surface_t *intermediate; - cairo_surface_pattern_t intermediate_pattern; - - _cairo_rectangle_intersect (&extents, &gstate->clip.rect); - - /* Shortcut if empty */ - if (_cairo_rectangle_empty (&extents)) { - status = CAIRO_STATUS_SUCCESS; - goto BAIL1; - } - - intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface, - CAIRO_FORMAT_A8, - extents.width, - extents.height, - CAIRO_COLOR_TRANSPARENT); - if (intermediate == NULL) { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL1; - } - - /* move the glyphs again, from dev space to intermediate space */ - for (i = 0; i < num_glyphs; ++i) - { - transformed_glyphs[i].x -= extents.x; - transformed_glyphs[i].y -= extents.y; - } - - _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE); - - status = _cairo_scaled_font_show_glyphs (gstate->scaled_font, - CAIRO_OPERATOR_ADD, - &pattern.base, intermediate, - extents.x, extents.y, - 0, 0, - extents.width, extents.height, - transformed_glyphs, num_glyphs); - - _cairo_pattern_fini (&pattern.base); - + status = _cairo_scaled_font_glyph_bbox (gstate->scaled_font, + transformed_glyphs, num_glyphs, + &bbox); if (status) - goto BAIL2; - - _cairo_pattern_init_for_surface (&pattern.surface, - gstate->clip.surface); - - status = _cairo_surface_composite (CAIRO_OPERATOR_IN, - &pattern.base, - NULL, - intermediate, - extents.x - gstate->clip.rect.x, - extents.y - gstate->clip.rect.y, - 0, 0, - 0, 0, - extents.width, extents.height); - - _cairo_pattern_fini (&pattern.base); - - if (status) - goto BAIL2; - - _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); - _cairo_pattern_init_copy (&pattern.base, gstate->source); - _cairo_gstate_pattern_transform (gstate, &pattern.base); - - status = _cairo_surface_composite (gstate->operator, - &pattern.base, - &intermediate_pattern.base, - gstate->surface, - extents.x, extents.y, - 0, 0, - extents.x, extents.y, - extents.width, extents.height); - _cairo_pattern_fini (&pattern.base); - _cairo_pattern_fini (&intermediate_pattern.base); - - BAIL2: - cairo_surface_destroy (intermediate); - BAIL1: - ; + goto CLEANUP_GLYPHS; + + _cairo_box_round_to_rectangle (&bbox, &extents); } else { - _cairo_pattern_init_copy (&pattern.base, gstate->source); - _cairo_gstate_pattern_transform (gstate, &pattern.base); - - status = _cairo_scaled_font_show_glyphs (gstate->scaled_font, - gstate->operator, &pattern.base, - gstate->surface, - extents.x, extents.y, - extents.x, extents.y, - extents.width, extents.height, - transformed_glyphs, num_glyphs); - - _cairo_pattern_fini (&pattern.base); + status = _cairo_surface_get_extents (gstate->target, &extents); + if (status) + goto CLEANUP_GLYPHS; } + status = _cairo_clip_intersect_to_rectangle (&gstate->clip, &extents); + if (status) + goto CLEANUP_GLYPHS; + + _cairo_gstate_copy_transformed_source (gstate, &pattern.base); + + glyph_info.font = gstate->scaled_font; + glyph_info.glyphs = transformed_glyphs; + glyph_info.num_glyphs = num_glyphs; + + status = _cairo_gstate_clip_and_composite (&gstate->clip, gstate->operator, + &pattern.base, + _cairo_gstate_show_glyphs_draw_func, &glyph_info, + gstate->target, + &extents); + + _cairo_pattern_fini (&pattern.base); + CLEANUP_GLYPHS: free (transformed_glyphs); @@ -2166,7 +1987,7 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, int i; cairo_glyph_t *transformed_glyphs = NULL; - status = _cairo_gstate_ensure_font (gstate); + status = _cairo_gstate_ensure_scaled_font (gstate); if (status) return status; @@ -2189,3 +2010,19 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, free (transformed_glyphs); return status; } + +cairo_private cairo_status_t +_cairo_gstate_set_antialias (cairo_gstate_t *gstate, + cairo_antialias_t antialias) +{ + gstate->antialias = antialias; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_private cairo_antialias_t +_cairo_gstate_get_antialias (cairo_gstate_t *gstate) +{ + return gstate->antialias; +} + diff --git a/gfx/cairo/cairo/src/cairo-hash-private.h b/gfx/cairo/cairo/src/cairo-hash-private.h new file mode 100644 index 000000000000..6dc9c9073eb1 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-hash-private.h @@ -0,0 +1,125 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 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 + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Keith Packard + * Graydon Hoare + * Carl Worth + */ + +#ifndef CAIRO_HASH_PRIVATE_H +#define CAIRO_HASH_PRIVATE_H + +/* XXX: I'd like this file to be self-contained in terms of + * includeability, but that's not really possible with the current + * monolithic cairoint.h. So, for now, just include cairoint.h instead + * if you want to include this file. */ + +typedef struct _cairo_hash_table cairo_hash_table_t; + +/** + * cairo_hash_entry_t: + * + * A #cairo_hash_entry_t contains both a key and a value for + * cairo_hash_table_t. User-derived types for cairo_hash_entry_t must + * be type-compatible with this structure (eg. they must have an + * unsigned long as the first parameter. The easiest way to get this + * is to use: + * + * typedef _my_entry { + * cairo_hash_entry_t base; + * ... Remainder of key and value fields here .. + * } my_entry_t; + * + * which then allows a pointer to my_entry_t to be passed to any of + * the cairo_hash_table functions as follows without requiring a cast: + * + * _cairo_hash_table_insert (hash_table, &my_entry->base); + * + * IMPORTANT: The caller is reponsible for initializing + * my_entry->base.hash with a hash code derived from the key. The + * essential property of the hash code is that keys_equal must never + * return TRUE for two keys that have different hashes. The best hash + * code will reduce the frequency of two keys with the same code for + * which keys_equal returns FALSE. + * + * Which parts of the entry make up the "key" and which part make up + * the value are entirely up to the caller, (as determined by the + * computation going into base.hash as well as the keys_equal + * function). A few of the cairo_hash_table functions accept an entry + * which will be used exclusively as a "key", (indicated by a + * parameter name of key). In these cases, the value-related fields of + * the entry need not be initialized if so desired. + **/ +typedef struct _cairo_hash_entry { + unsigned long hash; +} cairo_hash_entry_t; + +typedef cairo_bool_t +(*cairo_hash_keys_equal_func_t) (void *key_a, void *key_b); + +typedef cairo_bool_t +(*cairo_hash_predicate_func_t) (void *entry); + +typedef void +(*cairo_hash_callback_func_t) (void *entry, + void *closure); + +cairo_private cairo_hash_table_t * +_cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal); + +cairo_private void +_cairo_hash_table_destroy (cairo_hash_table_t *hash_table); + +cairo_private cairo_bool_t +_cairo_hash_table_lookup (cairo_hash_table_t *hash_table, + cairo_hash_entry_t *key, + cairo_hash_entry_t **entry_return); + +cairo_private void * +_cairo_hash_table_random_entry (cairo_hash_table_t *hash_table, + cairo_hash_predicate_func_t predicate); + +cairo_private cairo_status_t +_cairo_hash_table_insert (cairo_hash_table_t *hash_table, + cairo_hash_entry_t *entry); + +cairo_private void +_cairo_hash_table_remove (cairo_hash_table_t *hash_table, + cairo_hash_entry_t *key); + +cairo_private void +_cairo_hash_table_foreach (cairo_hash_table_t *hash_table, + cairo_hash_callback_func_t hash_callback, + void *closure); + +#endif diff --git a/gfx/cairo/cairo/src/cairo-hash.c b/gfx/cairo/cairo/src/cairo-hash.c new file mode 100644 index 000000000000..e44ab30258ac --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-hash.c @@ -0,0 +1,533 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 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 + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Keith Packard + * Graydon Hoare + * Carl Worth + */ + +#include "cairoint.h" + +/* + * An entry can be in one of three states: + * + * FREE: Entry has never been used, terminates all searches. + * Appears in the table as a NULL pointer. + * + * DEAD: Entry had been live in the past. A dead entry can be reused + * but does not terminate a search for an exact entry. + * Appears in the table as a pointer to DEAD_ENTRY. + * + * LIVE: Entry is currently being used. + * Appears in the table as any non-NULL, non-DEAD_ENTRY pointer. + */ + +static cairo_hash_entry_t dead_entry = { 0 }; +#define DEAD_ENTRY (&dead_entry) + +#define ENTRY_IS_FREE(entry) ((entry) == NULL) +#define ENTRY_IS_DEAD(entry) ((entry) == DEAD_ENTRY) +#define ENTRY_IS_LIVE(entry) ((entry) && ! ENTRY_IS_DEAD(entry)) + +/* We expect keys will not be destroyed frequently, so our table does not + * contain any explicit shrinking code nor any chain-coalescing code for + * entries randomly deleted by memory pressure (except during rehashing, of + * course). These assumptions are potentially bad, but they make the + * implementation straightforward. + * + * Revisit later if evidence appears that we're using excessive memory from + * a mostly-dead table. + * + * This table is open-addressed with double hashing. Each table size is a + * prime chosen to be a little more than double the high water mark for a + * given arrangement, so the tables should remain < 50% full. The table + * size makes for the "first" hash modulus; a second prime (2 less than the + * first prime) serves as the "second" hash modulus, which is co-prime and + * thus guarantees a complete permutation of table indices. + * + * This structure, and accompanying table, is borrowed/modified from the + * file xserver/render/glyph.c in the freedesktop.org x server, with + * permission (and suggested modification of doubling sizes) by Keith + * Packard. + */ + +typedef struct _cairo_hash_table_arrangement { + unsigned long high_water_mark; + unsigned long size; + unsigned long rehash; +} cairo_hash_table_arrangement_t; + +static const cairo_hash_table_arrangement_t hash_table_arrangements [] = { + { 16, 43, 41 }, + { 32, 73, 71 }, + { 64, 151, 149 }, + { 128, 283, 281 }, + { 256, 571, 569 }, + { 512, 1153, 1151 }, + { 1024, 2269, 2267 }, + { 2048, 4519, 4517 }, + { 4096, 9013, 9011 }, + { 8192, 18043, 18041 }, + { 16384, 36109, 36107 }, + { 32768, 72091, 72089 }, + { 65536, 144409, 144407 }, + { 131072, 288361, 288359 }, + { 262144, 576883, 576881 }, + { 524288, 1153459, 1153457 }, + { 1048576, 2307163, 2307161 }, + { 2097152, 4613893, 4613891 }, + { 4194304, 9227641, 9227639 }, + { 8388608, 18455029, 18455027 }, + { 16777216, 36911011, 36911009 }, + { 33554432, 73819861, 73819859 }, + { 67108864, 147639589, 147639587 }, + { 134217728, 295279081, 295279079 }, + { 268435456, 590559793, 590559791 } +}; + +#define NUM_HASH_TABLE_ARRANGEMENTS (sizeof(hash_table_arrangements)/sizeof(hash_table_arrangements[0])) + +struct _cairo_hash_table { + cairo_hash_keys_equal_func_t keys_equal; + + const cairo_hash_table_arrangement_t *arrangement; + cairo_hash_entry_t **entries; + + unsigned long live_entries; +}; + +/** + * _cairo_hash_table_create: + * @keys_equal: a function to return TRUE if two keys are equal + * + * Creates a new hash table which will use the keys_equal() function + * to compare hash keys. Data is provided to the hash table in the + * form of user-derived versions of cairo_hash_entry_t. A hash entry + * must be able to hold both a key (including a hash code) and a + * value. Sometimes only the key will be necessary, (as in + * _cairo_hash_table_remove), and other times both a key and a value + * will be necessary, (as in _cairo_hash_table_insert). + * + * See #cairo_hash_entry_t for more details. + * + * Return value: the new hash table or NULL if out of memory. + **/ +cairo_hash_table_t * +_cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal) +{ + cairo_hash_table_t *hash_table; + + hash_table = malloc (sizeof (cairo_hash_table_t)); + if (hash_table == NULL) + return NULL; + + hash_table->keys_equal = keys_equal; + + hash_table->arrangement = &hash_table_arrangements[0]; + + hash_table->entries = calloc (hash_table->arrangement->size, + sizeof(cairo_hash_entry_t *)); + if (hash_table->entries == NULL) { + free (hash_table); + return NULL; + } + + hash_table->live_entries = 0; + + return hash_table; +} + +/** + * _cairo_hash_table_destroy: + * @hash_table: an empty hash table to destroy + * + * Immediately destroys the given hash table, freeing all resources + * associated with it. + * + * WARNING: The hash_table must have no live entries in it before + * _cairo_hash_table_destroy is called. It is a fatal error otherwise, + * and this function will halt. The rationale for this behavior is to + * avoid memory leaks and to avoid needless complication of the API + * with destroy notifiy callbacks. + **/ +void +_cairo_hash_table_destroy (cairo_hash_table_t *hash_table) +{ + if (hash_table == NULL) + return; + + /* The hash table must be empty. Otherwise, halt. */ + assert (hash_table->live_entries == 0); + + free (hash_table->entries); + hash_table->entries = NULL; + + free (hash_table); +} + +/** + * _cairo_hash_table_lookup_internal: + * + * @hash_table: a #cairo_hash_table_t to search + * @key: the key to search on + * @hash_code: the hash_code for @key + * @key_unique: If TRUE, then caller asserts that no key already + * exists that will compare equal to #key, so search can be + * optimized. If unsure, set to FALSE and the code will always work. + * + * Search the hashtable for a live entry for which + * hash_table->keys_equal returns true. If no such entry exists then + * return the first available (free or dead entry). + * + * If the key_unique flag is set, then the search will never call + * hash_table->keys_equal and will act as if it always returned + * false. This is useful as a performance optimization in special + * circumstances where the caller knows that there is no existing + * entry in the hash table with a matching key. + * + * Return value: The matching entry in the hash table (if + * any). Otherwise, the first available entry. The caller should check + * entry->state to check whether a match was found or not. + **/ +static cairo_hash_entry_t ** +_cairo_hash_table_lookup_internal (cairo_hash_table_t *hash_table, + cairo_hash_entry_t *key, + cairo_bool_t key_is_unique) +{ + cairo_hash_entry_t **entry, **first_available = NULL; + unsigned long table_size, i, idx, step; + + table_size = hash_table->arrangement->size; + + idx = key->hash % table_size; + step = 0; + + for (i = 0; i < table_size; ++i) + { + entry = &hash_table->entries[idx]; + + if (ENTRY_IS_FREE(*entry)) + { + return entry; + } + else if (ENTRY_IS_DEAD(*entry)) + { + if (key_is_unique) { + return entry; + } else { + if (! first_available) + first_available = entry; + } + } + else /* ENTRY_IS_LIVE(*entry) */ + { + if (! key_is_unique) + if (hash_table->keys_equal (key, *entry)) + return entry; + } + + if (step == 0) { + step = key->hash % hash_table->arrangement->rehash; + if (step == 0) + step = 1; + } + + idx += step; + if (idx >= table_size) + idx -= table_size; + } + + /* + * The table should not have permitted you to get here if you were just + * looking for a free slot: there should have been room. + */ + assert (key_is_unique == 0); + + return first_available; +} + +/** + * _cairo_hash_table_resize: + * @hash_table: a hash table + * + * Resize the hash table if the number of entries has gotten much + * bigger or smaller than the ideal number of entries for the current + * size. + * + * Return value: CAIRO_STATUS_SUCCESS if successful or + * CAIRO_STATUS_NO_MEMORY if out of memory. + **/ +static cairo_status_t +_cairo_hash_table_resize (cairo_hash_table_t *hash_table) +{ + cairo_hash_table_t tmp; + cairo_hash_entry_t **entry; + unsigned long new_size, i; + + /* This keeps the hash table between 25% and 50% full. */ + unsigned long high = hash_table->arrangement->high_water_mark; + unsigned long low = high >> 2; + + if (hash_table->live_entries >= low && hash_table->live_entries <= high) + return CAIRO_STATUS_SUCCESS; + + tmp = *hash_table; + + if (hash_table->live_entries > high) + { + tmp.arrangement = hash_table->arrangement + 1; + /* This code is being abused if we can't make a table big enough. */ + assert (tmp.arrangement - hash_table_arrangements < + NUM_HASH_TABLE_ARRANGEMENTS); + } + else /* hash_table->live_entries < low */ + { + /* Can't shrink if we're at the smallest size */ + if (hash_table->arrangement == &hash_table_arrangements[0]) + return CAIRO_STATUS_SUCCESS; + tmp.arrangement = hash_table->arrangement - 1; + } + + new_size = tmp.arrangement->size; + tmp.entries = calloc (new_size, sizeof (cairo_hash_entry_t*)); + if (tmp.entries == NULL) + return CAIRO_STATUS_NO_MEMORY; + + for (i = 0; i < hash_table->arrangement->size; ++i) { + if (ENTRY_IS_LIVE (hash_table->entries[i])) { + entry = _cairo_hash_table_lookup_internal (&tmp, + hash_table->entries[i], + TRUE); + assert (ENTRY_IS_FREE(*entry)); + *entry = hash_table->entries[i]; + } + } + + free (hash_table->entries); + hash_table->entries = tmp.entries; + hash_table->arrangement = tmp.arrangement; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_hash_table_lookup: + * @hash_table: a hash table + * @key: the key of interest + * @entry_return: pointer for return value. + * + * Performs a lookup in @hash_table looking for an entry which has a + * key that matches @key, (as determined by the keys_equal() function + * passed to _cairo_hash_table_create). + * + * Return value: TRUE if there is an entry in the hash table that + * matches the given key, (which will now be in *entry_return). FALSE + * otherwise, (in which case *entry_return will be NULL). + **/ +cairo_bool_t +_cairo_hash_table_lookup (cairo_hash_table_t *hash_table, + cairo_hash_entry_t *key, + cairo_hash_entry_t **entry_return) +{ + cairo_hash_entry_t **entry; + + /* See if we have an entry in the table already. */ + entry = _cairo_hash_table_lookup_internal (hash_table, key, FALSE); + if (ENTRY_IS_LIVE(*entry)) { + *entry_return = *entry; + return TRUE; + } + + *entry_return = NULL; + return FALSE; +} + +/** + * _cairo_hash_table_random_entry: + * @hash_table: a hash table + * @predicate: a predicate function, or NULL for any entry. + * + * Find a random entry in the hash table satisfying the given + * @predicate. A NULL @predicate is taken as equivalent to a function + * which always returns TRUE, (eg. any entry in the table will do). + * + * We use the same algorithm as the lookup algorithm to walk over the + * entries in the hash table in a pseudo-random order. Walking + * linearly would favor entries following gaps in the hash table. We + * could also call rand() repeatedly, which works well for almost-full + * tables, but degrades when the table is almost empty, or predicate + * returns TRUE for most entries. + * + * Return value: a random live entry or NULL if there are no entries + * that match the given predicate. In particular, if predicate is + * NULL, a NULL return value indicates that the table is empty. + **/ +void * +_cairo_hash_table_random_entry (cairo_hash_table_t *hash_table, + cairo_hash_predicate_func_t predicate) +{ + cairo_hash_entry_t **entry; + unsigned long hash; + unsigned long table_size, i, idx, step; + + table_size = hash_table->arrangement->size; + + hash = rand (); + idx = hash % table_size; + step = 0; + + for (i = 0; i < table_size; ++i) + { + entry = &hash_table->entries[idx]; + + if (ENTRY_IS_LIVE (*entry) && + (predicate == NULL || predicate (*entry))) + { + return *entry; + } + + if (step == 0) { + step = hash % hash_table->arrangement->rehash; + if (step == 0) + step = 1; + } + + idx += step; + if (idx >= table_size) + idx -= table_size; + } + + return NULL; +} + +/** + * _cairo_hash_table_insert: + * @hash_table: a hash table + * @key_and_value: an entry to be inserted + * + * Insert the entry #key_and_value into the hash table. + * + * WARNING: It is a fatal error if an entry exists in the hash table + * with a matching key, (this function will halt). + * + * Instead of using insert to replace an entry, consider just editing + * the entry obtained with _cairo_hash_table_lookup. Or if absolutely + * necessary, use _cairo_hash_table_remove first. + * + * Return value: CAIRO_STATUS_SUCCESS if successful or + * CAIRO_STATUS_NO_MEMORY if insufficient memory is available. + **/ +cairo_status_t +_cairo_hash_table_insert (cairo_hash_table_t *hash_table, + cairo_hash_entry_t *key_and_value) +{ + cairo_status_t status; + cairo_hash_entry_t **entry; + + entry = _cairo_hash_table_lookup_internal (hash_table, + key_and_value, FALSE); + + if (ENTRY_IS_LIVE(*entry)) + { + /* User is being bad, let's crash. */ + ASSERT_NOT_REACHED; + } + + *entry = key_and_value; + hash_table->live_entries++; + + status = _cairo_hash_table_resize (hash_table); + if (status) + return status; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_hash_table_remove: + * @hash_table: a hash table + * @key: key of entry to be removed + * + * Remove an entry from the hash table which has a key that matches + * @key, if any (as determined by the keys_equal() function passed to + * _cairo_hash_table_create). + * + * Return value: CAIRO_STATUS_SUCCESS if successful or + * CAIRO_STATUS_NO_MEMORY if out of memory. + **/ +void +_cairo_hash_table_remove (cairo_hash_table_t *hash_table, + cairo_hash_entry_t *key) +{ + cairo_hash_entry_t **entry; + + entry = _cairo_hash_table_lookup_internal (hash_table, key, FALSE); + if (! ENTRY_IS_LIVE(*entry)) + return; + + *entry = DEAD_ENTRY; + hash_table->live_entries--; + + /* This call _can_ fail, but only in failing to allocate new + * memory to shrink the hash table. It does leave the table in a + * consistent state, and we've already succeeded in removing the + * entry, so we don't examine the failure status of this call. */ + _cairo_hash_table_resize (hash_table); +} + +/** + * _cairo_hash_table_foreach: + * @hash_table: a hash table + * @hash_callback: function to be called for each live entry + * @closure: additional argument to be passed to @hash_callback + * + * Call @hash_callback for each live entry in the hash table, in a + * non-specified order. + **/ +void +_cairo_hash_table_foreach (cairo_hash_table_t *hash_table, + cairo_hash_callback_func_t hash_callback, + void *closure) +{ + unsigned long i; + cairo_hash_entry_t *entry; + + if (hash_table == NULL) + return; + + for (i = 0; i < hash_table->arrangement->size; i++) { + entry = hash_table->entries[i]; + if (ENTRY_IS_LIVE(entry)) + hash_callback (entry, closure); + } +} diff --git a/gfx/cairo/cairo/src/cairo-image-surface.c b/gfx/cairo/cairo/src/cairo-image-surface.c index 19dc7b6114cc..1de9402e5340 100644 --- a/gfx/cairo/cairo/src/cairo-image-surface.c +++ b/gfx/cairo/cairo/src/cairo-image-surface.c @@ -36,8 +36,6 @@ #include "cairoint.h" -static const cairo_surface_backend_t cairo_image_surface_backend; - static int _cairo_format_bpp (cairo_format_t format) { @@ -53,15 +51,17 @@ _cairo_format_bpp (cairo_format_t format) } } -static cairo_image_surface_t * +static cairo_surface_t * _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, cairo_format_t format) { cairo_image_surface_t *surface; surface = malloc (sizeof (cairo_image_surface_t)); - if (surface == NULL) - return NULL; + if (surface == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } _cairo_surface_init (&surface->base, &cairo_image_surface_backend); @@ -69,24 +69,25 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, surface->format = format; surface->data = (unsigned char *) pixman_image_get_data (pixman_image); - surface->owns_data = 0; + surface->owns_data = FALSE; + surface->has_clip = FALSE; surface->width = pixman_image_get_width (pixman_image); surface->height = pixman_image_get_height (pixman_image); surface->stride = pixman_image_get_stride (pixman_image); surface->depth = pixman_image_get_depth (pixman_image); - return surface; + return &surface->base; } -cairo_image_surface_t * +cairo_surface_t * _cairo_image_surface_create_with_masks (unsigned char *data, cairo_format_masks_t *format, int width, int height, int stride) { - cairo_image_surface_t *surface; + cairo_surface_t *surface; pixman_format_t *pixman_format; pixman_image_t *pixman_image; @@ -96,16 +97,20 @@ _cairo_image_surface_create_with_masks (unsigned char *data, format->green_mask, format->blue_mask); - if (pixman_format == NULL) - return NULL; + if (pixman_format == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format, width, height, format->bpp, stride); pixman_format_destroy (pixman_format); - if (pixman_image == NULL) - return NULL; + if (pixman_image == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } surface = _cairo_image_surface_create_for_pixman_image (pixman_image, (cairo_format_t)-1); @@ -152,24 +157,31 @@ cairo_image_surface_create (cairo_format_t format, int width, int height) { - cairo_image_surface_t *surface; + cairo_surface_t *surface; pixman_format_t *pixman_format; pixman_image_t *pixman_image; + if (! CAIRO_FORMAT_VALID (format)) + return (cairo_surface_t*) &_cairo_surface_nil; + pixman_format = _create_pixman_format (format); - if (pixman_format == NULL) - return NULL; + if (pixman_format == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } pixman_image = pixman_image_create (pixman_format, width, height); pixman_format_destroy (pixman_format); - if (pixman_image == NULL) - return NULL; + if (pixman_image == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format); - return &surface->base; + return surface; } /** @@ -201,13 +213,18 @@ cairo_image_surface_create_for_data (unsigned char *data, int height, int stride) { - cairo_image_surface_t *surface; + cairo_surface_t *surface; pixman_format_t *pixman_format; pixman_image_t *pixman_image; + if (! CAIRO_FORMAT_VALID (format)) + return (cairo_surface_t*) &_cairo_surface_nil; + pixman_format = _create_pixman_format (format); - if (pixman_format == NULL) - return NULL; + if (pixman_format == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format, width, height, @@ -216,12 +233,14 @@ cairo_image_surface_create_for_data (unsigned char *data, pixman_format_destroy (pixman_format); - if (pixman_image == NULL) - return NULL; + if (pixman_image == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format); - return &surface->base; + return surface; } /** @@ -237,6 +256,11 @@ cairo_image_surface_get_width (cairo_surface_t *surface) { cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; + if (!_cairo_surface_is_image (surface)) { + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return 0; + } + return image_surface->width; } @@ -253,17 +277,57 @@ cairo_image_surface_get_height (cairo_surface_t *surface) { cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; + if (!_cairo_surface_is_image (surface)) { + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return 0; + } + return image_surface->height; } +cairo_format_t +_cairo_format_from_content (cairo_content_t content) +{ + switch (content) { + case CAIRO_CONTENT_COLOR: + return CAIRO_FORMAT_RGB24; + case CAIRO_CONTENT_ALPHA: + return CAIRO_FORMAT_A8; + case CAIRO_CONTENT_COLOR_ALPHA: + return CAIRO_FORMAT_ARGB32; + } + + ASSERT_NOT_REACHED; + return CAIRO_FORMAT_ARGB32; +} + +cairo_content_t +_cairo_content_from_format (cairo_format_t format) +{ + switch (format) { + case CAIRO_FORMAT_ARGB32: + return CAIRO_CONTENT_COLOR_ALPHA; + case CAIRO_FORMAT_RGB24: + return CAIRO_CONTENT_COLOR; + case CAIRO_FORMAT_A8: + case CAIRO_FORMAT_A1: + return CAIRO_CONTENT_ALPHA; + } + + ASSERT_NOT_REACHED; + return CAIRO_CONTENT_COLOR_ALPHA; +} + static cairo_surface_t * -_cairo_image_surface_create_similar (void *abstract_src, - cairo_format_t format, - int drawable, +_cairo_image_surface_create_similar (void *abstract_src, + cairo_content_t content, int width, int height) { - return cairo_image_surface_create (format, width, height); + assert (CAIRO_CONTENT_VALID (content)); + + return cairo_image_surface_create (_cairo_format_from_content (content), + width, height); } static cairo_status_t @@ -296,6 +360,7 @@ _cairo_image_surface_acquire_source_image (void *abstract_sur void **image_extra) { *image_out = abstract_surface; + *image_extra = NULL; return CAIRO_STATUS_SUCCESS; } @@ -322,7 +387,8 @@ _cairo_image_surface_acquire_dest_image (void *abstract_surfa image_rect_out->height = surface->height; *image_out = surface; - + *image_extra = NULL; + return CAIRO_STATUS_SUCCESS; } @@ -343,8 +409,7 @@ _cairo_image_surface_clone_similar (void *abstract_surface, cairo_image_surface_t *surface = abstract_surface; if (src->backend == surface->base.backend) { - *clone_out = src; - cairo_surface_reference (src); + *clone_out = cairo_surface_reference (src); return CAIRO_STATUS_SUCCESS; } @@ -352,7 +417,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 +440,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 +470,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,41 +583,54 @@ _cairo_image_surface_composite (cairo_operator_t operator, return status; status = _cairo_image_surface_set_attributes (src, &src_attr); - if (CAIRO_OK (status)) - { - if (mask) - { - status = _cairo_image_surface_set_attributes (mask, &mask_attr); - if (CAIRO_OK (status)) - pixman_composite (_pixman_operator (operator), - src->pixman_image, - mask->pixman_image, - dst->pixman_image, - src_x + src_attr.x_offset, - src_y + src_attr.y_offset, - mask_x + mask_attr.x_offset, - mask_y + mask_attr.y_offset, - dst_x, dst_y, - width, height); - } - else - { - pixman_composite (_pixman_operator (operator), - src->pixman_image, - NULL, - dst->pixman_image, - src_x + src_attr.x_offset, - src_y + src_attr.y_offset, - 0, 0, - dst_x, dst_y, - width, height); - } - } + if (status) + goto CLEANUP_SURFACES; if (mask) - _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr); + { + status = _cairo_image_surface_set_attributes (mask, &mask_attr); + if (status) + goto CLEANUP_SURFACES; + + pixman_composite (_pixman_operator (operator), + src->pixman_image, + mask->pixman_image, + dst->pixman_image, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + mask_x + mask_attr.x_offset, + mask_y + mask_attr.y_offset, + dst_x, dst_y, + width, height); + } + else + { + pixman_composite (_pixman_operator (operator), + src->pixman_image, + NULL, + dst->pixman_image, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + 0, 0, + dst_x, dst_y, + width, height); + } - _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr); + if (!_cairo_operator_bounded (operator)) + status = _cairo_surface_composite_fixup_unbounded (&dst->base, + &src_attr, src->width, src->height, + mask ? &mask_attr : NULL, + mask ? mask->width : 0, + mask ? mask->height : 0, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, width, height); + + CLEANUP_SURFACES: + if (mask) + _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr); + + _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr); return status; } @@ -580,10 +658,25 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } +static cairo_bool_t +_cairo_image_surface_is_alpha_only (cairo_image_surface_t *surface) +{ + int bpp, alpha, red, green, blue; + + if (surface->format != (cairo_format_t) -1) + return surface->format == CAIRO_FORMAT_A1 || surface->format == CAIRO_FORMAT_A8; + + pixman_format_get_masks (pixman_image_get_format (surface->pixman_image), + &bpp, &alpha, &red, &green, &blue); + + return red == 0 && blue == 0 && green == 0; +} + static cairo_int_status_t _cairo_image_surface_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, void *abstract_dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, @@ -597,8 +690,35 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t operator, cairo_image_surface_t *dst = abstract_dst; cairo_image_surface_t *src; cairo_int_status_t status; - int render_reference_x, render_reference_y; - int render_src_x, render_src_y; + pixman_image_t *mask; + pixman_format_t *format; + pixman_bits_t *mask_data; + int mask_stride; + int mask_bpp; + + /* Special case adding trapezoids onto a mask surface; we want to avoid + * creating an intermediate temporary mask unecessarily. + * + * We make the assumption here that the portion of the trapezoids + * contained within the surface is bounded by [dst_x,dst_y,width,height]; + * the Cairo core code passes bounds based on the trapezoid extents. + * + * Currently the check surface->has_clip is needed for correct + * functioning, since pixman_add_trapezoids() doesn't obey the + * surface clip, which is a libpixman bug , but there's no harm in + * falling through to the general case when the surface is clipped + * since libpixman would have to generate an intermediate mask anyways. + */ + if (operator == CAIRO_OPERATOR_ADD && + _cairo_pattern_is_opaque_solid (pattern) && + _cairo_image_surface_is_alpha_only (dst) && + !dst->has_clip && + antialias != CAIRO_ANTIALIAS_NONE) + { + pixman_add_trapezoids (dst->pixman_image, 0, 0, + (pixman_trapezoid_t *) traps, num_traps); + return CAIRO_STATUS_SUCCESS; + } status = _cairo_pattern_acquire_surface (pattern, &dst->base, src_x, src_y, width, height, @@ -607,29 +727,72 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t operator, if (status) return status; - if (traps[0].left.p1.y < traps[0].left.p2.y) { - render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x); - render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y); - } else { - render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x); - render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y); + status = _cairo_image_surface_set_attributes (src, &attributes); + if (status) + goto CLEANUP_SOURCE; + + switch (antialias) { + case CAIRO_ANTIALIAS_NONE: + format = pixman_format_create (PIXMAN_FORMAT_NAME_A1); + mask_stride = (width + 31)/8; + mask_bpp = 1; + break; + default: + format = pixman_format_create (PIXMAN_FORMAT_NAME_A8); + mask_stride = (width + 3) & ~3; + mask_bpp = 8; + break; + } + if (!format) { + status = CAIRO_STATUS_NO_MEMORY; + goto CLEANUP_SOURCE; } - render_src_x = src_x + render_reference_x - dst_x; - render_src_y = src_y + render_reference_y - dst_y; + /* The image must be initially transparent */ + mask_data = calloc (1, mask_stride * height); + if (!mask_data) { + status = CAIRO_STATUS_NO_MEMORY; + pixman_format_destroy (format); + goto CLEANUP_SOURCE; + } + + mask = pixman_image_create_for_data (mask_data, format, width, height, + mask_bpp, mask_stride); + pixman_format_destroy (format); + if (!mask) { + status = CAIRO_STATUS_NO_MEMORY; + goto CLEANUP_IMAGE_DATA; + } /* XXX: The pixman_trapezoid_t cast is evil and needs to go away * somehow. */ - status = _cairo_image_surface_set_attributes (src, &attributes); - if (CAIRO_OK (status)) - pixman_composite_trapezoids (_pixman_operator (operator), - src->pixman_image, - dst->pixman_image, - render_src_x + attributes.x_offset, - render_src_y + attributes.y_offset, - (pixman_trapezoid_t *) traps, num_traps); + pixman_add_trapezoids (mask, - dst_x, - dst_y, + (pixman_trapezoid_t *) traps, num_traps); - _cairo_pattern_release_surface (&dst->base, &src->base, &attributes); + pixman_composite (_pixman_operator (operator), + src->pixman_image, + mask, + dst->pixman_image, + src_x + attributes.x_offset, + src_y + attributes.y_offset, + 0, 0, + dst_x, dst_y, + width, height); + + if (!_cairo_operator_bounded (operator)) + status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base, + &attributes, src->width, src->height, + width, height, + src_x, src_y, + 0, 0, + dst_x, dst_y, width, height); + pixman_image_destroy (mask); + + CLEANUP_IMAGE_DATA: + free (mask_data); + + CLEANUP_SOURCE: + _cairo_pattern_release_surface (pattern, &src->base, &attributes); return status; } @@ -647,20 +810,9 @@ cairo_int_status_t _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface, pixman_region16_t *region) { - if (region) { - pixman_region16_t *rcopy; + pixman_image_set_clip_region (surface->pixman_image, region); - rcopy = pixman_region_create(); - /* pixman_image_set_clip_region expects to take ownership of the - * passed-in region, so we create a copy to give it. */ - /* XXX: I think that's probably a bug in pixman. But its - * memory management issues need auditing anyway, so a - * workaround like this is fine for now. */ - pixman_region_copy (rcopy, region); - pixman_image_set_clip_region (surface->pixman_image, rcopy); - } else { - pixman_image_set_clip_region (surface->pixman_image, region); - } + surface->has_clip = region != NULL; return CAIRO_STATUS_SUCCESS; } @@ -692,15 +844,15 @@ _cairo_image_abstract_surface_get_extents (void *abstract_surface, * * Checks if a surface is an #cairo_image_surface_t * - * Return value: True if the surface is an image surface + * Return value: TRUE if the surface is an image surface **/ -int +cairo_bool_t _cairo_surface_is_image (cairo_surface_t *surface) { return surface->backend == &cairo_image_surface_backend; } -static const cairo_surface_backend_t cairo_image_surface_backend = { +const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_create_similar, _cairo_image_abstract_surface_finish, _cairo_image_surface_acquire_source_image, @@ -714,6 +866,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/gfx/cairo/cairo/src/cairo-matrix.c b/gfx/cairo/cairo/src/cairo-matrix.c index 14280c99ab71..7596b0843c6b 100644 --- a/gfx/cairo/cairo/src/cairo-matrix.c +++ b/gfx/cairo/cairo/src/cairo-matrix.c @@ -525,7 +525,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; @@ -558,49 +560,30 @@ _cairo_matrix_compute_scale_factors (const cairo_matrix_t *matrix, return CAIRO_STATUS_SUCCESS; } -/* Compute the min/max expansion factors. See the comment in - * cairo-pen.c for the derivation */ -cairo_status_t -_cairo_matrix_compute_expansion_factors (const cairo_matrix_t *matrix, - double *min, double *max) -{ - double a = matrix->xx, b = matrix->yx; - double c = matrix->xy, d = matrix->yy; - - double i = a*a + c*c; - double j = b*b + d*d; - - double f = 0.5 * (i + j); - double g = 0.5 * (i - j); - double h = a*b + c*d; - - *max = sqrt (f + sqrt (g*g+h*h)); - - *min = sqrt (f - sqrt (g*g+h*h)); - - return CAIRO_STATUS_SUCCESS; -} - 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/gfx/cairo/cairo/src/cairo-meta-surface-private.h b/gfx/cairo/cairo/src/cairo-meta-surface-private.h new file mode 100644 index 000000000000..0a80fe702d91 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-meta-surface-private.h @@ -0,0 +1,155 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Kristian Høgsberg + */ + +#ifndef CAIRO_META_SURFACE_H +#define CAIRO_META_SURFACE_H + +#include "cairoint.h" +#include "cairo-path-fixed-private.h" + +typedef enum { + CAIRO_COMMAND_COMPOSITE, + CAIRO_COMMAND_FILL_RECTANGLES, + CAIRO_COMMAND_COMPOSITE_TRAPEZOIDS, + CAIRO_COMMAND_SET_CLIP_REGION, + CAIRO_COMMAND_INTERSECT_CLIP_PATH, + CAIRO_COMMAND_SHOW_GLYPHS, + CAIRO_COMMAND_FILL_PATH +} cairo_command_type_t; + +typedef struct _cairo_command_composite { + cairo_command_type_t type; + cairo_operator_t operator; + cairo_pattern_union_t src_pattern; + cairo_pattern_union_t mask_pattern; + cairo_pattern_t *mask_pattern_pointer; + int src_x; + int src_y; + int mask_x; + int mask_y; + int dst_x; + int dst_y; + unsigned int width; + unsigned int height; +} cairo_command_composite_t; + +typedef struct _cairo_command_fill_rectangles { + cairo_command_type_t type; + cairo_operator_t operator; + cairo_color_t color; + cairo_rectangle_t *rects; + int num_rects; +} cairo_command_fill_rectangles_t; + +typedef struct _cairo_command_composite_trapezoids { + cairo_command_type_t type; + cairo_operator_t operator; + cairo_pattern_union_t pattern; + cairo_antialias_t antialias; + int x_src; + int y_src; + int x_dst; + int y_dst; + unsigned int width; + unsigned int height; + cairo_trapezoid_t *traps; + int num_traps; +} cairo_command_composite_trapezoids_t; + +typedef struct _cairo_command_set_clip_region { + cairo_command_type_t type; + pixman_region16_t *region; + unsigned int serial; +} cairo_command_set_clip_region_t; + +typedef struct _cairo_command_intersect_clip_path { + cairo_command_type_t type; + cairo_path_fixed_t *path_pointer; + cairo_path_fixed_t path; + cairo_fill_rule_t fill_rule; + double tolerance; + cairo_antialias_t antialias; +} cairo_command_intersect_clip_path_t; + +typedef struct _cairo_command_show_glyphs { + cairo_command_type_t type; + cairo_scaled_font_t *scaled_font; + cairo_operator_t operator; + cairo_pattern_union_t pattern; + int source_x; + int source_y; + int dest_x; + int dest_y; + unsigned int width; + unsigned int height; + cairo_glyph_t *glyphs; + int num_glyphs; +} cairo_command_show_glyphs_t; + +typedef struct _cairo_command_fill_path { + cairo_command_type_t type; + cairo_operator_t operator; + cairo_pattern_union_t pattern; + cairo_path_fixed_t path; + cairo_fill_rule_t fill_rule; + double tolerance; + cairo_antialias_t antialias; +} cairo_command_fill_path_t; + +typedef union _cairo_command { + cairo_command_type_t type; + cairo_command_composite_t composite; + cairo_command_fill_rectangles_t fill_rectangles; + cairo_command_composite_trapezoids_t composite_trapezoids; + cairo_command_set_clip_region_t set_clip_region; + cairo_command_intersect_clip_path_t intersect_clip_path; + cairo_command_show_glyphs_t show_glyphs; + cairo_command_fill_path_t fill_path; +} cairo_command_t; + +typedef struct _cairo_meta_surface { + cairo_surface_t base; + double width, height; + cairo_array_t commands; +} cairo_meta_surface_t; + +cairo_private cairo_surface_t * +_cairo_meta_surface_create (double width, double height); + +cairo_private cairo_int_status_t +_cairo_meta_surface_replay (cairo_surface_t *surface, + cairo_surface_t *target); + +#endif /* CAIRO_META_SURFACE_H */ diff --git a/gfx/cairo/cairo/src/cairo-meta-surface.c b/gfx/cairo/cairo/src/cairo-meta-surface.c new file mode 100644 index 000000000000..f218ae240464 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-meta-surface.c @@ -0,0 +1,592 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Kristian Høgsberg + */ + +#include "cairoint.h" +#include "cairo-meta-surface-private.h" +#include "cairo-gstate-private.h" + +static const cairo_surface_backend_t cairo_meta_surface_backend; + +cairo_surface_t * +_cairo_meta_surface_create (double width, double height) +{ + cairo_meta_surface_t *meta; + + meta = malloc (sizeof (cairo_meta_surface_t)); + if (meta == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } + + meta->width = width; + meta->height = height; + _cairo_surface_init (&meta->base, &cairo_meta_surface_backend); + _cairo_array_init (&meta->commands, sizeof (cairo_command_t *)); + + return &meta->base; +} + +static cairo_surface_t * +_cairo_meta_surface_create_similar (void *abstract_surface, + cairo_content_t content, + int width, + int height) +{ + return _cairo_meta_surface_create (width, height); +} + +static cairo_status_t +_cairo_meta_surface_finish (void *abstract_surface) +{ + cairo_meta_surface_t *meta = abstract_surface; + cairo_command_t *command; + cairo_command_t **elements; + int i, num_elements; + + num_elements = meta->commands.num_elements; + elements = (cairo_command_t **) meta->commands.elements; + for (i = 0; i < num_elements; i++) { + command = elements[i]; + switch (command->type) { + case CAIRO_COMMAND_COMPOSITE: + _cairo_pattern_fini (&command->composite.src_pattern.base); + if (command->composite.mask_pattern_pointer) + _cairo_pattern_fini (command->composite.mask_pattern_pointer); + free (command); + break; + + case CAIRO_COMMAND_FILL_RECTANGLES: + free (command->fill_rectangles.rects); + free (command); + break; + + case CAIRO_COMMAND_COMPOSITE_TRAPEZOIDS: + _cairo_pattern_fini (&command->composite_trapezoids.pattern.base); + free (command->composite_trapezoids.traps); + free (command); + break; + + case CAIRO_COMMAND_INTERSECT_CLIP_PATH: + if (command->intersect_clip_path.path_pointer) + _cairo_path_fixed_fini (&command->intersect_clip_path.path); + free (command); + break; + + case CAIRO_COMMAND_SHOW_GLYPHS: + cairo_scaled_font_destroy (command->show_glyphs.scaled_font); + _cairo_pattern_fini (&command->show_glyphs.pattern.base); + free (command->show_glyphs.glyphs); + free (command); + break; + + case CAIRO_COMMAND_FILL_PATH: + _cairo_pattern_fini (&command->fill_path.pattern.base); + _cairo_path_fixed_fini (&command->fill_path.path); + free (command); + break; + + default: + ASSERT_NOT_REACHED; + } + } + + _cairo_array_fini (&meta->commands); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_meta_surface_composite (cairo_operator_t operator, + cairo_pattern_t *src_pattern, + cairo_pattern_t *mask_pattern, + void *abstract_surface, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_meta_surface_t *meta = abstract_surface; + cairo_command_composite_t *command; + + command = malloc (sizeof (cairo_command_composite_t)); + if (command == NULL) + return CAIRO_STATUS_NO_MEMORY; + + command->type = CAIRO_COMMAND_COMPOSITE; + command->operator = operator; + _cairo_pattern_init_copy (&command->src_pattern.base, src_pattern); + if (mask_pattern) { + _cairo_pattern_init_copy (&command->mask_pattern.base, mask_pattern); + command->mask_pattern_pointer = &command->mask_pattern.base; + } else { + command->mask_pattern_pointer = NULL; + } + + command->src_x = src_x; + command->src_y = src_y; + command->mask_x = mask_x; + command->mask_y = mask_y; + command->dst_x = dst_x; + command->dst_y = dst_y; + command->width = width; + command->height = height; + + if (_cairo_array_append (&meta->commands, &command, 1) == NULL) { + _cairo_pattern_fini (&command->src_pattern.base); + _cairo_pattern_fini (command->mask_pattern_pointer); + free (command); + return CAIRO_STATUS_NO_MEMORY; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_meta_surface_fill_rectangles (void *abstract_surface, + cairo_operator_t operator, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int num_rects) +{ + cairo_meta_surface_t *meta = abstract_surface; + cairo_command_fill_rectangles_t *command; + + command = malloc (sizeof (cairo_command_fill_rectangles_t)); + if (command == NULL) + return CAIRO_STATUS_NO_MEMORY; + + command->type = CAIRO_COMMAND_FILL_RECTANGLES; + command->operator = operator; + command->color = *color; + + command->rects = malloc (sizeof (cairo_rectangle_t) * num_rects); + if (command->rects == NULL) { + free (command); + return CAIRO_STATUS_NO_MEMORY; + } + memcpy (command->rects, rects, sizeof (cairo_rectangle_t) * num_rects); + + command->num_rects = num_rects; + + if (_cairo_array_append (&meta->commands, &command, 1) == NULL) { + free (command->rects); + free (command); + return CAIRO_STATUS_NO_MEMORY; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_meta_surface_composite_trapezoids (cairo_operator_t operator, + cairo_pattern_t *pattern, + void *abstract_surface, + cairo_antialias_t antialias, + int x_src, + int y_src, + int x_dst, + int y_dst, + unsigned int width, + unsigned int height, + cairo_trapezoid_t *traps, + int num_traps) +{ + cairo_meta_surface_t *meta = abstract_surface; + cairo_command_composite_trapezoids_t *command; + + command = malloc (sizeof (cairo_command_composite_trapezoids_t)); + if (command == NULL) + return CAIRO_STATUS_NO_MEMORY; + + command->type = CAIRO_COMMAND_COMPOSITE_TRAPEZOIDS; + command->operator = operator; + _cairo_pattern_init_copy (&command->pattern.base, pattern); + command->antialias = antialias; + command->x_src = x_src; + command->y_src = y_src; + command->x_dst = x_dst; + command->y_dst = y_dst; + command->width = width; + command->height = height; + + command->traps = malloc (sizeof (cairo_trapezoid_t) * num_traps); + if (command->traps == NULL) { + _cairo_pattern_fini (&command->pattern.base); + free (command); + return CAIRO_STATUS_NO_MEMORY; + } + memcpy (command->traps, traps, sizeof (cairo_trapezoid_t) * num_traps); + + command->num_traps = num_traps; + + if (_cairo_array_append (&meta->commands, &command, 1) == NULL) { + _cairo_pattern_fini (&command->pattern.base); + free (command->traps); + free (command); + return CAIRO_STATUS_NO_MEMORY; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_meta_surface_intersect_clip_path (void *dst, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_meta_surface_t *meta = dst; + cairo_command_intersect_clip_path_t *command; + cairo_status_t status; + + command = malloc (sizeof (cairo_command_intersect_clip_path_t)); + if (command == NULL) + return CAIRO_STATUS_NO_MEMORY; + + command->type = CAIRO_COMMAND_INTERSECT_CLIP_PATH; + + if (path) { + status = _cairo_path_fixed_init_copy (&command->path, path); + if (status) { + free (command); + return status; + } + command->path_pointer = &command->path; + } else { + command->path_pointer = NULL; + } + command->fill_rule = fill_rule; + command->tolerance = tolerance; + command->antialias = antialias; + + if (_cairo_array_append (&meta->commands, &command, 1) == NULL) { + if (path) + _cairo_path_fixed_fini (&command->path); + free (command); + return CAIRO_STATUS_NO_MEMORY; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_meta_surface_get_extents (void *abstract_surface, + cairo_rectangle_t *rectangle) +{ + cairo_meta_surface_t *meta = abstract_surface; + + /* Currently this is used for getting the extents of the surface + * before calling cairo_paint(). This is the only this that + * requires the meta surface to have an explicit size. If paint + * was just a backend function, this would not be necessary. */ + + rectangle->x = 0; + rectangle->y = 0; + rectangle->width = meta->width; + rectangle->height = meta->height; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_meta_surface_show_glyphs (cairo_scaled_font_t *scaled_font, + cairo_operator_t operator, + cairo_pattern_t *pattern, + void *abstract_surface, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, + const cairo_glyph_t *glyphs, + int num_glyphs) +{ + cairo_meta_surface_t *meta = abstract_surface; + cairo_command_show_glyphs_t *command; + + command = malloc (sizeof (cairo_command_show_glyphs_t)); + if (command == NULL) + return CAIRO_STATUS_NO_MEMORY; + + command->type = CAIRO_COMMAND_SHOW_GLYPHS; + command->scaled_font = cairo_scaled_font_reference (scaled_font); + command->operator = operator; + _cairo_pattern_init_copy (&command->pattern.base, pattern); + command->source_x = source_x; + command->source_y = source_y; + command->dest_x = dest_x; + command->dest_y = dest_y; + command->width = width; + command->height = height; + + command->glyphs = malloc (sizeof (cairo_glyph_t) * num_glyphs); + if (command->glyphs == NULL) { + _cairo_pattern_fini (&command->pattern.base); + free (command); + return CAIRO_STATUS_NO_MEMORY; + } + memcpy (command->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs); + + command->num_glyphs = num_glyphs; + + if (_cairo_array_append (&meta->commands, &command, 1) == NULL) { + _cairo_pattern_fini (&command->pattern.base); + free (command->glyphs); + free (command); + return CAIRO_STATUS_NO_MEMORY; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_meta_surface_fill_path (cairo_operator_t operator, + cairo_pattern_t *pattern, + void *abstract_surface, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance) +{ + cairo_meta_surface_t *meta = abstract_surface; + cairo_command_fill_path_t *command; + cairo_status_t status; + + command = malloc (sizeof (cairo_command_fill_path_t)); + if (command == NULL) + return CAIRO_STATUS_NO_MEMORY; + + command->type = CAIRO_COMMAND_FILL_PATH; + command->operator = operator; + _cairo_pattern_init_copy (&command->pattern.base, pattern); + status = _cairo_path_fixed_init_copy (&command->path, path); + if (status) { + _cairo_pattern_fini (&command->pattern.base); + free (command); + return CAIRO_STATUS_NO_MEMORY; + } + command->fill_rule = fill_rule; + command->tolerance = tolerance; + + if (_cairo_array_append (&meta->commands, &command, 1) == NULL) { + _cairo_path_fixed_fini (&command->path); + _cairo_pattern_fini (&command->pattern.base); + free (command); + return CAIRO_STATUS_NO_MEMORY; + } + + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_surface_backend_t cairo_meta_surface_backend = { + _cairo_meta_surface_create_similar, + _cairo_meta_surface_finish, + NULL, /* acquire_source_image */ + NULL, /* release_source_image */ + NULL, /* acquire_dest_image */ + NULL, /* release_dest_image */ + NULL, /* clone_similar */ + _cairo_meta_surface_composite, + _cairo_meta_surface_fill_rectangles, + _cairo_meta_surface_composite_trapezoids, + NULL, /* copy_page */ + NULL, /* show_page */ + NULL, /* set_clip_region */ + _cairo_meta_surface_intersect_clip_path, + _cairo_meta_surface_get_extents, + _cairo_meta_surface_show_glyphs, + _cairo_meta_surface_fill_path, +}; + +cairo_int_status_t +_cairo_meta_surface_replay (cairo_surface_t *surface, + cairo_surface_t *target) +{ + cairo_meta_surface_t *meta; + cairo_command_t *command, **elements; + int i, num_elements; + cairo_int_status_t status; + cairo_traps_t traps; + cairo_clip_t clip; + + meta = (cairo_meta_surface_t *) surface; + status = CAIRO_STATUS_SUCCESS; + + _cairo_clip_init (&clip, target); + + num_elements = meta->commands.num_elements; + elements = (cairo_command_t **) meta->commands.elements; + for (i = 0; i < num_elements; i++) { + command = elements[i]; + switch (command->type) { + case CAIRO_COMMAND_COMPOSITE: + status = _cairo_surface_set_clip (target, &clip); + if (status) + break; + + status = _cairo_surface_composite + (command->composite.operator, + &command->composite.src_pattern.base, + command->composite.mask_pattern_pointer, + target, + command->composite.src_x, + command->composite.src_y, + command->composite.mask_x, + command->composite.mask_y, + command->composite.dst_x, + command->composite.dst_y, + command->composite.width, + command->composite.height); + break; + + case CAIRO_COMMAND_FILL_RECTANGLES: + status = _cairo_surface_set_clip (target, &clip); + if (status) + break; + + status = _cairo_surface_fill_rectangles + (target, + command->fill_rectangles.operator, + &command->fill_rectangles.color, + command->fill_rectangles.rects, + command->fill_rectangles.num_rects); + break; + + case CAIRO_COMMAND_COMPOSITE_TRAPEZOIDS: + status = _cairo_surface_set_clip (target, &clip); + if (status) + break; + + status = _cairo_surface_composite_trapezoids + (command->composite_trapezoids.operator, + &command->composite_trapezoids.pattern.base, + target, + command->composite_trapezoids.antialias, + command->composite_trapezoids.x_src, + command->composite_trapezoids.y_src, + command->composite_trapezoids.x_dst, + command->composite_trapezoids.y_dst, + command->composite_trapezoids.width, + command->composite_trapezoids.height, + command->composite_trapezoids.traps, + command->composite_trapezoids.num_traps); + break; + + case CAIRO_COMMAND_INTERSECT_CLIP_PATH: + /* XXX Meta surface clipping is broken and requires some + * cairo-gstate.c rewriting. Work around it for now. */ + if (command->intersect_clip_path.path_pointer == NULL) + status = _cairo_clip_reset (&clip); + else + status = _cairo_clip_clip (&clip, + command->intersect_clip_path.path_pointer, + command->intersect_clip_path.fill_rule, + command->intersect_clip_path.tolerance, + command->intersect_clip_path.antialias, + target); + break; + + case CAIRO_COMMAND_SHOW_GLYPHS: + status = _cairo_surface_set_clip (target, &clip); + if (status) + break; + + status = _cairo_surface_show_glyphs + (command->show_glyphs.scaled_font, + command->show_glyphs.operator, + &command->show_glyphs.pattern.base, + target, + command->show_glyphs.source_x, + command->show_glyphs.source_y, + command->show_glyphs.dest_x, + command->show_glyphs.dest_y, + command->show_glyphs.width, + command->show_glyphs.height, + command->show_glyphs.glyphs, + command->show_glyphs.num_glyphs); + break; + + case CAIRO_COMMAND_FILL_PATH: + status = _cairo_surface_set_clip (target, &clip); + if (status) + break; + + status = _cairo_surface_fill_path (command->fill_path.operator, + &command->fill_path.pattern.base, + target, + &command->fill_path.path, + command->fill_path.fill_rule, + command->fill_path.tolerance); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + break; + + _cairo_traps_init (&traps); + + status = _cairo_path_fixed_fill_to_traps (&command->fill_path.path, + command->fill_path.fill_rule, + command->fill_path.tolerance, + &traps); + if (status) { + _cairo_traps_fini (&traps); + break; + } + + status = _cairo_surface_clip_and_composite_trapezoids (&command->fill_path.pattern.base, + command->fill_path.operator, + target, + &traps, + &clip, + command->fill_path.antialias); + + _cairo_traps_fini (&traps); + break; + + default: + ASSERT_NOT_REACHED; + } + + if (status) + break; + } + + _cairo_clip_fini (&clip); + + return status; +} diff --git a/gfx/cairo/cairo/src/cairo-output-stream.c b/gfx/cairo/cairo/src/cairo-output-stream.c index 14b4486a6d3d..afb4d428d971 100644 --- a/gfx/cairo/cairo/src/cairo-output-stream.c +++ b/gfx/cairo/cairo/src/cairo-output-stream.c @@ -39,6 +39,10 @@ #include #include "cairoint.h" +#ifdef _MSC_VER +#define snprintf _snprintf +#endif /* _MSC_VER */ + struct _cairo_output_stream { cairo_write_func_t write_data; void *closure; @@ -90,6 +94,26 @@ _cairo_output_stream_write (cairo_output_stream_t *stream, return stream->status; } +void +_cairo_output_stream_write_hex_string (cairo_output_stream_t *stream, + const char *data, + size_t length) +{ + const char hex_chars[] = "0123456789abcdef"; + char buffer[2]; + int i, column; + + for (i = 0, column = 0; i < length; i++, column++) { + if (column == 38) { + _cairo_output_stream_write (stream, "\n", 1); + column = 0; + } + buffer[0] = hex_chars[(data[i] >> 4) & 0x0f]; + buffer[1] = hex_chars[data[i] & 0x0f]; + _cairo_output_stream_write (stream, buffer, 2); + } +} + /* Format a double in a locale independent way and trim trailing * zeros. Based on code from Alex Larson . * http://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html @@ -187,8 +211,8 @@ _cairo_output_stream_vprintf (cairo_output_stream_t *stream, switch (*f | length_modifier) { case '%': - p[0] = *f; - p[1] = 0; + buffer[0] = *f; + buffer[1] = 0; break; case 'd': snprintf (buffer, sizeof buffer, "%d", va_arg (ap, int)); @@ -211,6 +235,10 @@ _cairo_output_stream_vprintf (cairo_output_stream_t *stream, case 'f': dtostr (buffer, sizeof buffer, va_arg (ap, double)); break; + case 'c': + buffer[0] = va_arg (ap, int); + buffer[1] = 0; + break; default: ASSERT_NOT_REACHED; } diff --git a/gfx/cairo/cairo/src/cairo-path-data-private.h b/gfx/cairo/cairo/src/cairo-path-data-private.h index e47eaaef95b2..3208bc1debda 100644 --- a/gfx/cairo/cairo/src/cairo-path-data-private.h +++ b/gfx/cairo/cairo/src/cairo-path-data-private.h @@ -38,17 +38,17 @@ #include "cairoint.h" -extern cairo_path_t _cairo_path_nil; +extern const cairo_private 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_status_t _cairo_path_data_append_to_context (cairo_path_t *path, cairo_t *cr); diff --git a/gfx/cairo/cairo/src/cairo-path-data.c b/gfx/cairo/cairo/src/cairo-path-data.c index 95fc3bb2634a..e72e0738cbdf 100644 --- a/gfx/cairo/cairo/src/cairo-path-data.c +++ b/gfx/cairo/cairo/src/cairo-path-data.c @@ -37,8 +37,7 @@ #include "cairo-path-fixed-private.h" #include "cairo-gstate-private.h" -cairo_path_t -_cairo_path_nil = { NULL, 0 }; +const cairo_path_t _cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 }; /* Closure for path interpretation. */ typedef struct cairo_path_data_count { @@ -105,14 +104,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 +279,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 +346,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_t*) &_cairo_path_nil; path->num_data = _cairo_path_data_count (path, path_fixed, gstate->tolerance, flatten); @@ -347,23 +354,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_t*) &_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 +411,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 +433,16 @@ _cairo_path_data_create_flat (cairo_path_fixed_t *path, return _cairo_path_data_create_real (path, gstate, TRUE); } +/** + * _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) @@ -389,29 +454,29 @@ _cairo_path_data_append_to_context (cairo_path_t *path, p = &path->data[i]; switch (p->header.type) { case CAIRO_PATH_MOVE_TO: + if (p->header.length != 2) + return CAIRO_STATUS_INVALID_PATH_DATA; cairo_move_to (cr, p[1].point.x, p[1].point.y); - if (p->header.length != 2) - return CAIRO_STATUS_INVALID_PATH_DATA; break; case CAIRO_PATH_LINE_TO: - cairo_line_to (cr, - p[1].point.x, p[1].point.y); if (p->header.length != 2) return CAIRO_STATUS_INVALID_PATH_DATA; + cairo_line_to (cr, + p[1].point.x, p[1].point.y); break; case CAIRO_PATH_CURVE_TO: + if (p->header.length != 4) + return CAIRO_STATUS_INVALID_PATH_DATA; cairo_curve_to (cr, p[1].point.x, p[1].point.y, p[2].point.x, p[2].point.y, p[3].point.x, p[3].point.y); - if (p->header.length != 4) - return CAIRO_STATUS_INVALID_PATH_DATA; break; case CAIRO_PATH_CLOSE_PATH: - cairo_close_path (cr); if (p->header.length != 1) return CAIRO_STATUS_INVALID_PATH_DATA; + cairo_close_path (cr); break; default: return CAIRO_STATUS_INVALID_PATH_DATA; diff --git a/gfx/cairo/cairo/src/cairo-path-fill.c b/gfx/cairo/cairo/src/cairo-path-fill.c index c0015fc969b6..31b83ade3d77 100644 --- a/gfx/cairo/cairo/src/cairo-path-fill.c +++ b/gfx/cairo/cairo/src/cairo-path-fill.c @@ -36,10 +36,8 @@ #include "cairoint.h" -#include "cairo-gstate-private.h" - typedef struct cairo_filler { - cairo_gstate_t *gstate; + double tolerance; cairo_traps_t *traps; cairo_point_t current_point; @@ -48,7 +46,7 @@ typedef struct cairo_filler { } cairo_filler_t; static void -_cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_t *traps); +_cairo_filler_init (cairo_filler_t *filler, double tolerance, cairo_traps_t *traps); static void _cairo_filler_fini (cairo_filler_t *filler); @@ -69,9 +67,9 @@ static cairo_status_t _cairo_filler_close_path (void *closure); static void -_cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_t *traps) +_cairo_filler_init (cairo_filler_t *filler, double tolerance, cairo_traps_t *traps) { - filler->gstate = gstate; + filler->tolerance = tolerance; filler->traps = traps; filler->current_point.x = 0; @@ -132,7 +130,6 @@ _cairo_filler_curve_to (void *closure, cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_filler_t *filler = closure; cairo_polygon_t *polygon = &filler->polygon; - cairo_gstate_t *gstate = filler->gstate; cairo_spline_t spline; status = _cairo_spline_init (&spline, &filler->current_point, b, c, d); @@ -140,7 +137,7 @@ _cairo_filler_curve_to (void *closure, if (status == CAIRO_INT_STATUS_DEGENERATE) return CAIRO_STATUS_SUCCESS; - _cairo_spline_decompose (&spline, gstate->tolerance); + _cairo_spline_decompose (&spline, filler->tolerance); if (status) goto CLEANUP_SPLINE; @@ -174,13 +171,14 @@ _cairo_filler_close_path (void *closure) cairo_status_t _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path, - cairo_gstate_t *gstate, + cairo_fill_rule_t fill_rule, + double tolerance, cairo_traps_t *traps) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_filler_t filler; - _cairo_filler_init (&filler, gstate, traps); + _cairo_filler_init (&filler, tolerance, traps); status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD, @@ -198,7 +196,7 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path, status = _cairo_traps_tessellate_polygon (filler.traps, &filler.polygon, - filler.gstate->fill_rule); + fill_rule); if (status) goto BAIL; diff --git a/gfx/cairo/cairo/src/cairo-pattern.c b/gfx/cairo/cairo/src/cairo-pattern.c index 1746b6b2af20..82b409b6c187 100644 --- a/gfx/cairo/cairo/src/cairo-pattern.c +++ b/gfx/cairo/cairo/src/cairo-pattern.c @@ -50,20 +50,92 @@ typedef struct _cairo_shader_op { ((unsigned char) \ ((((unsigned char) (c1)) * (int) ((unsigned char) (c2))) / 0xff)) +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 */ +}; + +/** + * _cairo_pattern_set_error: + * @pattern: a pattern + * @status: a status value indicating an error, (eg. not + * CAIRO_STATUS_SUCCESS) + * + * Sets pattern->status to @status and calls _cairo_error; + * + * All assignments of an error status to pattern->status should happen + * through _cairo_pattern_set_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. + **/ +static void +_cairo_pattern_set_error (cairo_pattern_t *pattern, + cairo_status_t status) +{ + pattern->status = status; + + _cairo_error (status); +} + 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) { @@ -80,21 +152,28 @@ _cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern, *dst = *src; } + if (other->base.status) + _cairo_pattern_set_error (&pattern->base, other->base.status); + 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 == NULL) { + 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 +193,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 @@ -162,8 +236,7 @@ _cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern, { _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SURFACE); - pattern->surface = surface; - cairo_surface_reference (surface); + pattern->surface = cairo_surface_reference (surface); } static void @@ -210,47 +283,195 @@ _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_rgb: + * @red: red component of the color + * @green: green component of the color + * @blue: blue component of the color + * + * Creates a new cairo_pattern_t corresponding to an opaque color. The + * color components are floating point numbers in the range 0 to 1. + * If the values passed in are outside that range, they will be + * clamped. + * + * Return value: the newly created #cairo_pattern_t if succesful, or + * an error pattern in case of no memory. The caller owns the + * returned object and should call cairo_pattern_destroy() when + * finished with it. + * + * This function will always return a valid pointer, but if an error + * occurred the pattern status will be set to an error. To inspect + * the status of a pattern use cairo_pattern_status(). + **/ +cairo_pattern_t * +cairo_pattern_create_rgb (double red, double green, double blue) +{ + cairo_pattern_t *pattern; + cairo_color_t color; + + _cairo_restrict_value (&red, 0.0, 1.0); + _cairo_restrict_value (&green, 0.0, 1.0); + _cairo_restrict_value (&blue, 0.0, 1.0); + + _cairo_color_init_rgb (&color, red, green, blue); + + pattern = _cairo_pattern_create_solid (&color); + if (pattern->status) + _cairo_pattern_set_error (pattern, pattern->status); + + return pattern; +} + +/** + * cairo_pattern_create_rgba: + * @red: red component of the color + * @green: green component of the color + * @blue: blue component of the color + * @alpha: alpha component of the color + * + * Creates a new cairo_pattern_t corresponding to a translucent color. + * The color components are floating point numbers in the range 0 to + * 1. If the values passed in are outside that range, they will be + * clamped. + * + * Return value: the newly created #cairo_pattern_t if succesful, or + * an error pattern in case of no memory. The caller owns the + * returned object and should call cairo_pattern_destroy() when + * finished with it. + * + * This function will always return a valid pointer, but if an error + * occurred the pattern status will be set to an error. To inspect + * the status of a pattern use cairo_pattern_status(). + **/ +cairo_pattern_t * +cairo_pattern_create_rgba (double red, double green, double blue, + double alpha) +{ + cairo_pattern_t *pattern; + cairo_color_t color; + + _cairo_restrict_value (&red, 0.0, 1.0); + _cairo_restrict_value (&green, 0.0, 1.0); + _cairo_restrict_value (&blue, 0.0, 1.0); + _cairo_restrict_value (&alpha, 0.0, 1.0); + + _cairo_color_init_rgba (&color, red, green, blue, alpha); + + pattern = _cairo_pattern_create_solid (&color); + if (pattern->status) + _cairo_pattern_set_error (pattern, pattern->status); + + return pattern; +} + +/** + * cairo_pattern_create_for_surface: + * @surface: the surface + * + * Create a new cairo_pattern_t for the given surface. + * + * Return value: the newly created #cairo_pattern_t if succesful, or + * an error pattern in case of no memory. The caller owns the + * returned object and should call cairo_pattern_destroy() when + * finished with it. + * + * This function will always return a valid pointer, but if an error + * occurred the pattern status will be set to an error. To inspect + * the status of a pattern use cairo_pattern_status(). + **/ cairo_pattern_t * cairo_pattern_create_for_surface (cairo_surface_t *surface) { cairo_surface_pattern_t *pattern; pattern = malloc (sizeof (cairo_surface_pattern_t)); - if (pattern == NULL) - return NULL; + if (pattern == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + 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; } +/** + * cairo_pattern_create_linear: + * @x0: x coordinate of the start point + * @y0: y coordinate of the start point + * @x1: x coordinate of the end point + * @y1: y coordinate of the end point + * + * Create a new linear gradient cairo_pattern_t along the line defined + * by (x0, y0) and (x1, y1). Before using the gradient pattern, a + * number of color stops should be defined using + * cairo_pattern_add_color_stop_rgb() or + * cairo_pattern_add_color_stop_rgba(). + * + * Note: The coordinates here are in pattern space. For a new pattern, + * pattern space is identical to user space, but the relationship + * between the spaces can be changed with cairo_pattern_set_matrix(). + * + * Return value: the newly created #cairo_pattern_t if succesful, or + * an error pattern in case of no memory. The caller owns the + * returned object and should call cairo_pattern_destroy() when + * finished with it. + * + * This function will always return a valid pointer, but if an error + * occurred the pattern status will be set to an error. To inspect + * the status of a pattern use cairo_pattern_status(). + **/ cairo_pattern_t * cairo_pattern_create_linear (double x0, double y0, double x1, double y1) { cairo_linear_pattern_t *pattern; pattern = malloc (sizeof (cairo_linear_pattern_t)); - if (pattern == NULL) - return NULL; + if (pattern == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_pattern_t *) &cairo_linear_pattern_nil.base; + } _cairo_pattern_init_linear (pattern, x0, y0, x1, y1); return &pattern->base.base; } +/** + * cairo_pattern_create_radial: + * @cx0: x coordinate for the center of the start circle + * @cy0: y coordinate for the center of the start circle + * @radius0: radius of the start cirle + * @cx1: x coordinate for the center of the end circle + * @cy1: y coordinate for the center of the end circle + * @radius1: radius of the end cirle + * + * Creates a new radial gradient cairo_pattern_t between the two + * circles defined by (x0, y0, c0) and (x1, y1, c0). Before using the + * gradient pattern, a number of color stops should be defined using + * cairo_pattern_add_color_stop_rgb() or + * cairo_pattern_add_color_stop_rgba(). + * + * Note: The coordinates here are in pattern space. For a new pattern, + * pattern space is identical to user space, but the relationship + * between the spaces can be changed with cairo_pattern_set_matrix(). + * + * Return value: the newly created #cairo_pattern_t if succesful, or + * an error pattern in case of no memory. The caller owns the + * returned object and should call cairo_pattern_destroy() when + * finished with it. + * + * This function will always return a valid pointer, but if an error + * occurred the pattern status will be set to an error. To inspect + * the status of a pattern use cairo_pattern_status(). + **/ cairo_pattern_t * cairo_pattern_create_radial (double cx0, double cy0, double radius0, double cx1, double cy1, double radius1) @@ -258,29 +479,73 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0, cairo_radial_pattern_t *pattern; pattern = malloc (sizeof (cairo_radial_pattern_t)); - if (pattern == NULL) - return NULL; + if (pattern == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_pattern_t *) &cairo_radial_pattern_nil.base; + } _cairo_pattern_init_radial (pattern, cx0, cy0, radius0, cx1, cy1, radius1); return &pattern->base.base; } -void +/** + * cairo_pattern_reference: + * @pattern: a #cairo_pattern_t + * + * Increases the reference count on @pattern by one. This prevents + * @pattern from being destroyed until a matching call to + * cairo_pattern_destroy() is made. + * + * Return value: the referenced #cairo_pattern_t. + **/ +cairo_pattern_t * cairo_pattern_reference (cairo_pattern_t *pattern) { if (pattern == NULL) - return; + return NULL; + + if (pattern->ref_count == (unsigned int)-1) + return pattern; pattern->ref_count++; + + return pattern; } +/** + * cairo_pattern_status: + * @pattern: a #cairo_pattern_t + * + * Checks whether an error has previously occurred for this + * pattern. + * + * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NO_MEMORY, or + * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. + **/ +cairo_status_t +cairo_pattern_status (cairo_pattern_t *pattern) +{ + return pattern->status; +} + +/** + * cairo_pattern_destroy: + * @pattern: a #cairo_pattern_t + * + * Decreases the reference count on @pattern by one. If the result is + * zero, then @pattern and all associated resources are freed. See + * cairo_pattern_reference(). + **/ 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 +554,51 @@ 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) { + _cairo_pattern_set_error (&pattern->base, 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 +/** + * cairo_pattern_add_color_stop_rgb: + * @pattern: a #cairo_pattern_t + * @offset: an offset in the range [0.0 .. 1.0] + * @red: red component of color + * @green: green component of color + * @blue: blue component of color + * + * Adds an opaque color stop to a gradient pattern. The offset + * specifies the location along the gradient's control vector. For + * example, a linear gradient's control vector is from (x0,y0) to + * (x1,y1) while a radial gradient's control vector is from any point + * on the start circle to the corresponding point on the end circle. + * + * The color is specified in the same way as in cairo_set_source_rgb(). + * + * Note: If the pattern is not a gradient pattern, (eg. a linear or + * radial pattern), then the pattern will be put into an error status + * with a status of CAIRO_STATUS_PATTERN_MISMATCH. + **/ +void cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, double offset, double red, @@ -322,11 +607,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; + _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + return; } _cairo_restrict_value (&offset, 0.0, 1.0); @@ -335,12 +623,33 @@ 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 +/** + * cairo_pattern_add_color_stop_rgba: + * @pattern: a #cairo_pattern_t + * @offset: an offset in the range [0.0 .. 1.0] + * @red: red component of color + * @green: green component of color + * @blue: blue component of color + * @alpha: alpha component of color + * + * Adds a translucent color stop to a gradient pattern. The offset + * specifies the location along the gradient's control vector. For + * example, a linear gradient's control vector is from (x0,y0) to + * (x1,y1) while a radial gradient's control vector is from any point + * on the start circle to the corresponding point on the end circle. + * + * The color is specified in the same way as in cairo_set_source_rgba(). + * + * Note: If the pattern is not a gradient pattern, (eg. a linear or + * radial pattern), then the pattern will be put into an error status + * with a status of CAIRO_STATUS_PATTERN_MISMATCH. + */ +void cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, double offset, double red, @@ -350,11 +659,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; + _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + return; } _cairo_restrict_value (&offset, 0.0, 1.0); @@ -364,34 +676,77 @@ 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 +/** + * cairo_pattern_set_matrix: + * @pattern: a #cairo_pattern_t + * @matrix: a #cairo_matrix_t + * + * Sets the pattern's transformation matrix to @matrix. This matrix is + * a transformation from user space to pattern space. + * + * When a pattern is first created it always has the identity matrix + * for its transformation matrix, which means that pattern space is + * initially identical to user space. + * + * Important: Please note that the direction of this transformation + * matrix is from user space to pattern space. This means that if you + * imagine the flow from a pattern to user space (and on to device + * space), then coordinates in that flow will be transformed by the + * inverse of the pattern matrix. + * + * For example, if you want to make a pattern appear twice as large as + * it does by default the correct code to use is: + * + * + * cairo_matrix_init_scale (&matrix, 0.5, 0.5); + * cairo_pattern_set_matrix (pattern, &matrix); + * + * + * Meanwhile, using values of 2.0 rather than 0.5 in the code above + * would cause the pattern to appear at half of its default size. + * + * Also, please note the discussion of the user-space locking + * semantics of cairo_set_source(). + **/ +void cairo_pattern_set_matrix (cairo_pattern_t *pattern, const cairo_matrix_t *matrix) { - pattern->matrix = *matrix; + if (pattern->status) { + _cairo_pattern_set_error (pattern, pattern->status); + return; + } - return CAIRO_STATUS_SUCCESS; + pattern->matrix = *matrix; } -cairo_status_t +/** + * cairo_pattern_get_matrix: + * @pattern: a #cairo_pattern_t + * @matrix: return value for the matrix + * + * Stores the pattern's transformation matrix into @matrix. + **/ +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) { + _cairo_pattern_set_error (pattern, pattern->status); + return; + } - return CAIRO_STATUS_SUCCESS; + pattern->filter = filter; } cairo_filter_t @@ -400,12 +755,15 @@ 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) { + _cairo_pattern_set_error (pattern, pattern->status); + return; + } - return CAIRO_STATUS_SUCCESS; + pattern->extend = extend; } cairo_extend_t @@ -418,6 +776,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 +1228,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++); @@ -914,7 +1275,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern, } data = malloc (width * height * 4); - if (!data) + if (data == NULL) return CAIRO_STATUS_NO_MEMORY; if (pattern->base.type == CAIRO_PATTERN_LINEAR) @@ -943,7 +1304,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern, width, height, width * 4); - if (image == NULL) { + if (image->base.status) { free (data); return CAIRO_STATUS_NO_MEMORY; } @@ -960,7 +1321,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; } @@ -976,11 +1336,10 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern, cairo_surface_attributes_t *attribs) { *out = _cairo_surface_create_similar_solid (dst, - CAIRO_FORMAT_ARGB32, + CAIRO_CONTENT_COLOR_ALPHA, 1, 1, &pattern->color); - - if (*out == NULL) + if ((*out)->status) return CAIRO_STATUS_NO_MEMORY; attribs->x_offset = attribs->y_offset = 0; @@ -988,7 +1347,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 +1373,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 +1390,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 +1457,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 +1493,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,43 +1513,37 @@ _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; } /** * _cairo_pattern_release_surface: * @pattern: a #cairo_pattern_t - * @info: pointer to #cairo_surface_attributes_t filled in by - * _cairo_pattern_acquire_surface + * @surface: a surface obtained by _cairo_pattern_acquire_surface + * @attributes: attributes obtained by _cairo_pattern_acquire_surface * * Releases resources obtained by _cairo_pattern_acquire_surface. **/ void -_cairo_pattern_release_surface (cairo_surface_t *dst, +_cairo_pattern_release_surface (cairo_pattern_t *pattern, 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_surface_pattern_t *surface_pattern; + + assert (pattern->type == CAIRO_PATTERN_SURFACE); + surface_pattern = (cairo_surface_pattern_t *) pattern; + + _cairo_surface_release_source_image (surface_pattern->surface, (cairo_image_surface_t *) surface, attributes->extra); - } else + } + else + { cairo_surface_destroy (surface); + } } cairo_int_status_t @@ -1217,7 +1562,12 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src, cairo_surface_attributes_t *mask_attributes) { cairo_int_status_t status; - cairo_pattern_union_t tmp; + cairo_pattern_union_t src_tmp, mask_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 +1577,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; @@ -1235,44 +1585,44 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src, combined = src_solid->color; _cairo_color_multiply_alpha (&combined, mask_solid->color.alpha); - _cairo_pattern_init_solid (&tmp.solid, &combined); + _cairo_pattern_init_solid (&src_tmp.solid, &combined); mask = NULL; - } else { - _cairo_pattern_init_copy (&tmp.base, src); - } - - status = _cairo_pattern_acquire_surface (&tmp.base, dst, - src_x, src_y, - width, height, - src_out, src_attributes); - - _cairo_pattern_fini (&tmp.base); - - if (status) - return status; - - if (mask) - { - _cairo_pattern_init_copy (&tmp.base, mask); - - status = _cairo_pattern_acquire_surface (&tmp.base, dst, - mask_x, mask_y, - width, height, - mask_out, mask_attributes); - - _cairo_pattern_fini (&tmp.base); - - if (status) - { - _cairo_pattern_release_surface (dst, *src_out, src_attributes); - return status; - } } else { - *mask_out = NULL; + _cairo_pattern_init_copy (&src_tmp.base, src); } - return CAIRO_STATUS_SUCCESS; + status = _cairo_pattern_acquire_surface (&src_tmp.base, dst, + src_x, src_y, + width, height, + src_out, src_attributes); + if (status) { + _cairo_pattern_fini (&src_tmp.base); + return status; + } + + if (mask == NULL) + { + _cairo_pattern_fini (&src_tmp.base); + *mask_out = NULL; + return CAIRO_STATUS_SUCCESS; + } + + _cairo_pattern_init_copy (&mask_tmp.base, mask); + + status = _cairo_pattern_acquire_surface (&mask_tmp.base, dst, + mask_x, mask_y, + width, height, + mask_out, mask_attributes); + + if (status) + _cairo_pattern_release_surface (&src_tmp.base, + *src_out, src_attributes); + + _cairo_pattern_fini (&src_tmp.base); + _cairo_pattern_fini (&mask_tmp.base); + + return status; } diff --git a/gfx/cairo/cairo/src/cairo-pdf-surface.c b/gfx/cairo/cairo/src/cairo-pdf-surface.c index 228c2c89aa81..6b863721ee41 100644 --- a/gfx/cairo/cairo/src/cairo-pdf-surface.c +++ b/gfx/cairo/cairo/src/cairo-pdf-surface.c @@ -36,15 +36,9 @@ #include "cairoint.h" #include "cairo-pdf.h" -/* XXX: Eventually, we need to handle other font backends */ +#include "cairo-font-subset-private.h" #include "cairo-ft-private.h" -#include -#include FT_FREETYPE_H -#include FT_OUTLINE_H -#include FT_TRUETYPE_TAGS_H -#include FT_TRUETYPE_TABLES_H - #include #include @@ -93,45 +87,6 @@ * instead of outputting the cm operator in every page. */ -typedef struct ft_subset_glyph ft_subset_glyph_t; -struct ft_subset_glyph { - int parent_index; - unsigned long location; -}; - -typedef struct cairo_pdf_font_backend cairo_pdf_font_backend_t; -struct cairo_pdf_font_backend { - int (*use_glyph) (void *abstract_font, - int glyph); - cairo_status_t (*generate) (void *abstract_font, - const char **data, - unsigned long *length); - void (*destroy) (void *abstract_font); -}; - -typedef struct cairo_pdf_font cairo_pdf_font_t; -struct cairo_pdf_font { - cairo_pdf_font_backend_t *backend; - cairo_unscaled_font_t *unscaled_font; - unsigned int font_id; - char *base_font; - int num_glyphs; - int *widths; - long x_min, y_min, x_max, y_max; - long ascent, descent; -}; - -typedef struct cairo_pdf_ft_font cairo_pdf_ft_font_t; -struct cairo_pdf_ft_font { - cairo_pdf_font_t base; - ft_subset_glyph_t *glyphs; - FT_Face face; - unsigned long *checksum_location; - cairo_array_t output; - int *parent_to_subset; - cairo_status_t status; -}; - typedef struct cairo_pdf_object cairo_pdf_object_t; typedef struct cairo_pdf_resource cairo_pdf_resource_t; typedef struct cairo_pdf_stream cairo_pdf_stream_t; @@ -154,7 +109,7 @@ struct cairo_pdf_stream { struct cairo_pdf_document { cairo_output_stream_t *output_stream; - unsigned long refcount; + unsigned long ref_count; cairo_surface_t *owner; cairo_bool_t finished; @@ -188,6 +143,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 @@ -203,7 +159,7 @@ _cairo_pdf_document_destroy (cairo_pdf_document_t *document); static cairo_status_t _cairo_pdf_document_finish (cairo_pdf_document_t *document); -static void +static cairo_pdf_document_t * _cairo_pdf_document_reference (cairo_pdf_document_t *document); static unsigned int @@ -220,6 +176,9 @@ static cairo_pdf_stream_t * _cairo_pdf_document_open_stream (cairo_pdf_document_t *document, const char *fmt, ...); +static void +_cairo_pdf_document_close_stream (cairo_pdf_document_t *document); + static cairo_surface_t * _cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document, double width, @@ -232,586 +191,6 @@ _cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface); static const cairo_surface_backend_t cairo_pdf_surface_backend; -/* Truetype font subsetting code */ - -#define ARRAY_LENGTH(a) ( (sizeof (a)) / (sizeof ((a)[0])) ) - -#define SFNT_VERSION 0x00010000 - -#ifdef WORDS_BIGENDIAN - -#define cpu_to_be16(v) (v) -#define be16_to_cpu(v) (v) -#define cpu_to_be32(v) (v) -#define be32_to_cpu(v) (v) - -#else - -static inline unsigned short -cpu_to_be16(unsigned short v) -{ - return (v << 8) | (v >> 8); -} - -static inline unsigned short -be16_to_cpu(unsigned short v) -{ - return cpu_to_be16 (v); -} - -static inline unsigned long -cpu_to_be32(unsigned long v) -{ - return (cpu_to_be16 (v) << 16) | cpu_to_be16 (v >> 16); -} - -static inline unsigned long -be32_to_cpu(unsigned long v) -{ - return cpu_to_be32 (v); -} - -#endif - -static cairo_pdf_font_backend_t cairo_pdf_ft_font_backend; - -static int -cairo_pdf_font_use_glyph (cairo_pdf_font_t *font, int glyph) -{ - return font->backend->use_glyph (font, glyph); -} - -static cairo_status_t -cairo_pdf_font_generate (cairo_pdf_font_t *font, - const char **data, unsigned long *length) -{ - return font->backend->generate (font, data, length); -} - -static void -cairo_pdf_font_destroy (cairo_pdf_font_t *font) -{ - font->backend->destroy (font); -} - -static cairo_pdf_font_t * -cairo_pdf_ft_font_create (cairo_pdf_document_t *document, - cairo_unscaled_font_t *unscaled_font) -{ - FT_Face face; - cairo_pdf_ft_font_t *font; - unsigned long size; - int i, j; - - face = _cairo_ft_unscaled_font_lock_face (unscaled_font); - - /* We currently only support freetype truetype fonts. */ - size = 0; - if (!FT_IS_SFNT (face) || - FT_Load_Sfnt_Table (face, TTAG_glyf, 0, NULL, &size) != 0) - return NULL; - - font = malloc (sizeof (cairo_pdf_ft_font_t)); - if (font == NULL) - return NULL; - - font->base.unscaled_font = unscaled_font; - _cairo_unscaled_font_reference (unscaled_font); - font->base.backend = &cairo_pdf_ft_font_backend; - font->base.font_id = _cairo_pdf_document_new_object (document); - - _cairo_array_init (&font->output, sizeof (char)); - if (_cairo_array_grow_by (&font->output, 4096) != CAIRO_STATUS_SUCCESS) - goto fail1; - - font->glyphs = calloc (face->num_glyphs + 1, sizeof (ft_subset_glyph_t)); - if (font->glyphs == NULL) - goto fail2; - - font->parent_to_subset = calloc (face->num_glyphs, sizeof (int)); - if (font->parent_to_subset == NULL) - goto fail3; - - font->base.num_glyphs = 1; - font->base.x_min = face->bbox.xMin; - font->base.y_min = face->bbox.yMin; - font->base.x_max = face->bbox.xMax; - font->base.y_max = face->bbox.yMax; - font->base.ascent = face->ascender; - font->base.descent = face->descender; - font->base.base_font = strdup (face->family_name); - if (font->base.base_font == NULL) - goto fail4; - - for (i = 0, j = 0; font->base.base_font[j]; j++) { - if (font->base.base_font[j] == ' ') - continue; - font->base.base_font[i++] = font->base.base_font[j]; - } - font->base.base_font[i] = '\0'; - - font->base.widths = calloc (face->num_glyphs, sizeof (int)); - if (font->base.widths == NULL) - goto fail5; - - _cairo_ft_unscaled_font_unlock_face (unscaled_font); - - font->status = CAIRO_STATUS_SUCCESS; - - return &font->base; - - fail5: - free (font->base.base_font); - fail4: - free (font->parent_to_subset); - fail3: - free (font->glyphs); - fail2: - _cairo_array_fini (&font->output); - fail1: - free (font); - return NULL; -} - -static void -cairo_pdf_ft_font_destroy (void *abstract_font) -{ - cairo_pdf_ft_font_t *font = abstract_font; - - _cairo_unscaled_font_destroy (font->base.unscaled_font); - free (font->base.base_font); - free (font->parent_to_subset); - free (font->glyphs); - _cairo_array_fini (&font->output); - free (font); -} - -static void * -cairo_pdf_ft_font_write (cairo_pdf_ft_font_t *font, - const void *data, size_t length) -{ - void *p; - - p = _cairo_array_append (&font->output, data, length); - if (p == NULL) - font->status = CAIRO_STATUS_NO_MEMORY; - - return p; -} - -static void -cairo_pdf_ft_font_write_be16 (cairo_pdf_ft_font_t *font, - unsigned short value) -{ - unsigned short be16_value; - - be16_value = cpu_to_be16 (value); - cairo_pdf_ft_font_write (font, &be16_value, sizeof be16_value); -} - -static void -cairo_pdf_ft_font_write_be32 (cairo_pdf_ft_font_t *font, unsigned long value) -{ - unsigned long be32_value; - - be32_value = cpu_to_be32 (value); - cairo_pdf_ft_font_write (font, &be32_value, sizeof be32_value); -} - -static unsigned long -cairo_pdf_ft_font_align_output (cairo_pdf_ft_font_t *font) -{ - int length, aligned; - static const char pad[4]; - - length = _cairo_array_num_elements (&font->output); - aligned = (length + 3) & ~3; - cairo_pdf_ft_font_write (font, pad, aligned - length); - - return aligned; -} - -static int -cairo_pdf_ft_font_write_cmap_table (cairo_pdf_ft_font_t *font, unsigned long tag) -{ - int i; - - cairo_pdf_ft_font_write_be16 (font, 0); - cairo_pdf_ft_font_write_be16 (font, 1); - - cairo_pdf_ft_font_write_be16 (font, 1); - cairo_pdf_ft_font_write_be16 (font, 0); - cairo_pdf_ft_font_write_be32 (font, 12); - - /* Output a format 6 encoding table. */ - - cairo_pdf_ft_font_write_be16 (font, 6); - cairo_pdf_ft_font_write_be16 (font, 10 + 2 * (font->base.num_glyphs - 1)); - cairo_pdf_ft_font_write_be16 (font, 0); - cairo_pdf_ft_font_write_be16 (font, 1); /* First glyph */ - cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs - 1); - for (i = 1; i < font->base.num_glyphs; i++) - cairo_pdf_ft_font_write_be16 (font, i); - - return font->status; -} - -static int -cairo_pdf_ft_font_write_generic_table (cairo_pdf_ft_font_t *font, - unsigned long tag) -{ - unsigned char *buffer; - unsigned long size; - - size = 0; - FT_Load_Sfnt_Table (font->face, tag, 0, NULL, &size); - buffer = cairo_pdf_ft_font_write (font, NULL, size); - FT_Load_Sfnt_Table (font->face, tag, 0, buffer, &size); - - return 0; -} - -static int -cairo_pdf_ft_font_write_glyf_table (cairo_pdf_ft_font_t *font, - unsigned long tag) -{ - unsigned long start_offset, index, size; - TT_Header *header; - unsigned long begin, end; - unsigned char *buffer; - int i; - union { - unsigned char *bytes; - unsigned short *short_offsets; - unsigned long *long_offsets; - } u; - - header = FT_Get_Sfnt_Table (font->face, ft_sfnt_head); - if (header->Index_To_Loc_Format == 0) - size = sizeof (short) * (font->face->num_glyphs + 1); - else - size = sizeof (long) * (font->face->num_glyphs + 1); - - u.bytes = malloc (size); - if (u.bytes == NULL) { - font->status = CAIRO_STATUS_NO_MEMORY; - return font->status; - } - FT_Load_Sfnt_Table (font->face, TTAG_loca, 0, u.bytes, &size); - - start_offset = _cairo_array_num_elements (&font->output); - for (i = 0; i < font->base.num_glyphs; i++) { - index = font->glyphs[i].parent_index; - if (header->Index_To_Loc_Format == 0) { - begin = be16_to_cpu (u.short_offsets[index]) * 2; - end = be16_to_cpu (u.short_offsets[index + 1]) * 2; - } - else { - begin = be32_to_cpu (u.long_offsets[index]); - end = be32_to_cpu (u.long_offsets[index + 1]); - } - - size = end - begin; - - font->glyphs[i].location = - cairo_pdf_ft_font_align_output (font) - start_offset; - buffer = cairo_pdf_ft_font_write (font, NULL, size); - if (buffer == NULL) - break; - FT_Load_Sfnt_Table (font->face, TTAG_glyf, begin, buffer, &size); - /* FIXME: remap composite glyphs */ - } - - font->glyphs[i].location = - cairo_pdf_ft_font_align_output (font) - start_offset; - - free (u.bytes); - - return font->status; -} - -static int -cairo_pdf_ft_font_write_head_table (cairo_pdf_ft_font_t *font, - unsigned long tag) -{ - TT_Header *head; - - head = FT_Get_Sfnt_Table (font->face, ft_sfnt_head); - - cairo_pdf_ft_font_write_be32 (font, head->Table_Version); - cairo_pdf_ft_font_write_be32 (font, head->Font_Revision); - - font->checksum_location = - (unsigned long *) _cairo_array_index (&font->output, 0) + - _cairo_array_num_elements (&font->output) / sizeof (long); - cairo_pdf_ft_font_write_be32 (font, 0); - cairo_pdf_ft_font_write_be32 (font, head->Magic_Number); - - cairo_pdf_ft_font_write_be16 (font, head->Flags); - cairo_pdf_ft_font_write_be16 (font, head->Units_Per_EM); - - cairo_pdf_ft_font_write_be32 (font, head->Created[0]); - cairo_pdf_ft_font_write_be32 (font, head->Created[1]); - cairo_pdf_ft_font_write_be32 (font, head->Modified[0]); - cairo_pdf_ft_font_write_be32 (font, head->Modified[1]); - - cairo_pdf_ft_font_write_be16 (font, head->xMin); - cairo_pdf_ft_font_write_be16 (font, head->yMin); - cairo_pdf_ft_font_write_be16 (font, head->xMax); - cairo_pdf_ft_font_write_be16 (font, head->yMax); - - cairo_pdf_ft_font_write_be16 (font, head->Mac_Style); - cairo_pdf_ft_font_write_be16 (font, head->Lowest_Rec_PPEM); - - cairo_pdf_ft_font_write_be16 (font, head->Font_Direction); - cairo_pdf_ft_font_write_be16 (font, head->Index_To_Loc_Format); - cairo_pdf_ft_font_write_be16 (font, head->Glyph_Data_Format); - - return font->status; -} - -static int cairo_pdf_ft_font_write_hhea_table (cairo_pdf_ft_font_t *font, unsigned long tag) -{ - TT_HoriHeader *hhea; - - hhea = FT_Get_Sfnt_Table (font->face, ft_sfnt_hhea); - - cairo_pdf_ft_font_write_be32 (font, hhea->Version); - cairo_pdf_ft_font_write_be16 (font, hhea->Ascender); - cairo_pdf_ft_font_write_be16 (font, hhea->Descender); - cairo_pdf_ft_font_write_be16 (font, hhea->Line_Gap); - - cairo_pdf_ft_font_write_be16 (font, hhea->advance_Width_Max); - - cairo_pdf_ft_font_write_be16 (font, hhea->min_Left_Side_Bearing); - cairo_pdf_ft_font_write_be16 (font, hhea->min_Right_Side_Bearing); - cairo_pdf_ft_font_write_be16 (font, hhea->xMax_Extent); - cairo_pdf_ft_font_write_be16 (font, hhea->caret_Slope_Rise); - cairo_pdf_ft_font_write_be16 (font, hhea->caret_Slope_Run); - cairo_pdf_ft_font_write_be16 (font, hhea->caret_Offset); - - cairo_pdf_ft_font_write_be16 (font, 0); - cairo_pdf_ft_font_write_be16 (font, 0); - cairo_pdf_ft_font_write_be16 (font, 0); - cairo_pdf_ft_font_write_be16 (font, 0); - - cairo_pdf_ft_font_write_be16 (font, hhea->metric_Data_Format); - cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs); - - return font->status; -} - -static int -cairo_pdf_ft_font_write_hmtx_table (cairo_pdf_ft_font_t *font, - unsigned long tag) -{ - unsigned long entry_size; - short *p; - int i; - - for (i = 0; i < font->base.num_glyphs; i++) { - entry_size = 2 * sizeof (short); - p = cairo_pdf_ft_font_write (font, NULL, entry_size); - FT_Load_Sfnt_Table (font->face, TTAG_hmtx, - font->glyphs[i].parent_index * entry_size, - (FT_Byte *) p, &entry_size); - font->base.widths[i] = be16_to_cpu (p[0]); - } - - return font->status; -} - -static int -cairo_pdf_ft_font_write_loca_table (cairo_pdf_ft_font_t *font, - unsigned long tag) -{ - int i; - TT_Header *header; - - header = FT_Get_Sfnt_Table (font->face, ft_sfnt_head); - - if (header->Index_To_Loc_Format == 0) { - for (i = 0; i < font->base.num_glyphs + 1; i++) - cairo_pdf_ft_font_write_be16 (font, font->glyphs[i].location / 2); - } - else { - for (i = 0; i < font->base.num_glyphs + 1; i++) - cairo_pdf_ft_font_write_be32 (font, font->glyphs[i].location); - } - - return font->status; -} - -static int -cairo_pdf_ft_font_write_maxp_table (cairo_pdf_ft_font_t *font, - unsigned long tag) -{ - TT_MaxProfile *maxp; - - maxp = FT_Get_Sfnt_Table (font->face, ft_sfnt_maxp); - - cairo_pdf_ft_font_write_be32 (font, maxp->version); - cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs); - cairo_pdf_ft_font_write_be16 (font, maxp->maxPoints); - cairo_pdf_ft_font_write_be16 (font, maxp->maxContours); - cairo_pdf_ft_font_write_be16 (font, maxp->maxCompositePoints); - cairo_pdf_ft_font_write_be16 (font, maxp->maxCompositeContours); - cairo_pdf_ft_font_write_be16 (font, maxp->maxZones); - cairo_pdf_ft_font_write_be16 (font, maxp->maxTwilightPoints); - cairo_pdf_ft_font_write_be16 (font, maxp->maxStorage); - cairo_pdf_ft_font_write_be16 (font, maxp->maxFunctionDefs); - cairo_pdf_ft_font_write_be16 (font, maxp->maxInstructionDefs); - cairo_pdf_ft_font_write_be16 (font, maxp->maxStackElements); - cairo_pdf_ft_font_write_be16 (font, maxp->maxSizeOfInstructions); - cairo_pdf_ft_font_write_be16 (font, maxp->maxComponentElements); - cairo_pdf_ft_font_write_be16 (font, maxp->maxComponentDepth); - - return font->status; -} - -typedef struct table table_t; -struct table { - unsigned long tag; - int (*write) (cairo_pdf_ft_font_t *font, unsigned long tag); -}; - -static const table_t truetype_tables[] = { - { TTAG_cmap, cairo_pdf_ft_font_write_cmap_table }, - { TTAG_cvt, cairo_pdf_ft_font_write_generic_table }, - { TTAG_fpgm, cairo_pdf_ft_font_write_generic_table }, - { TTAG_glyf, cairo_pdf_ft_font_write_glyf_table }, - { TTAG_head, cairo_pdf_ft_font_write_head_table }, - { TTAG_hhea, cairo_pdf_ft_font_write_hhea_table }, - { TTAG_hmtx, cairo_pdf_ft_font_write_hmtx_table }, - { TTAG_loca, cairo_pdf_ft_font_write_loca_table }, - { TTAG_maxp, cairo_pdf_ft_font_write_maxp_table }, - { TTAG_name, cairo_pdf_ft_font_write_generic_table }, - { TTAG_prep, cairo_pdf_ft_font_write_generic_table }, -}; - -static cairo_status_t -cairo_pdf_ft_font_write_offset_table (cairo_pdf_ft_font_t *font) -{ - unsigned short search_range, entry_selector, range_shift; - int num_tables; - - num_tables = ARRAY_LENGTH (truetype_tables); - search_range = 1; - entry_selector = 0; - while (search_range * 2 <= num_tables) { - search_range *= 2; - entry_selector++; - } - search_range *= 16; - range_shift = num_tables * 16 - search_range; - - cairo_pdf_ft_font_write_be32 (font, SFNT_VERSION); - cairo_pdf_ft_font_write_be16 (font, num_tables); - cairo_pdf_ft_font_write_be16 (font, search_range); - cairo_pdf_ft_font_write_be16 (font, entry_selector); - cairo_pdf_ft_font_write_be16 (font, range_shift); - - cairo_pdf_ft_font_write (font, NULL, ARRAY_LENGTH (truetype_tables) * 16); - - return font->status; -} - -static unsigned long -cairo_pdf_ft_font_calculate_checksum (cairo_pdf_ft_font_t *font, - unsigned long start, unsigned long end) -{ - unsigned long *padded_end; - unsigned long *p; - unsigned long checksum; - char *data; - - checksum = 0; - data = _cairo_array_index (&font->output, 0); - p = (unsigned long *) (data + start); - padded_end = (unsigned long *) (data + ((end + 3) & ~3)); - while (p < padded_end) - checksum += *p++; - - return checksum; -} - -static void -cairo_pdf_ft_font_update_entry (cairo_pdf_ft_font_t *font, int index, unsigned long tag, - unsigned long start, unsigned long end) -{ - unsigned long *entry; - - entry = _cairo_array_index (&font->output, 12 + 16 * index); - entry[0] = cpu_to_be32 (tag); - entry[1] = cpu_to_be32 (cairo_pdf_ft_font_calculate_checksum (font, start, end)); - entry[2] = cpu_to_be32 (start); - entry[3] = cpu_to_be32 (end - start); -} - -static cairo_status_t -cairo_pdf_ft_font_generate (void *abstract_font, - const char **data, unsigned long *length) -{ - cairo_pdf_ft_font_t *font = abstract_font; - unsigned long start, end, next, checksum; - int i; - - font->face = _cairo_ft_unscaled_font_lock_face (font->base.unscaled_font); - - if (cairo_pdf_ft_font_write_offset_table (font)) - goto fail; - - start = cairo_pdf_ft_font_align_output (font); - end = start; - - end = 0; - for (i = 0; i < ARRAY_LENGTH (truetype_tables); i++) { - if (truetype_tables[i].write (font, truetype_tables[i].tag)) - goto fail; - - end = _cairo_array_num_elements (&font->output); - next = cairo_pdf_ft_font_align_output (font); - cairo_pdf_ft_font_update_entry (font, i, truetype_tables[i].tag, - start, end); - start = next; - } - - checksum = - 0xb1b0afba - cairo_pdf_ft_font_calculate_checksum (font, 0, end); - *font->checksum_location = cpu_to_be32 (checksum); - - *data = _cairo_array_index (&font->output, 0); - *length = _cairo_array_num_elements (&font->output); - - fail: - _cairo_ft_unscaled_font_unlock_face (font->base.unscaled_font); - font->face = NULL; - - return font->status; -} - -static int -cairo_pdf_ft_font_use_glyph (void *abstract_font, int glyph) -{ - cairo_pdf_ft_font_t *font = abstract_font; - - if (font->parent_to_subset[glyph] == 0) { - font->parent_to_subset[glyph] = font->base.num_glyphs; - font->glyphs[font->base.num_glyphs].parent_index = glyph; - font->base.num_glyphs++; - } - - return font->parent_to_subset[glyph]; -} - -static cairo_pdf_font_backend_t cairo_pdf_ft_font_backend = { - cairo_pdf_ft_font_use_glyph, - cairo_pdf_ft_font_generate, - cairo_pdf_ft_font_destroy -}; - -/* PDF Generation */ - static unsigned int _cairo_pdf_document_new_object (cairo_pdf_document_t *document) { @@ -911,8 +290,10 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *stream, cairo_surface_t *surface; document = _cairo_pdf_document_create (stream, width, height); - if (document == NULL) - return NULL; + if (document == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } surface = _cairo_pdf_surface_create_for_document (document, width, height); @@ -931,8 +312,10 @@ cairo_pdf_surface_create_for_stream (cairo_write_func_t write, cairo_output_stream_t *stream; stream = _cairo_output_stream_create (write, closure); - if (stream == NULL) - return NULL; + if (stream == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } return _cairo_pdf_surface_create_for_stream_internal (stream, width, height); } @@ -945,8 +328,10 @@ cairo_pdf_surface_create (const char *filename, cairo_output_stream_t *stream; stream = _cairo_output_stream_create_for_file (filename); - if (stream == NULL) - return NULL; + if (stream == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } return _cairo_pdf_surface_create_for_stream_internal (stream, width, height); } @@ -970,21 +355,23 @@ _cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document, cairo_pdf_surface_t *surface; surface = malloc (sizeof (cairo_pdf_surface_t)); - if (surface == NULL) - return NULL; + if (surface == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } _cairo_surface_init (&surface->base, &cairo_pdf_surface_backend); surface->width = width; surface->height = height; - _cairo_pdf_document_reference (document); - surface->document = document; + surface->document = _cairo_pdf_document_reference (document); _cairo_array_init (&surface->streams, sizeof (cairo_pdf_stream_t *)); _cairo_array_init (&surface->patterns, sizeof (cairo_pdf_resource_t)); _cairo_array_init (&surface->xobjects, sizeof (cairo_pdf_resource_t)); _cairo_array_init (&surface->alphas, sizeof (double)); _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_resource_t)); + surface->has_clip = FALSE; return &surface->base; } @@ -1009,9 +396,8 @@ _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, +_cairo_pdf_surface_create_similar (void *abstract_src, + cairo_content_t content, int width, int height) { @@ -1106,6 +492,12 @@ _cairo_pdf_surface_finish (void *abstract_surface) _cairo_pdf_document_destroy (document); + _cairo_array_fini (&surface->streams); + _cairo_array_fini (&surface->patterns); + _cairo_array_fini (&surface->xobjects); + _cairo_array_fini (&surface->alphas); + _cairo_array_fini (&surface->fonts); + return status; } @@ -1225,7 +617,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 +673,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 +792,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 +1027,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 +1039,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 +1048,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 +1092,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 +1101,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 +1119,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 +1129,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; } @@ -1734,6 +1151,7 @@ static cairo_int_status_t _cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, void *abstract_dst, + cairo_antialias_t antialias, int x_src, int y_src, int x_dst, @@ -1794,10 +1212,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 @@ -1819,14 +1239,19 @@ _cairo_pdf_surface_get_extents (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } -static cairo_pdf_font_t * +static cairo_font_subset_t * _cairo_pdf_document_get_font (cairo_pdf_document_t *document, cairo_scaled_font_t *scaled_font) { cairo_unscaled_font_t *unscaled_font; - cairo_pdf_font_t *pdf_font; + cairo_font_subset_t *pdf_font; unsigned int num_fonts, i; + /* XXX: Need to fix this to work with a general cairo_scaled_font_t. */ + if (! _cairo_scaled_font_is_ft (scaled_font)) + return NULL; + + /* XXX Why is this an ft specific function? */ unscaled_font = _cairo_ft_scaled_font_get_unscaled_font (scaled_font); num_fonts = _cairo_array_num_elements (&document->fonts); @@ -1838,12 +1263,14 @@ _cairo_pdf_document_get_font (cairo_pdf_document_t *document, /* FIXME: Figure out here which font backend is in use and call * the appropriate constructor. */ - pdf_font = cairo_pdf_ft_font_create (document, unscaled_font); + pdf_font = _cairo_font_subset_create (unscaled_font); if (pdf_font == NULL) return NULL; + pdf_font->font_id = _cairo_pdf_document_new_object (document); + if (_cairo_array_append (&document->fonts, &pdf_font, 1) == NULL) { - cairo_pdf_font_destroy (pdf_font); + _cairo_font_subset_destroy (pdf_font); return NULL; } @@ -1867,9 +1294,13 @@ _cairo_pdf_surface_show_glyphs (cairo_scaled_font_t *scaled_font, cairo_pdf_surface_t *surface = abstract_surface; cairo_pdf_document_t *document = surface->document; cairo_output_stream_t *output = document->output_stream; - cairo_pdf_font_t *pdf_font; + cairo_font_subset_t *pdf_font; int i, index; + /* XXX: Need to fix this to work with a general cairo_scaled_font_t. */ + if (! _cairo_scaled_font_is_ft (scaled_font)) + return CAIRO_INT_STATUS_UNSUPPORTED; + pdf_font = _cairo_pdf_document_get_font (document, scaled_font); if (pdf_font == NULL) return CAIRO_STATUS_NO_MEMORY; @@ -1880,13 +1311,13 @@ _cairo_pdf_surface_show_glyphs (cairo_scaled_font_t *scaled_font, "BT /res%u 1 Tf", pdf_font->font_id); for (i = 0; i < num_glyphs; i++) { - index = cairo_pdf_font_use_glyph (pdf_font, glyphs[i].index); + index = _cairo_font_subset_use_glyph (pdf_font, glyphs[i].index); _cairo_output_stream_printf (output, " %f %f %f %f %f %f Tm (\\%o) Tj", scaled_font->scale.xx, scaled_font->scale.yx, - scaled_font->scale.xy, + -scaled_font->scale.xy, -scaled_font->scale.yy, glyphs[i].x, glyphs[i].y, @@ -1900,6 +1331,73 @@ _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_antialias_t antialias) +{ + 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 void +_cairo_pdf_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + _cairo_font_options_init_default (options); + + cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF); +} + static const cairo_surface_backend_t cairo_pdf_surface_backend = { _cairo_pdf_surface_create_similar, _cairo_pdf_surface_finish, @@ -1914,9 +1412,11 @@ 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 + _cairo_pdf_surface_fill_path, + _cairo_pdf_surface_get_font_options }; static cairo_pdf_document_t * @@ -1931,7 +1431,7 @@ _cairo_pdf_document_create (cairo_output_stream_t *output_stream, return NULL; document->output_stream = output_stream; - document->refcount = 1; + document->ref_count = 1; document->owner = NULL; document->finished = FALSE; document->width = width; @@ -1947,7 +1447,7 @@ _cairo_pdf_document_create (cairo_output_stream_t *output_stream, document->pages_id = _cairo_pdf_document_new_object (document); - _cairo_array_init (&document->fonts, sizeof (cairo_pdf_font_t *)); + _cairo_array_init (&document->fonts, sizeof (cairo_font_subset_t *)); /* Document header */ _cairo_output_stream_printf (output_stream, @@ -2011,7 +1511,7 @@ static cairo_status_t _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document) { cairo_output_stream_t *output = document->output_stream; - cairo_pdf_font_t *font; + cairo_font_subset_t *font; int num_fonts, i, j; const char *data; char *compressed; @@ -2023,7 +1523,7 @@ _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document) for (i = 0; i < num_fonts; i++) { _cairo_array_copy_element (&document->fonts, i, &font); - status = cairo_pdf_font_generate (font, &data, &data_size); + status = _cairo_font_subset_generate (font, &data, &data_size); if (status) goto fail; @@ -2106,7 +1606,7 @@ _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document) "endobj\r\n"); fail: - cairo_pdf_ft_font_destroy (font); + _cairo_font_subset_destroy (font); } return status; @@ -2159,17 +1659,19 @@ _cairo_pdf_document_write_xref (cairo_pdf_document_t *document) return offset; } -static void +static cairo_pdf_document_t * _cairo_pdf_document_reference (cairo_pdf_document_t *document) { - document->refcount++; + document->ref_count++; + + return document; } static void _cairo_pdf_document_destroy (cairo_pdf_document_t *document) { - document->refcount--; - if (document->refcount > 0) + document->ref_count--; + if (document->ref_count > 0) return; _cairo_pdf_document_finish (document); @@ -2214,6 +1716,10 @@ _cairo_pdf_document_finish (cairo_pdf_document_t *document) status = _cairo_output_stream_get_status (output); _cairo_output_stream_destroy (output); + _cairo_array_fini (&document->objects); + _cairo_array_fini (&document->pages); + _cairo_array_fini (&document->fonts); + document->finished = TRUE; return status; @@ -2232,6 +1738,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/gfx/cairo/cairo/src/cairo-pdf.h b/gfx/cairo/cairo/src/cairo-pdf.h index b7d56c3ea706..61bf7a841e7d 100644 --- a/gfx/cairo/cairo/src/cairo-pdf.h +++ b/gfx/cairo/cairo/src/cairo-pdf.h @@ -39,7 +39,7 @@ #include -#ifdef CAIRO_HAS_PDF_SURFACE +#if CAIRO_HAS_PDF_SURFACE CAIRO_BEGIN_DECLS diff --git a/gfx/cairo/cairo/src/cairo-pen.c b/gfx/cairo/cairo/src/cairo-pen.c index 81b43abe8e87..18b9ddb5926b 100644 --- a/gfx/cairo/cairo/src/cairo-pen.c +++ b/gfx/cairo/cairo/src/cairo-pen.c @@ -306,36 +306,36 @@ an ellipse parameterized by angle 't': Perturb t by ± d and compute two new points (x+,y+), (x-,y-). The distance from the average of these two points to (x,y) represents the maximum error in approximating the ellipse with a polygon formed -from vertices 2? radians apart. +from vertices 2∆ radians apart. - x+ = M cos (t+?) y+ = m sin (t+?) - x- = M cos (t-?) y- = m sin (t-?) + x+ = M cos (t+∆) y+ = m sin (t+∆) + x- = M cos (t-∆) y- = m sin (t-∆) Now compute the approximation error, E: Ex = (x - (x+ + x-) / 2) - Ex = (M cos(t) - (Mcos(t+?) + Mcos(t-?))/2) - = M (cos(t) - (cos(t)cos(?) + sin(t)sin(?) + - cos(t)cos(?) - sin(t)sin(?))/2) - = M(cos(t) - cos(t)cos(?)) - = M cos(t) (1 - cos(?)) + Ex = (M cos(t) - (Mcos(t+∆) + Mcos(t-∆))/2) + = M (cos(t) - (cos(t)cos(∆) + sin(t)sin(∆) + + cos(t)cos(∆) - sin(t)sin(∆))/2) + = M(cos(t) - cos(t)cos(∆)) + = M cos(t) (1 - cos(∆)) Ey = y - (y+ - y-) / 2 - = m sin (t) - (m sin(t+?) + m sin(t-?)) / 2 - = m (sin(t) - (sin(t)cos(?) + cos(t)sin(?) + - sin(t)cos(?) - cos(t)sin(?))/2) - = m (sin(t) - sin(t)cos(?)) - = m sin(t) (1 - cos(?)) + = m sin (t) - (m sin(t+∆) + m sin(t-∆)) / 2 + = m (sin(t) - (sin(t)cos(∆) + cos(t)sin(∆) + + sin(t)cos(∆) - cos(t)sin(∆))/2) + = m (sin(t) - sin(t)cos(∆)) + = m sin(t) (1 - cos(∆)) E² = Ex² + Ey² - = (M cos(t) (1 - cos (?)))² + (m sin(t) (1-cos(?)))² - = (1 - cos(?))² (M² cos²(t) + m² sin²(t)) - = (1 - cos(?))² ((m² + M² - m²) cos² (t) + m² sin²(t)) - = (1 - cos(?))² (M² - m²) cos² (t) + (1 - cos(?))² m² + = (M cos(t) (1 - cos (∆)))² + (m sin(t) (1-cos(∆)))² + = (1 - cos(∆))² (M² cos²(t) + m² sin²(t)) + = (1 - cos(∆))² ((m² + M² - m²) cos² (t) + m² sin²(t)) + = (1 - cos(∆))² (M² - m²) cos² (t) + (1 - cos(∆))² m² Find the extremum by differentiation wrt t and setting that to zero -∂(E²)/∂(t) = (1-cos(?))² (M² - m²) (-2 cos(t) sin(t)) +∂(E²)/∂(t) = (1-cos(∆))² (M² - m²) (-2 cos(t) sin(t)) 0 = 2 cos (t) sin (t) 0 = sin (2t) @@ -344,25 +344,25 @@ Find the extremum by differentiation wrt t and setting that to zero Which is to say that the maximum and minimum errors occur on the axes of the ellipse at 0 and π radians: - E²(0) = (1-cos(?))² (M² - m²) + (1-cos(?))² m² - = (1-cos(?))² M² - E²(π) = (1-cos(?))² m² + E²(0) = (1-cos(∆))² (M² - m²) + (1-cos(∆))² m² + = (1-cos(∆))² M² + E²(π) = (1-cos(∆))² m² -maximum error = M (1-cos(?)) -minimum error = m (1-cos(?)) +maximum error = M (1-cos(∆)) +minimum error = m (1-cos(∆)) -We must make maximum error ≤ tolerance, so compute the ? needed: +We must make maximum error ≤ tolerance, so compute the ∆ needed: - tolerance = M (1-cos(?)) - tolerance / M = 1 - cos (?) - cos(?) = 1 - tolerance/M - ? = acos (1 - tolerance / M); + tolerance = M (1-cos(∆)) + tolerance / M = 1 - cos (∆) + cos(∆) = 1 - tolerance/M + ∆ = acos (1 - tolerance / M); -Remembering that ? is half of our angle between vertices, +Remembering that ∆ is half of our angle between vertices, the number of vertices is then -vertices = ceil(2π/2?). - = ceil(π/?). +vertices = ceil(2π/2∆). + = ceil(π/∆). Note that this also equation works for M == m (a circle) as it doesn't matter where on the circle the error is computed. @@ -374,15 +374,32 @@ _cairo_pen_vertices_needed (double tolerance, double radius, cairo_matrix_t *matrix) { - double min, max, major_axis; - int num_vertices; + double a = matrix->xx, b = matrix->yx; + double c = matrix->xy, d = matrix->yy; - _cairo_matrix_compute_expansion_factors (matrix, &min, &max); - major_axis = radius * max; + double i = a*a + c*c; + double j = b*b + d*d; + + double f = 0.5 * (i + j); + double g = 0.5 * (i - j); + double h = a*b + c*d; + + /* + * compute major and minor axes lengths for + * a pen with the specified radius + */ + + double major_axis = radius * sqrt (f + sqrt (g*g+h*h)); + + /* + * we don't need the minor axis length, which is + * double min = radius * sqrt (f - sqrt (g*g+h*h)); + */ /* * compute number of vertices needed */ + int num_vertices; /* Where tolerance / M is > 1, we use 4 points */ if (tolerance >= major_axis) { diff --git a/gfx/cairo/cairo/src/cairo-png.c b/gfx/cairo/cairo/src/cairo-png.c index ecb23ca45adf..afe9e6ea1f51 100644 --- a/gfx/cairo/cairo/src/cairo-png.c +++ b/gfx/cairo/cairo/src/cairo-png.c @@ -36,8 +36,10 @@ */ #include +#include #include "cairoint.h" +/* Unpremultiplies data and converts native endian ARGB => RGBA bytes */ static void unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data) { @@ -53,14 +55,33 @@ unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data) if (alpha == 0) { b[0] = b[1] = b[2] = b[3] = 0; } else { - b[0] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha; + b[0] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha; b[1] = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha; - b[2] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha; + b[2] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha; b[3] = alpha; } } } +/* Converts native endian xRGB => RGBx bytes */ +static void +convert_data_to_bytes (png_structp png, png_row_infop row_info, png_bytep data) +{ + int i; + + for (i = 0; i < row_info->rowbytes; i += 4) { + uint8_t *b = &data[i]; + uint32_t pixel; + + memcpy (&pixel, b, sizeof (uint32_t)); + + b[0] = (pixel & 0xff0000) >> 16; + b[1] = (pixel & 0x00ff00) >> 8; + b[2] = (pixel & 0x0000ff) >> 0; + b[3] = 0; + } +} + static cairo_status_t write_png (cairo_surface_t *surface, png_rw_ptr write_func, @@ -153,14 +174,19 @@ write_png (cairo_surface_t *surface, png_convert_from_time_t (&pt, time (NULL)); png_set_tIME (png, info, &pt); - png_set_write_user_transform_fn (png, unpremultiply_data); - if (image->format == CAIRO_FORMAT_ARGB32 || - image->format == CAIRO_FORMAT_RGB24) - png_set_bgr (png); + /* We have to call png_write_info() before setting up the write + * transformation, since it stores data internally in 'png' + * that is needed for the write transformation functions to work. + */ + png_write_info (png, info); + + if (image->format == CAIRO_FORMAT_ARGB32) + png_set_write_user_transform_fn (png, unpremultiply_data); + else if (image->format == CAIRO_FORMAT_RGB24) + png_set_write_user_transform_fn (png, convert_data_to_bytes); if (image->format == CAIRO_FORMAT_RGB24) png_set_filler (png, 0, PNG_FILLER_AFTER); - - png_write_info (png, info); + png_write_image (png, rows); png_write_end (png, info); @@ -212,7 +238,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 +252,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"); } @@ -260,6 +288,7 @@ cairo_surface_write_to_png_stream (cairo_surface_t *surface, return write_png (surface, stream_write_func, &png_closure); } +/* Premultiplies data and converts RGBA bytes => native endian */ static void premultiply_data (png_structp png, png_row_infop row_info, @@ -269,9 +298,9 @@ premultiply_data (png_structp png, for (i = 0; i < row_info->rowbytes; i += 4) { uint8_t *base = &data[i]; - uint8_t blue = base[0]; + uint8_t red = base[0]; uint8_t green = base[1]; - uint8_t red = base[2]; + uint8_t blue = base[2]; uint8_t alpha = base[3]; uint32_t p; @@ -287,19 +316,15 @@ static cairo_surface_t * read_png (png_rw_ptr read_func, void *closure) { - cairo_surface_t *surface; - png_byte *data; + cairo_surface_t *surface = (cairo_surface_t*) &_cairo_surface_nil; + png_byte *data = NULL; int i; - png_struct *png; + png_struct *png = NULL; png_info *info; png_uint_32 png_width, png_height, stride; int depth, color_type, interlace; unsigned int pixel_size; - png_byte **row_pointers; - - surface = NULL; - data = NULL; - row_pointers = NULL; + png_byte **row_pointers = NULL; /* XXX: Perhaps we'll want some other error handlers? */ png = png_create_read_struct (PNG_LIBPNG_VER_STRING, @@ -307,7 +332,7 @@ read_png (png_rw_ptr read_func, NULL, NULL); if (png == NULL) - return NULL; + goto BAIL; info = png_create_info_struct (png); if (info == NULL) @@ -315,8 +340,10 @@ read_png (png_rw_ptr read_func, png_set_read_fn (png, closure, read_func); - if (setjmp (png_jmpbuf (png))) + if (setjmp (png_jmpbuf (png))) { + surface = (cairo_surface_t*) &_cairo_surface_nil_read_error; goto BAIL; + } png_read_info (png, info); @@ -350,7 +377,6 @@ read_png (png_rw_ptr read_func, if (interlace != PNG_INTERLACE_NONE) png_set_interlace_handling (png); - png_set_bgr (png); png_set_filler (png, 0xff, PNG_FILLER_AFTER); png_set_read_user_transform_fn (png, premultiply_data); @@ -375,13 +401,22 @@ read_png (png_rw_ptr read_func, surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, png_width, png_height, stride); + if (surface->status) + goto BAIL; + _cairo_image_surface_assume_ownership_of_data ((cairo_image_surface_t*)surface); data = NULL; BAIL: - free (row_pointers); - free (data); - png_destroy_read_struct (&png, NULL, NULL); + if (row_pointers) + free (row_pointers); + if (data) + free (data); + if (png) + png_destroy_read_struct (&png, &info, NULL); + + if (surface->status) + _cairo_error (surface->status); return surface; } @@ -404,8 +439,13 @@ stdio_read_func (png_structp png, png_bytep data, png_size_t size) * given PNG file. * * Return value: a new #cairo_surface_t initialized with the contents - * of the PNG file or %NULL if the file is not a valid PNG file or - * memory could not be allocated for the operation. + * of the PNG file, or a "nil" surface if any error occurred. A nil + * surface can be checked for with cairo_surface_status(surface) which + * may return one of the following values: + * + * CAIRO_STATUS_NO_MEMORY + * CAIRO_STATUS_FILE_NOT_FOUND + * CAIRO_STATUS_READ_ERROR **/ cairo_surface_t * cairo_image_surface_create_from_png (const char *filename) @@ -414,8 +454,19 @@ cairo_image_surface_create_from_png (const char *filename) cairo_surface_t *surface; fp = fopen (filename, "rb"); - if (fp == NULL) - return NULL; + if (fp == NULL) { + switch (errno) { + case ENOMEM: + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + case ENOENT: + _cairo_error (CAIRO_STATUS_FILE_NOT_FOUND); + return (cairo_surface_t*) &_cairo_surface_nil_file_not_found; + default: + _cairo_error (CAIRO_STATUS_READ_ERROR); + return (cairo_surface_t*) &_cairo_surface_nil_read_error; + } + } surface = read_png (stdio_read_func, fp); @@ -432,10 +483,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"); } @@ -460,6 +513,6 @@ cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, png_closure.read_func = read_func; png_closure.closure = closure; - return read_png (stream_read_func, &closure); + return read_png (stream_read_func, &png_closure); } diff --git a/gfx/cairo/cairo/src/cairo-private.h b/gfx/cairo/cairo/src/cairo-private.h index a43c8ef7f05c..7051f7ebd18c 100644 --- a/gfx/cairo/cairo/src/cairo-private.h +++ b/gfx/cairo/cairo/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/gfx/cairo/cairo/src/cairo-ps-surface.c b/gfx/cairo/cairo/src/cairo-ps-surface.c index a79703e1d1e9..79ab65953013 100644 --- a/gfx/cairo/cairo/src/cairo-ps-surface.c +++ b/gfx/cairo/cairo/src/cairo-ps-surface.c @@ -1,6 +1,7 @@ /* cairo - a vector graphics library with display and print output * * Copyright © 2003 University of Southern California + * Copyright © 2005 Red Hat, Inc * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -32,14 +33,27 @@ * * Contributor(s): * Carl D. Worth + * Kristian Høgsberg */ #include "cairoint.h" #include "cairo-ps.h" +#include "cairo-font-subset-private.h" +#include "cairo-meta-surface-private.h" +#include "cairo-ft-private.h" #include #include +/* TODO: + * + * - Add document structure convention comments where appropriate. + * + * - Fix image compression. + * + * - Create a set of procs to use... specifically a trapezoid proc. + */ + static const cairo_surface_backend_t cairo_ps_surface_backend; typedef struct cairo_ps_surface { @@ -48,77 +62,57 @@ typedef struct cairo_ps_surface { /* PS-specific fields */ cairo_output_stream_t *stream; - double width_in_points; - double height_in_points; + double width; + double height; double x_dpi; double y_dpi; - int pages; - - cairo_image_surface_t *image; + cairo_surface_t *current_page; + cairo_array_t pages; + cairo_array_t fonts; } cairo_ps_surface_t; #define PS_SURFACE_DPI_DEFAULT 300.0 -static void -_cairo_ps_surface_erase (cairo_ps_surface_t *surface); +static cairo_int_status_t +_cairo_ps_surface_write_font_subsets (cairo_ps_surface_t *surface); + +static cairo_int_status_t +_cairo_ps_surface_render_page (cairo_ps_surface_t *surface, + cairo_surface_t *page, int page_number); static cairo_surface_t * _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream, - double width_in_points, - double height_in_points) + double width, + double height) { cairo_ps_surface_t *surface; - int width_in_pixels, height_in_pixels; - time_t now = time (0); surface = malloc (sizeof (cairo_ps_surface_t)); - if (surface == NULL) - return NULL; + if (surface == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } _cairo_surface_init (&surface->base, &cairo_ps_surface_backend); surface->stream = stream; - surface->width_in_points = width_in_points; - surface->height_in_points = height_in_points; + surface->width = width; + surface->height = height; surface->x_dpi = PS_SURFACE_DPI_DEFAULT; surface->y_dpi = PS_SURFACE_DPI_DEFAULT; - surface->pages = 0; - - width_in_pixels = (int) (surface->x_dpi * width_in_points / 72.0 + 1.0); - height_in_pixels = (int) (surface->y_dpi * height_in_points / 72.0 + 1.0); - - surface->image = (cairo_image_surface_t *) - cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - width_in_pixels, height_in_pixels); - if (surface->image == NULL) { + surface->current_page = _cairo_meta_surface_create (width, + height); + if (surface->current_page->status) { free (surface); - return NULL; + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; } - _cairo_ps_surface_erase (surface); - - /* Document header */ - _cairo_output_stream_printf (surface->stream, - "%%!PS-Adobe-3.0\n" - "%%%%Creator: Cairo (http://cairographics.org)\n"); - _cairo_output_stream_printf (surface->stream, - "%%%%CreationDate: %s", - ctime (&now)); - _cairo_output_stream_printf (surface->stream, - "%%%%BoundingBox: %f %f %f %f\n", - 0.0, 0.0, - surface->width_in_points, - surface->height_in_points); - /* The "/FlateDecode filter" currently used is a feature of LanguageLevel 3 */ - _cairo_output_stream_printf (surface->stream, - "%%%%DocumentData: Clean7Bit\n" - "%%%%LanguageLevel: 3\n"); - _cairo_output_stream_printf (surface->stream, - "%%%%Orientation: Portrait\n" - "%%%%EndComments\n"); + _cairo_array_init (&surface->pages, sizeof (cairo_surface_t *)); + _cairo_array_init (&surface->fonts, sizeof (cairo_font_subset_t *)); return &surface->base; } @@ -131,8 +125,10 @@ cairo_ps_surface_create (const char *filename, cairo_output_stream_t *stream; stream = _cairo_output_stream_create_for_file (filename); - if (stream == NULL) - return NULL; + if (stream == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } return _cairo_ps_surface_create_for_stream_internal (stream, width_in_points, @@ -148,196 +144,198 @@ cairo_ps_surface_create_for_stream (cairo_write_func_t write_func, cairo_output_stream_t *stream; stream = _cairo_output_stream_create (write_func, closure); - if (stream == NULL) - return NULL; + if (stream == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } return _cairo_ps_surface_create_for_stream_internal (stream, width_in_points, height_in_points); } -static cairo_surface_t * -_cairo_ps_surface_create_similar (void *abstract_src, - cairo_format_t format, - int drawable, - int width, - int height) -{ - return NULL; -} - static cairo_status_t _cairo_ps_surface_finish (void *abstract_surface) { cairo_ps_surface_t *surface = abstract_surface; + cairo_surface_t *page; + cairo_font_subset_t *subset; + cairo_status_t status; + int i; + time_t now; + + now = time (0); + + /* Document header */ + _cairo_output_stream_printf (surface->stream, + "%%!PS-Adobe-3.0\n" + "%%%%Creator: Cairo (http://cairographics.org)\n" + "%%%%CreationDate: %s" + "%%%%Title: Some clever title\n" + "%%%%Pages: %d\n" + "%%%%BoundingBox: %f %f %f %f\n", + ctime (&now), + surface->pages.num_elements, + 0.0, 0.0, + surface->width, + surface->height); + + /* The "/FlateDecode filter" currently used is a feature of + * LanguageLevel 3 */ + _cairo_output_stream_printf (surface->stream, + "%%%%DocumentData: Clean7Bit\n" + "%%%%LanguageLevel: 3\n" + "%%%%Orientation: Portrait\n" + "%%%%EndComments\n"); + + _cairo_ps_surface_write_font_subsets (surface); + + status = CAIRO_STATUS_SUCCESS; + for (i = 0; i < surface->pages.num_elements; i++) { + _cairo_array_copy_element (&surface->pages, i, &page); + + status = _cairo_ps_surface_render_page (surface, page, i + 1); + if (status) + break; + } /* Document footer */ _cairo_output_stream_printf (surface->stream, + "%%%%Trailer\n" "%%%%EOF\n"); - cairo_surface_destroy (&surface->image->base); + for (i = 0; i < surface->pages.num_elements; i++) { + _cairo_array_copy_element (&surface->pages, i, &page); + cairo_surface_destroy (page); + } + _cairo_array_fini (&surface->pages); - return CAIRO_STATUS_SUCCESS; + for (i = 0; i < surface->fonts.num_elements; i++) { + _cairo_array_copy_element (&surface->fonts, i, &subset); + _cairo_font_subset_destroy (subset); + } + _cairo_array_fini (&surface->fonts); + + _cairo_output_stream_destroy (surface->stream); + cairo_surface_destroy (surface->current_page); + + return status; } -static void -_cairo_ps_surface_erase (cairo_ps_surface_t *surface) +static cairo_int_status_t +_cairo_ps_surface_composite (cairo_operator_t operator, + cairo_pattern_t *src_pattern, + cairo_pattern_t *mask_pattern, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) { - _cairo_surface_fill_rectangle (&surface->image->base, - CAIRO_OPERATOR_SOURCE, - CAIRO_COLOR_TRANSPARENT, - 0, 0, - surface->image->width, - surface->image->height); + cairo_ps_surface_t *surface = abstract_dst; + + return _cairo_surface_composite (operator, + src_pattern, + mask_pattern, + surface->current_page, + src_x, + src_y, + mask_x, + mask_y, + dst_x, + dst_y, + width, + height); } -static cairo_status_t -_cairo_ps_surface_acquire_source_image (void *abstract_surface, - cairo_image_surface_t **image_out, - void **image_extra) +static cairo_int_status_t +_cairo_ps_surface_fill_rectangles (void *abstract_surface, + cairo_operator_t operator, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int num_rects) { cairo_ps_surface_t *surface = abstract_surface; - - *image_out = surface->image; - return CAIRO_STATUS_SUCCESS; + return _cairo_surface_fill_rectangles (surface->current_page, + operator, + color, + rects, + num_rects); } -static cairo_status_t -_cairo_ps_surface_acquire_dest_image (void *abstract_surface, - cairo_rectangle_t *interest_rect, - cairo_image_surface_t **image_out, - cairo_rectangle_t *image_rect, - void **image_extra) +static cairo_int_status_t +_cairo_ps_surface_composite_trapezoids (cairo_operator_t operator, + cairo_pattern_t *pattern, + void *abstract_dst, + cairo_antialias_t antialias, + int x_src, + int y_src, + int x_dst, + int y_dst, + unsigned int width, + unsigned int height, + cairo_trapezoid_t *traps, + int num_traps) { - cairo_ps_surface_t *surface = abstract_surface; - - image_rect->x = 0; - image_rect->y = 0; - image_rect->width = surface->image->width; - image_rect->height = surface->image->height; - - *image_out = surface->image; + cairo_ps_surface_t *surface = abstract_dst; - return CAIRO_STATUS_SUCCESS; + return _cairo_surface_composite_trapezoids (operator, + pattern, + surface->current_page, + antialias, + x_src, + y_src, + x_dst, + y_dst, + width, + height, + traps, + num_traps); } static cairo_int_status_t _cairo_ps_surface_copy_page (void *abstract_surface) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_ps_surface_t *surface = abstract_surface; - int width = surface->image->width; - int height = surface->image->height; - cairo_output_stream_t *stream = surface->stream; - int i, x, y; + /* FIXME: We need to copy the meta surface contents here */ - cairo_solid_pattern_t white_pattern; - unsigned char *rgb, *compressed; - unsigned long rgb_size, compressed_size; - - rgb_size = 3 * width * height; - rgb = malloc (rgb_size); - if (rgb == NULL) { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL0; - } - - compressed_size = (int) (1.0 + 1.1 * rgb_size); - compressed = malloc (compressed_size); - if (compressed == NULL) { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL1; - } - - /* PostScript can not represent the alpha channel, so we blend the - current image over a white RGB surface to eliminate it. */ - - _cairo_pattern_init_solid (&white_pattern, CAIRO_COLOR_WHITE); - - _cairo_surface_composite (CAIRO_OPERATOR_DEST_OVER, - &white_pattern.base, - NULL, - &surface->image->base, - 0, 0, - 0, 0, - 0, 0, - width, height); - - _cairo_pattern_fini (&white_pattern.base); - - i = 0; - for (y = 0; y < height; y++) { - pixman_bits_t *pixel = (pixman_bits_t *) (surface->image->data + y * surface->image->stride); - for (x = 0; x < width; x++, pixel++) { - rgb[i++] = (*pixel & 0x00ff0000) >> 16; - rgb[i++] = (*pixel & 0x0000ff00) >> 8; - rgb[i++] = (*pixel & 0x000000ff) >> 0; - } - } - - compress (compressed, &compressed_size, rgb, rgb_size); - - /* Page header */ - _cairo_output_stream_printf (stream, "%%%%Page: %d\n", ++surface->pages); - - _cairo_output_stream_printf (stream, "gsave\n"); - - /* Image header goop */ - _cairo_output_stream_printf (stream, "%f %f translate\n", - 0.0, surface->height_in_points); - _cairo_output_stream_printf (stream, "/DeviceRGB setcolorspace\n"); - _cairo_output_stream_printf (stream, "<<\n"); - _cairo_output_stream_printf (stream, " /ImageType 1\n"); - _cairo_output_stream_printf (stream, " /Width %d\n", width); - _cairo_output_stream_printf (stream, " /Height %d\n", height); - _cairo_output_stream_printf (stream, " /BitsPerComponent 8\n"); - _cairo_output_stream_printf (stream, " /Decode [ 0 1 0 1 0 1 ]\n"); - _cairo_output_stream_printf (stream, " /DataSource currentfile /FlateDecode filter\n"); - _cairo_output_stream_printf (stream, " /ImageMatrix [ 1 0 0 -1 0 1 ]\n"); - _cairo_output_stream_printf (stream, ">>\n"); - _cairo_output_stream_printf (stream, "image\n"); - - /* Compressed image data */ - _cairo_output_stream_write (stream, compressed, compressed_size); - - _cairo_output_stream_printf (stream, "showpage\n"); - - _cairo_output_stream_printf (stream, "grestore\n"); - - /* Page footer */ - _cairo_output_stream_printf (stream, "%%%%EndPage\n"); - - free (compressed); - BAIL1: - free (rgb); - BAIL0: - return status; + return _cairo_surface_show_page (&surface->base); } static cairo_int_status_t _cairo_ps_surface_show_page (void *abstract_surface) { - cairo_int_status_t status; cairo_ps_surface_t *surface = abstract_surface; - status = _cairo_ps_surface_copy_page (surface); - if (status) - return status; - - _cairo_ps_surface_erase (surface); + _cairo_array_append (&surface->pages, &surface->current_page, 1); + surface->current_page = _cairo_meta_surface_create (surface->width, + surface->height); + if (surface->current_page->status) + return CAIRO_STATUS_NO_MEMORY; return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t -_cairo_ps_surface_set_clip_region (void *abstract_surface, - pixman_region16_t *region) +_cairo_ps_surface_intersect_clip_path (void *dst, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) { - cairo_ps_surface_t *surface = abstract_surface; + cairo_ps_surface_t *surface = dst; - return _cairo_image_surface_set_clip_region (surface->image, region); + return _cairo_surface_intersect_clip_path (surface->current_page, + path, + fill_rule, + tolerance, + antialias); } static cairo_int_status_t @@ -353,26 +351,984 @@ _cairo_ps_surface_get_extents (void *abstract_surface, * mention the aribitray limitation of width to a short(!). We * may need to come up with a better interface for get_size. */ - rectangle->width = (surface->width_in_points + 0.5); - rectangle->height = (surface->height_in_points + 0.5); + rectangle->width = surface->width; + rectangle->height = surface->height; return CAIRO_STATUS_SUCCESS; } +static cairo_font_subset_t * +_cairo_ps_surface_get_font (cairo_ps_surface_t *surface, + cairo_scaled_font_t *scaled_font) +{ + cairo_unscaled_font_t *unscaled_font; + cairo_font_subset_t *subset; + unsigned int num_fonts, i; + + /* XXX: Need to fix this to work with a general cairo_scaled_font_t. */ + if (! _cairo_scaled_font_is_ft (scaled_font)) + return NULL; + + /* XXX Why is this an ft specific function? */ + unscaled_font = _cairo_ft_scaled_font_get_unscaled_font (scaled_font); + + num_fonts = _cairo_array_num_elements (&surface->fonts); + for (i = 0; i < num_fonts; i++) { + _cairo_array_copy_element (&surface->fonts, i, &subset); + if (subset->unscaled_font == unscaled_font) + return subset; + } + + subset = _cairo_font_subset_create (unscaled_font); + if (subset == NULL) + return NULL; + + subset->font_id = surface->fonts.num_elements; + if (_cairo_array_append (&surface->fonts, &subset, 1) == NULL) { + _cairo_font_subset_destroy (subset); + return NULL; + } + + return subset; +} + +static cairo_int_status_t +_cairo_ps_surface_show_glyphs (cairo_scaled_font_t *scaled_font, + cairo_operator_t operator, + cairo_pattern_t *pattern, + void *abstract_surface, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, + const cairo_glyph_t *glyphs, + int num_glyphs) +{ + cairo_ps_surface_t *surface = abstract_surface; + cairo_font_subset_t *subset; + int i; + + /* XXX: Need to fix this to work with a general cairo_scaled_font_t. */ + if (! _cairo_scaled_font_is_ft (scaled_font)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Collect font subset info as we go. */ + subset = _cairo_ps_surface_get_font (surface, scaled_font); + if (subset == NULL) + return CAIRO_STATUS_NO_MEMORY; + + for (i = 0; i < num_glyphs; i++) + _cairo_font_subset_use_glyph (subset, glyphs[i].index); + + return _cairo_surface_show_glyphs (scaled_font, + operator, + pattern, + surface->current_page, + source_x, + source_y, + dest_x, + dest_y, + width, + height, + glyphs, + num_glyphs); +} + +static cairo_int_status_t +_cairo_ps_surface_fill_path (cairo_operator_t operator, + cairo_pattern_t *pattern, + void *abstract_dst, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance) +{ + cairo_ps_surface_t *surface = abstract_dst; + + return _cairo_surface_fill_path (operator, + pattern, + surface->current_page, + path, + fill_rule, + tolerance); +} + static const cairo_surface_backend_t cairo_ps_surface_backend = { - _cairo_ps_surface_create_similar, + NULL, /* create_similar */ _cairo_ps_surface_finish, - _cairo_ps_surface_acquire_source_image, + NULL, /* acquire_source_image */ NULL, /* release_source_image */ - _cairo_ps_surface_acquire_dest_image, + NULL, /* acquire_dest_image */ NULL, /* release_dest_image */ NULL, /* clone_similar */ - NULL, /* composite */ - NULL, /* fill_rectangles */ - NULL, /* composite_trapezoids */ + _cairo_ps_surface_composite, + _cairo_ps_surface_fill_rectangles, + _cairo_ps_surface_composite_trapezoids, _cairo_ps_surface_copy_page, _cairo_ps_surface_show_page, - _cairo_ps_surface_set_clip_region, + NULL, /* set_clip_region */ + _cairo_ps_surface_intersect_clip_path, _cairo_ps_surface_get_extents, - NULL /* show_glyphs */ + _cairo_ps_surface_show_glyphs, + _cairo_ps_surface_fill_path }; + +static cairo_int_status_t +_cairo_ps_surface_write_type42_dict (cairo_ps_surface_t *surface, + cairo_font_subset_t *subset) +{ + const char *data; + unsigned long data_size; + cairo_status_t status; + int i; + + status = CAIRO_STATUS_SUCCESS; + + /* FIXME: Figure out document structure convention for fonts */ + + _cairo_output_stream_printf (surface->stream, + "11 dict begin\n" + "/FontType 42 def\n" + "/FontName /f%d def\n" + "/PaintType 0 def\n" + "/FontMatrix [ 1 0 0 1 0 0 ] def\n" + "/FontBBox [ 0 0 0 0 ] def\n" + "/Encoding 256 array def\n" + "0 1 255 { Encoding exch /.notdef put } for\n", + subset->font_id); + + /* FIXME: Figure out how subset->x_max etc maps to the /FontBBox */ + + for (i = 1; i < subset->num_glyphs; i++) + _cairo_output_stream_printf (surface->stream, + "Encoding %d /g%d put\n", i, i); + + _cairo_output_stream_printf (surface->stream, + "/CharStrings %d dict dup begin\n" + "/.notdef 0 def\n", + subset->num_glyphs); + + for (i = 1; i < subset->num_glyphs; i++) + _cairo_output_stream_printf (surface->stream, + "/g%d %d def\n", i, i); + + _cairo_output_stream_printf (surface->stream, + "end readonly def\n"); + + status = _cairo_font_subset_generate (subset, &data, &data_size); + + /* FIXME: We need to break up fonts bigger than 64k so we don't + * exceed string size limitation. At glyph boundaries. Stupid + * postscript. */ + _cairo_output_stream_printf (surface->stream, + "/sfnts [<"); + + _cairo_output_stream_write_hex_string (surface->stream, data, data_size); + + _cairo_output_stream_printf (surface->stream, + ">] def\n" + "FontName currentdict end definefont pop\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_ps_surface_write_font_subsets (cairo_ps_surface_t *surface) +{ + cairo_font_subset_t *subset; + int i; + + for (i = 0; i < surface->fonts.num_elements; i++) { + _cairo_array_copy_element (&surface->fonts, i, &subset); + _cairo_ps_surface_write_type42_dict (surface, subset); + } + + return CAIRO_STATUS_SUCCESS; +} + +typedef struct _cairo_ps_fallback_area cairo_ps_fallback_area_t; +struct _cairo_ps_fallback_area { + int x, y; + unsigned int width, height; + cairo_ps_fallback_area_t *next; +}; + +typedef struct _ps_output_surface { + cairo_surface_t base; + cairo_ps_surface_t *parent; + cairo_ps_fallback_area_t *fallback_areas; +} ps_output_surface_t; + +static cairo_int_status_t +_ps_output_add_fallback_area (ps_output_surface_t *surface, + int x, int y, + unsigned int width, + unsigned int height) +{ + cairo_ps_fallback_area_t *area; + + /* FIXME: Do a better job here. Ideally, we would use a 32 bit + * region type, but probably just computing bounding boxes would + * also work fine. */ + + area = malloc (sizeof (cairo_ps_fallback_area_t)); + if (area == NULL) + return CAIRO_STATUS_NO_MEMORY; + + area->x = x; + area->y = y; + area->width = width; + area->height = height; + area->next = surface->fallback_areas; + + surface->fallback_areas = area; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_ps_output_finish (void *abstract_surface) +{ + ps_output_surface_t *surface = abstract_surface; + cairo_ps_fallback_area_t *area, *next; + + for (area = surface->fallback_areas; area != NULL; area = next) { + next = area->next; + free (area); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +color_is_gray (cairo_color_t *color) +{ + const double epsilon = 0.00001; + + return (fabs (color->red - color->green) < epsilon && + fabs (color->red - color->blue) < epsilon); +} + +static cairo_bool_t +pattern_is_translucent (cairo_pattern_t *abstract_pattern) +{ + cairo_pattern_union_t *pattern; + + pattern = (cairo_pattern_union_t *) abstract_pattern; + switch (pattern->base.type) { + case CAIRO_PATTERN_SOLID: + return pattern->solid.color.alpha < 0.9; + case CAIRO_PATTERN_SURFACE: + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: + return FALSE; + } + + ASSERT_NOT_REACHED; + return FALSE; +} + +/* PS Output - this section handles output of the parts of the meta + * surface we can render natively in PS. */ + +static void * +compress_dup (const void *data, unsigned long data_size, + unsigned long *compressed_size) +{ + void *compressed; + + /* Bound calculation taken from zlib. */ + *compressed_size = data_size + (data_size >> 12) + (data_size >> 14) + 11; + compressed = malloc (*compressed_size); + if (compressed == NULL) + return NULL; + + compress (compressed, compressed_size, data, data_size); + + return compressed; +} + +static cairo_status_t +emit_image (cairo_ps_surface_t *surface, + cairo_image_surface_t *image, + cairo_matrix_t *matrix) +{ + cairo_status_t status; + unsigned char *rgb, *compressed; + unsigned long rgb_size, compressed_size; + cairo_surface_t *opaque; + cairo_pattern_union_t pattern; + cairo_matrix_t d2i; + int x, y, i; + + /* PostScript can not represent the alpha channel, so we blend the + current image over a white RGB surface to eliminate it. */ + + if (image->base.status) + return image->base.status; + + opaque = _cairo_surface_create_similar_solid (&image->base, + CAIRO_CONTENT_COLOR, + image->width, + image->height, + CAIRO_COLOR_WHITE); + if (opaque->status) { + status = CAIRO_STATUS_NO_MEMORY; + goto bail0; + } + + _cairo_pattern_init_for_surface (&pattern.surface, &image->base); + + _cairo_surface_composite (CAIRO_OPERATOR_DEST_OVER, + &pattern.base, + NULL, + opaque, + 0, 0, + 0, 0, + 0, 0, + image->width, + image->height); + + _cairo_pattern_fini (&pattern.base); + + rgb_size = 3 * image->width * image->height; + rgb = malloc (rgb_size); + if (rgb == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto bail1; + } + + i = 0; + for (y = 0; y < image->height; y++) { + pixman_bits_t *pixel = (pixman_bits_t *) (image->data + y * image->stride); + for (x = 0; x < image->width; x++, pixel++) { + rgb[i++] = (*pixel & 0x00ff0000) >> 16; + rgb[i++] = (*pixel & 0x0000ff00) >> 8; + rgb[i++] = (*pixel & 0x000000ff) >> 0; + } + } + + compressed = compress_dup (rgb, rgb_size, &compressed_size); + if (compressed == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto bail2; + } + + /* matrix transforms from user space to image space. We need to + * transform from device space to image space to compensate for + * postscripts coordinate system. */ + cairo_matrix_init (&d2i, 1, 0, 0, -1, 0, surface->height); + cairo_matrix_multiply (&d2i, &d2i, matrix); + + _cairo_output_stream_printf (surface->stream, + "/DeviceRGB setcolorspace\n" + "<<\n" + " /ImageType 1\n" + " /Width %d\n" + " /Height %d\n" + " /BitsPerComponent 8\n" + " /Decode [ 0 1 0 1 0 1 ]\n" + " /DataSource currentfile\n" + " /ImageMatrix [ %f %f %f %f %f %f ]\n" + ">>\n" + "image\n", + image->width, + image->height, + d2i.xx, d2i.yx, + d2i.xy, d2i.yy, + d2i.x0, d2i.y0); + + /* Compressed image data */ + _cairo_output_stream_write (surface->stream, rgb, rgb_size); + status = CAIRO_STATUS_SUCCESS; + + _cairo_output_stream_printf (surface->stream, + "\n"); + + free (compressed); + bail2: + free (rgb); + bail1: + cairo_surface_destroy (opaque); + bail0: + return status; +} + +static void +emit_solid_pattern (cairo_ps_surface_t *surface, + cairo_solid_pattern_t *pattern) +{ + if (color_is_gray (&pattern->color)) + _cairo_output_stream_printf (surface->stream, + "%f setgray\n", + pattern->color.red); + else + _cairo_output_stream_printf (surface->stream, + "%f %f %f setrgbcolor\n", + pattern->color.red, + pattern->color.green, + pattern->color.blue); +} + +static void +emit_surface_pattern (cairo_ps_surface_t *surface, + cairo_surface_pattern_t *pattern) +{ +} + +static void +emit_linear_pattern (cairo_ps_surface_t *surface, + cairo_linear_pattern_t *pattern) +{ +} + +static void +emit_radial_pattern (cairo_ps_surface_t *surface, + cairo_radial_pattern_t *pattern) +{ +} + +static void +emit_pattern (cairo_ps_surface_t *surface, cairo_pattern_t *pattern) +{ + /* FIXME: We should keep track of what pattern is currently set in + * the postscript file and only emit code if we're setting a + * different pattern. */ + + switch (pattern->type) { + case CAIRO_PATTERN_SOLID: + emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern); + break; + + case CAIRO_PATTERN_SURFACE: + emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern); + break; + + case CAIRO_PATTERN_LINEAR: + emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern); + break; + + case CAIRO_PATTERN_RADIAL: + emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern); + break; + } +} + + +static cairo_int_status_t +_ps_output_composite (cairo_operator_t operator, + cairo_pattern_t *src_pattern, + cairo_pattern_t *mask_pattern, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + ps_output_surface_t *surface = abstract_dst; + cairo_output_stream_t *stream = surface->parent->stream; + cairo_surface_pattern_t *surface_pattern; + cairo_status_t status; + cairo_image_surface_t *image; + void *image_extra; + + if (mask_pattern) { + /* FIXME: Investigate how this can be done... we'll probably + * need pixmap fallbacks for this, though. */ + _cairo_output_stream_printf (stream, + "%% _ps_output_composite: with mask\n"); + return CAIRO_STATUS_SUCCESS; + } + + status = CAIRO_STATUS_SUCCESS; + switch (src_pattern->type) { + case CAIRO_PATTERN_SOLID: + _cairo_output_stream_printf (stream, + "%% _ps_output_composite: solid\n"); + break; + + case CAIRO_PATTERN_SURFACE: + surface_pattern = (cairo_surface_pattern_t *) src_pattern; + + if (src_pattern->extend != CAIRO_EXTEND_NONE) { + _cairo_output_stream_printf (stream, + "%% _ps_output_composite: repeating image\n"); + break; + } + + + status = _cairo_surface_acquire_source_image (surface_pattern->surface, + &image, + &image_extra); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + _cairo_output_stream_printf (stream, + "%% _ps_output_composite: src_pattern not available as image\n"); + break; + } else if (status) { + break; + } + status = emit_image (surface->parent, image, &src_pattern->matrix); + _cairo_surface_release_source_image (surface_pattern->surface, + image, image_extra); + break; + + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: + _cairo_output_stream_printf (stream, + "%% _ps_output_composite: gradient\n"); + break; + } + + return status; +} + +static cairo_int_status_t +_ps_output_fill_rectangles (void *abstract_surface, + cairo_operator_t operator, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int num_rects) +{ + ps_output_surface_t *surface = abstract_surface; + cairo_output_stream_t *stream = surface->parent->stream; + cairo_solid_pattern_t solid; + int i; + + _cairo_output_stream_printf (stream, + "%% _ps_output_fill_rectangles\n"); + + _cairo_pattern_init_solid (&solid, color); + emit_pattern (surface->parent, &solid.base); + _cairo_pattern_fini (&solid.base); + + _cairo_output_stream_printf (stream, "["); + for (i = 0; i < num_rects; i++) { + _cairo_output_stream_printf (stream, + " %d %f %d %d", + rects[i].x, + (double)(surface->parent->height - rects[i].y - rects[i].height), + rects[i].width, rects[i].height); + } + + _cairo_output_stream_printf (stream, " ] rectfill\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static double +intersect (cairo_line_t *line, cairo_fixed_t y) +{ + return _cairo_fixed_to_double (line->p1.x) + + _cairo_fixed_to_double (line->p2.x - line->p1.x) * + _cairo_fixed_to_double (y - line->p1.y) / + _cairo_fixed_to_double (line->p2.y - line->p1.y); +} + +static cairo_int_status_t +_ps_output_composite_trapezoids (cairo_operator_t operator, + cairo_pattern_t *pattern, + void *abstract_dst, + cairo_antialias_t antialias, + int x_src, + int y_src, + int x_dst, + int y_dst, + unsigned int width, + unsigned int height, + cairo_trapezoid_t *traps, + int num_traps) +{ + ps_output_surface_t *surface = abstract_dst; + cairo_output_stream_t *stream = surface->parent->stream; + int i; + + if (pattern_is_translucent (pattern)) + return _ps_output_add_fallback_area (surface, x_dst, y_dst, width, height); + + _cairo_output_stream_printf (stream, + "%% _ps_output_composite_trapezoids\n"); + + emit_pattern (surface->parent, pattern); + + for (i = 0; i < num_traps; i++) { + double left_x1, left_x2, right_x1, right_x2, top, bottom; + + left_x1 = intersect (&traps[i].left, traps[i].top); + left_x2 = intersect (&traps[i].left, traps[i].bottom); + right_x1 = intersect (&traps[i].right, traps[i].top); + right_x2 = intersect (&traps[i].right, traps[i].bottom); + top = surface->parent->height - _cairo_fixed_to_double (traps[i].top); + bottom = surface->parent->height - _cairo_fixed_to_double (traps[i].bottom); + + _cairo_output_stream_printf + (stream, + "%f %f moveto %f %f lineto %f %f lineto %f %f lineto " + "closepath\n", + left_x1, top, + left_x2, bottom, + right_x2, bottom, + right_x1, top); + } + + _cairo_output_stream_printf (stream, + "fill\n"); + + return CAIRO_STATUS_SUCCESS; +} + +typedef struct +{ + double height; + cairo_output_stream_t *output_stream; + cairo_bool_t has_current_point; +} ps_output_path_info_t; + +static cairo_status_t +_ps_output_path_move_to (void *closure, cairo_point_t *point) +{ + ps_output_path_info_t *info = closure; + + _cairo_output_stream_printf (info->output_stream, + "%f %f moveto ", + _cairo_fixed_to_double (point->x), + info->height - _cairo_fixed_to_double (point->y)); + info->has_current_point = TRUE; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_ps_output_path_line_to (void *closure, cairo_point_t *point) +{ + ps_output_path_info_t *info = closure; + const char *ps_operator; + + if (info->has_current_point) + ps_operator = "lineto"; + else + ps_operator = "moveto"; + + _cairo_output_stream_printf (info->output_stream, + "%f %f %s ", + _cairo_fixed_to_double (point->x), + info->height - _cairo_fixed_to_double (point->y), + ps_operator); + info->has_current_point = TRUE; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_ps_output_path_curve_to (void *closure, + cairo_point_t *b, + cairo_point_t *c, + cairo_point_t *d) +{ + ps_output_path_info_t *info = closure; + + _cairo_output_stream_printf (info->output_stream, + "%f %f %f %f %f %f curveto ", + _cairo_fixed_to_double (b->x), + info->height - _cairo_fixed_to_double (b->y), + _cairo_fixed_to_double (c->x), + info->height - _cairo_fixed_to_double (c->y), + _cairo_fixed_to_double (d->x), + info->height - _cairo_fixed_to_double (d->y)); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_ps_output_path_close_path (void *closure) +{ + ps_output_path_info_t *info = closure; + + _cairo_output_stream_printf (info->output_stream, + "closepath\n"); + info->has_current_point = FALSE; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_ps_output_intersect_clip_path (void *abstract_surface, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + ps_output_surface_t *surface = abstract_surface; + cairo_output_stream_t *stream = surface->parent->stream; + cairo_status_t status; + ps_output_path_info_t info; + const char *ps_operator; + + _cairo_output_stream_printf (stream, + "%% _ps_output_intersect_clip_path\n"); + + if (path == NULL) { + _cairo_output_stream_printf (stream, "initclip\n"); + return CAIRO_STATUS_SUCCESS; + } + + info.output_stream = stream; + info.has_current_point = FALSE; + info.height = surface->parent->height; + + status = _cairo_path_fixed_interpret (path, + CAIRO_DIRECTION_FORWARD, + _ps_output_path_move_to, + _ps_output_path_line_to, + _ps_output_path_curve_to, + _ps_output_path_close_path, + &info); + + switch (fill_rule) { + case CAIRO_FILL_RULE_WINDING: + ps_operator = "clip"; + break; + case CAIRO_FILL_RULE_EVEN_ODD: + ps_operator = "eoclip"; + break; + default: + ASSERT_NOT_REACHED; + } + + _cairo_output_stream_printf (stream, + "%s newpath\n", + ps_operator); + + return status; +} + + +static cairo_int_status_t +_ps_output_show_glyphs (cairo_scaled_font_t *scaled_font, + cairo_operator_t operator, + cairo_pattern_t *pattern, + void *abstract_surface, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, + const cairo_glyph_t *glyphs, + int num_glyphs) +{ + ps_output_surface_t *surface = abstract_surface; + cairo_output_stream_t *stream = surface->parent->stream; + cairo_font_subset_t *subset; + int i, subset_index; + + /* XXX: Need to fix this to work with a general cairo_scaled_font_t. */ + if (! _cairo_scaled_font_is_ft (scaled_font)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (pattern_is_translucent (pattern)) + return _ps_output_add_fallback_area (surface, dest_x, dest_y, width, height); + + _cairo_output_stream_printf (stream, + "%% _ps_output_show_glyphs\n"); + + emit_pattern (surface->parent, pattern); + + /* FIXME: Need to optimize this so we only do this sequence if the + * font isn't already set. */ + + subset = _cairo_ps_surface_get_font (surface->parent, scaled_font); + _cairo_output_stream_printf (stream, + "/f%d findfont\n" + "[ %f %f %f %f 0 0 ] makefont\n" + "setfont\n", + subset->font_id, + scaled_font->scale.xx, + scaled_font->scale.yx, + scaled_font->scale.xy, + scaled_font->scale.yy); + + /* FIXME: Need to optimize per glyph code. Should detect when + * glyphs share the same baseline and when the spacing corresponds + * to the glyph widths. */ + + for (i = 0; i < num_glyphs; i++) { + subset_index = _cairo_font_subset_use_glyph (subset, glyphs[i].index); + _cairo_output_stream_printf (stream, + "%f %f moveto (\\%o) show\n", + glyphs[i].x, + surface->parent->height - glyphs[i].y, + subset_index); + + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_ps_output_fill_path (cairo_operator_t operator, + cairo_pattern_t *pattern, + void *abstract_dst, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance) +{ + ps_output_surface_t *surface = abstract_dst; + cairo_output_stream_t *stream = surface->parent->stream; + cairo_int_status_t status; + ps_output_path_info_t info; + const char *ps_operator; + + _cairo_output_stream_printf (stream, + "%% _ps_output_fill_path\n"); + + emit_pattern (surface->parent, pattern); + + info.output_stream = stream; + info.has_current_point = FALSE; + info.height = surface->parent->height; + + status = _cairo_path_fixed_interpret (path, + CAIRO_DIRECTION_FORWARD, + _ps_output_path_move_to, + _ps_output_path_line_to, + _ps_output_path_curve_to, + _ps_output_path_close_path, + &info); + + switch (fill_rule) { + case CAIRO_FILL_RULE_WINDING: + ps_operator = "fill"; + break; + case CAIRO_FILL_RULE_EVEN_ODD: + ps_operator = "eofill"; + break; + default: + ASSERT_NOT_REACHED; + } + + _cairo_output_stream_printf (stream, + "%s\n", ps_operator); + + return status; +} + +static const cairo_surface_backend_t ps_output_backend = { + NULL, /* create_similar */ + _ps_output_finish, + NULL, /* acquire_source_image */ + NULL, /* release_source_image */ + NULL, /* acquire_dest_image */ + NULL, /* release_dest_image */ + NULL, /* clone_similar */ + _ps_output_composite, + _ps_output_fill_rectangles, + _ps_output_composite_trapezoids, + NULL, /* copy_page */ + NULL, /* show_page */ + NULL, /* set_clip_region */ + _ps_output_intersect_clip_path, + NULL, /* get_extents */ + _ps_output_show_glyphs, + _ps_output_fill_path +}; + +static cairo_int_status_t +_ps_output_render_fallbacks (cairo_surface_t *surface, + cairo_surface_t *page) +{ + ps_output_surface_t *ps_output; + cairo_surface_t *image; + cairo_int_status_t status; + cairo_matrix_t matrix; + int width, height; + + ps_output = (ps_output_surface_t *) surface; + if (ps_output->fallback_areas == NULL) + return CAIRO_STATUS_SUCCESS; + + width = ps_output->parent->width * ps_output->parent->x_dpi / 72; + height = ps_output->parent->height * ps_output->parent->y_dpi / 72; + + image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); + if (image->status) + return CAIRO_STATUS_NO_MEMORY; + + status = _cairo_surface_fill_rectangle (image, + CAIRO_OPERATOR_SOURCE, + CAIRO_COLOR_WHITE, + 0, 0, width, height); + if (status) + goto bail; + + status = _cairo_meta_surface_replay (page, image); + if (status) + goto bail; + + matrix.xx = 1; + matrix.xy = 0; + matrix.yx = 0; + matrix.yy = 1; + matrix.x0 = 0; + matrix.y0 = 0; + + status = emit_image (ps_output->parent, + (cairo_image_surface_t *) image, &matrix); + + bail: + cairo_surface_destroy (image); + + return status; +} + +static cairo_surface_t * +_ps_output_surface_create (cairo_ps_surface_t *parent) +{ + ps_output_surface_t *ps_output; + + ps_output = malloc (sizeof (ps_output_surface_t)); + if (ps_output == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } + + _cairo_surface_init (&ps_output->base, &ps_output_backend); + ps_output->parent = parent; + ps_output->fallback_areas = NULL; + + return &ps_output->base; +} + +static cairo_int_status_t +_cairo_ps_surface_render_page (cairo_ps_surface_t *surface, + cairo_surface_t *page, int page_number) +{ + cairo_surface_t *ps_output; + cairo_int_status_t status; + + _cairo_output_stream_printf (surface->stream, + "%%%%Page: %d\n" + "gsave\n", + page_number); + + ps_output = _ps_output_surface_create (surface); + if (ps_output->status) + return CAIRO_STATUS_NO_MEMORY; + + status = _cairo_meta_surface_replay (page, ps_output); + + _ps_output_render_fallbacks (ps_output, page); + + cairo_surface_destroy (ps_output); + + _cairo_output_stream_printf (surface->stream, + "showpage\n" + "grestore\n" + "%%%%EndPage\n"); + + return status; +} diff --git a/gfx/cairo/cairo/src/cairo-ps.h b/gfx/cairo/cairo/src/cairo-ps.h index 9c3cfb0a7969..ea2d53d092dd 100644 --- a/gfx/cairo/cairo/src/cairo-ps.h +++ b/gfx/cairo/cairo/src/cairo-ps.h @@ -39,7 +39,7 @@ #include -#ifdef CAIRO_HAS_PS_SURFACE +#if CAIRO_HAS_PS_SURFACE #include diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c index 292f5b491c92..70f408a3b7b8 100644 --- a/gfx/cairo/cairo/src/cairo-quartz-surface.c +++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c @@ -58,17 +58,6 @@ ImageDataReleaseFunc(void *info, const void *data, size_t size) } } -static cairo_surface_t *_cairo_quartz_surface_create_similar(void - *abstract_src, - cairo_format_t - format, - int drawable, - int width, - int height) -{ - return NULL; -} - static cairo_status_t _cairo_quartz_surface_finish(void *abstract_surface) { @@ -135,12 +124,11 @@ _cairo_quartz_surface_acquire_source_image(void *abstract_surface, CAIRO_FORMAT_ARGB32, surface->width, surface->height, rowBytes); - - - // Set the image surface Cairo state to match our own. - _cairo_image_surface_set_repeat(surface->image, surface->base.repeat); - _cairo_image_surface_set_matrix(surface->image, - &(surface->base.matrix)); + if (surface->image->base.status) { + /* XXX: I assume we're leaking memory here, but I don't know + * the right call to use to clean up from CGImageCreate. */ + return CAIRO_STATUS_NO_MEMORY; + } *image_out = surface->image; *image_extra = NULL; @@ -164,6 +152,8 @@ _cairo_quartz_surface_acquire_dest_image(void *abstract_surface, image_rect->height = surface->image->height; *image_out = surface->image; + if (image_extra) + *image_extra = NULL; return CAIRO_STATUS_SUCCESS; } @@ -195,8 +185,11 @@ _cairo_quartz_surface_set_clip_region(void *abstract_surface, pixman_region16_t * region) { cairo_quartz_surface_t *surface = abstract_surface; + unsigned int serial; - return _cairo_surface_set_clip_region(&surface->image->base, region); + serial = _cairo_surface_allocate_clip_serial (&surface->image->base); + return _cairo_surface_set_clip_region(&surface->image->base, + region, serial); } static cairo_int_status_t @@ -214,7 +207,7 @@ _cairo_quartz_surface_get_extents (void *abstract_surface, } static const struct _cairo_surface_backend cairo_quartz_surface_backend = { - _cairo_quartz_surface_create_similar, + NULL, /* create_similar */ _cairo_quartz_surface_finish, _cairo_quartz_surface_acquire_source_image, NULL, /* release_source_image */ @@ -227,6 +220,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 */ }; @@ -238,8 +232,10 @@ cairo_surface_t *cairo_quartz_surface_create(CGContextRef context, cairo_quartz_surface_t *surface; surface = malloc(sizeof(cairo_quartz_surface_t)); - if (surface == NULL) - return NULL; + if (surface == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } _cairo_surface_init(&surface->base, &cairo_quartz_surface_backend); diff --git a/gfx/cairo/cairo/src/cairo-quartz.h b/gfx/cairo/cairo/src/cairo-quartz.h index 271cd2a7ea02..dd929b29715c 100644 --- a/gfx/cairo/cairo/src/cairo-quartz.h +++ b/gfx/cairo/cairo/src/cairo-quartz.h @@ -39,16 +39,16 @@ #include -#ifdef CAIRO_HAS_QUARTZ_SURFACE +#if CAIRO_HAS_QUARTZ_SURFACE #include CAIRO_BEGIN_DECLS cairo_surface_t * -cairo_quartz_surface_create ( CGContextRef context, - int width, - int height); +cairo_quartz_surface_create (CGContextRef context, + int width, + int height); CAIRO_END_DECLS diff --git a/gfx/cairo/cairo/src/cairo-region.c b/gfx/cairo/cairo/src/cairo-region.c new file mode 100644 index 000000000000..369e2dc60114 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-region.c @@ -0,0 +1,83 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor + */ + +#include + +/** + * _cairo_region_create_from_rectangle: + * @rect: a #cairo_rectangle_t + * + * Creates a region with extents initialized from the given + * rectangle. + * + * Return value: a newly created #pixman_region16_t or %NULL if + * memory couldn't a allocated. + **/ +pixman_region16_t * +_cairo_region_create_from_rectangle (cairo_rectangle_t *rect) +{ + /* We can't use pixman_region_create_simple(), because it doesn't + * have an error return + */ + pixman_region16_t *region = pixman_region_create (); + if (pixman_region_union_rect (region, region, + rect->x, rect->y, + rect->width, rect->height) != PIXMAN_REGION_STATUS_SUCCESS) { + pixman_region_destroy (region); + return NULL; + } + + return region; +} + +/** + * _cairo_region_extents_rectangle: + * @region: a #pixman_region16_t + * @rect: rectangle into which to store the extents + * + * Gets the bounding box of a region as a cairo_rectangle_t + **/ +void +_cairo_region_extents_rectangle (pixman_region16_t *region, + cairo_rectangle_t *rect) +{ + pixman_box16_t *region_extents = pixman_region_extents (region); + + rect->x = region_extents->x1; + rect->y = region_extents->y1; + rect->width = region_extents->x2 - region_extents->x1; + rect->height = region_extents->y2 - region_extents->y1; +} + diff --git a/gfx/cairo/cairo/src/cairo-spline.c b/gfx/cairo/cairo/src/cairo-spline.c index 5119a8e2b672..60ad6c54de08 100644 --- a/gfx/cairo/cairo/src/cairo-spline.c +++ b/gfx/cairo/cairo/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/gfx/cairo/cairo/src/cairo-surface.c b/gfx/cairo/cairo/src/cairo-surface.c index 0bcf80cf8cfb..6ba25a7d26d5 100644 --- a/gfx/cairo/cairo/src/cairo-surface.c +++ b/gfx/cairo/cairo/src/cairo-surface.c @@ -38,17 +38,98 @@ #include #include "cairoint.h" +#include "cairo-gstate-private.h" -struct _cairo_surface_save { - cairo_surface_save_t *next; - pixman_region16_t *clip_region; +const cairo_surface_t _cairo_surface_nil = { + &cairo_image_surface_backend, /* backend */ + -1, /* ref_count */ + CAIRO_STATUS_NO_MEMORY, /* status */ + FALSE, /* finished */ + { 0, /* size */ + 0, /* num_elements */ + 0, /* element_size */ + NULL, /* elements */ + }, /* user_data */ + 0.0, /* device_x_offset */ + 0.0, /* device_y_offset */ + 0, /* next_clip_serial */ + 0 /* current_clip_serial */ }; -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); +const cairo_surface_t _cairo_surface_nil_file_not_found = { + &cairo_image_surface_backend, /* backend */ + -1, /* ref_count */ + CAIRO_STATUS_FILE_NOT_FOUND, /* status */ + FALSE, /* finished */ + { 0, /* size */ + 0, /* num_elements */ + 0, /* element_size */ + NULL, /* elements */ + }, /* user_data */ + 0.0, /* device_x_offset */ + 0.0, /* device_y_offset */ + 0, /* next_clip_serial */ + 0 /* current_clip_serial */ +}; + +const cairo_surface_t _cairo_surface_nil_read_error = { + &cairo_image_surface_backend, /* backend */ + -1, /* ref_count */ + CAIRO_STATUS_READ_ERROR, /* status */ + FALSE, /* finished */ + { 0, /* size */ + 0, /* num_elements */ + 0, /* element_size */ + NULL, /* elements */ + }, /* user_data */ + 0.0, /* device_x_offset */ + 0.0, /* device_y_offset */ + 0, /* next_clip_serial */ + 0 /* current_clip_serial */ +}; + +/** + * _cairo_surface_set_error: + * @surface: a surface + * @status: a status value indicating an error, (eg. not + * CAIRO_STATUS_SUCCESS) + * + * Sets surface->status to @status and calls _cairo_error; + * + * All assignments of an error status to surface->status should happen + * through _cairo_surface_set_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. + **/ +static void +_cairo_surface_set_error (cairo_surface_t *surface, + cairo_status_t status) +{ + surface->status = status; + + _cairo_error (status); +} + +/** + * cairo_surface_status: + * @surface: a #cairo_surface_t + * + * Checks whether an error has previously occurred for this + * surface. + * + * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NULL_POINTER, + * %CAIRO_STATUS_NO_MEMORY, %CAIRO_STATUS_READ_ERROR, + * %CAIRO_STATUS_INVALID_CONTENT, %CAIRO_STATUS_INVALUE_FORMAT, or + * %CAIRO_STATUS_INVALID_VISUAL. + **/ +cairo_status_t +cairo_surface_status (cairo_surface_t *surface) +{ + return surface->status; +} void _cairo_surface_init (cairo_surface_t *surface, @@ -57,154 +138,76 @@ _cairo_surface_init (cairo_surface_t *surface, surface->backend = backend; surface->ref_count = 1; + surface->status = CAIRO_STATUS_SUCCESS; surface->finished = FALSE; _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, +_cairo_surface_create_similar_scratch (cairo_surface_t *other, + cairo_content_t content, int width, int height) { - if (other == NULL) - return NULL; + cairo_format_t format = _cairo_format_from_content (content); - return other->backend->create_similar (other, format, drawable, - width, height); + if (other->status) + return (cairo_surface_t*) &_cairo_surface_nil; + + if (other->backend->create_similar) + return other->backend->create_similar (other, content, width, height); + else + return cairo_image_surface_create (format, width, height); } +/** + * cairo_surface_create_similar: + * @other: an existing surface used to select the backend of the new surface + * @content: the content for the new surface + * @width: width of the new surface, (in device-space units) + * @height: height of the new surface (in device-space units) + * + * Create a new surface that is as compatible as possible with an + * existing surface. The new surface will use the same backend as + * @other unless that is not possible for some reason. + * + * Return value: a pointer to the newly allocated surface. The caller + * owns the surface and should call cairo_surface_destroy when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if @other is already in an error state + * or any other error occurs. + **/ cairo_surface_t * -cairo_surface_create_similar (cairo_surface_t *other, - cairo_format_t format, +cairo_surface_create_similar (cairo_surface_t *other, + cairo_content_t content, int width, int height) { - if (other == NULL) - return NULL; + if (other->status) + return (cairo_surface_t*) &_cairo_surface_nil; - return _cairo_surface_create_similar_solid (other, format, + if (! CAIRO_CONTENT_VALID (content)) { + _cairo_error (CAIRO_STATUS_INVALID_CONTENT); + return (cairo_surface_t*) &_cairo_surface_nil; + } + + return _cairo_surface_create_similar_solid (other, content, width, height, CAIRO_COLOR_TRANSPARENT); } cairo_surface_t * _cairo_surface_create_similar_solid (cairo_surface_t *other, - cairo_format_t format, + cairo_content_t content, int width, int height, const cairo_color_t *color) @@ -212,45 +215,84 @@ _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, content, width, height); - - if (surface == NULL) - surface = cairo_image_surface_create (format, width, height); + if (surface->status) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } status = _cairo_surface_fill_rectangle (surface, CAIRO_OPERATOR_SOURCE, color, 0, 0, width, height); if (status) { cairo_surface_destroy (surface); - return NULL; + _cairo_error (status); + return (cairo_surface_t*) &_cairo_surface_nil; } return surface; } -void +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; +} + +/** + * cairo_surface_reference: + * @surface: a #cairo_surface_t + * + * Increases the reference count on @surface by one. This prevents + * @surface from being destroyed until a matching call to + * cairo_surface_destroy() is made. + * + * Return value: the referenced #cairo_surface_t. + **/ +cairo_surface_t * cairo_surface_reference (cairo_surface_t *surface) { if (surface == NULL) - return; + return NULL; + + if (surface->ref_count == (unsigned int)-1) + return surface; surface->ref_count++; + + return surface; } +/** + * cairo_surface_destroy: + * @surface: a #cairo_t + * + * Decreases the reference count on @surface by one. If the result is + * zero, then @surface and all associated resources are freed. See + * cairo_surface_reference(). + **/ void cairo_surface_destroy (cairo_surface_t *surface) { if (surface == NULL) return; + if (surface->ref_count == (unsigned int)-1) + return; + surface->ref_count--; if (surface->ref_count) return; cairo_surface_finish (surface); - _cairo_user_data_array_destroy (&surface->user_data); + _cairo_user_data_array_fini (&surface->user_data); free (surface); } @@ -265,44 +307,45 @@ slim_hidden_def(cairo_surface_destroy); * that cairo will no longer access the drawable, which can be freed. * After calling cairo_surface_finish() the only valid operations on a * surface are getting and setting user data and referencing and - * destroying it. Further drawing the the surface will not affect the - * surface but set the surface status to - * CAIRO_STATUS_SURFACE_FINISHED. + * destroying it. Further drawing to the surface will not affect the + * surface but will instead trigger a CAIRO_STATUS_SURFACE_FINISHED + * error. * * When the last call to cairo_surface_destroy() decreases the * reference count to zero, cairo will call cairo_surface_finish() if * it hasn't been called already, before freeing the resources * associated with the surface. - * - * Return value: CAIRO_STATUS_SUCCESS if the surface was finished - * successfully, otherwise CAIRO_STATUS_NO_MEMORY or - * CAIRO_STATUS_WRITE_ERROR. **/ -cairo_status_t +void cairo_surface_finish (cairo_surface_t *surface) { cairo_status_t status; - if (surface->finished) - return CAIRO_STATUS_SURFACE_FINISHED; - - if (surface->saves) - return CAIRO_STATUS_BAD_NESTING; - - if (surface->clip_region) { - pixman_region_destroy (surface->clip_region); - surface->clip_region = NULL; + if (surface->finished) { + _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); + return; } - if (surface->backend->finish) { - status = surface->backend->finish (surface); - if (status) - return status; + if (surface->backend->finish == NULL) { + surface->finished = TRUE; + return; + } + + if (!surface->status && surface->backend->flush) { + status = surface->backend->flush (surface); + if (status) { + _cairo_surface_set_error (surface, status); + return; + } + } + + status = surface->backend->finish (surface); + if (status) { + _cairo_surface_set_error (surface, status); + return; } surface->finished = TRUE; - - return CAIRO_STATUS_SUCCESS; } /** @@ -347,10 +390,123 @@ cairo_surface_set_user_data (cairo_surface_t *surface, void *user_data, cairo_destroy_func_t destroy) { + if (surface->ref_count == -1) + return CAIRO_STATUS_NO_MEMORY; + return _cairo_user_data_array_set_data (&surface->user_data, key, user_data, destroy); } +/** + * cairo_surface_get_font_options: + * @surface: a #cairo_surface_t + * @options: a #cairo_font_options_t object into which to store + * the retrieved options. All existing values are overwritten + * + * Retrieves the default font rendering options for the surface. + * This allows display surfaces to report the correct subpixel order + * for rendering on them, print surfaces to disable hinting of + * metrics and so forth. The result can then be used with + * cairo_scaled_font_create(). + **/ +void +cairo_surface_get_font_options (cairo_surface_t *surface, + cairo_font_options_t *options) +{ + if (!surface->finished && surface->backend->get_font_options) { + surface->backend->get_font_options (surface, options); + } else { + _cairo_font_options_init_default (options); + } +} + +/** + * cairo_surface_flush: + * @surface: a #cairo_surface_t + * + * Do any pending drawing for the surface and also restore any + * temporary modification's cairo has made to the surface's + * state. This function must be called before switching from + * drawing on the surface with cairo to drawing on it directly + * with native APIs. If the surface doesn't support direct access, + * then this function does nothing. + **/ +void +cairo_surface_flush (cairo_surface_t *surface) +{ + if (surface->status) { + _cairo_surface_set_error (surface, surface->status); + return; + } + + if (surface->finished) { + _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); + return; + } + + if (surface->backend->flush) { + cairo_status_t status; + + status = surface->backend->flush (surface); + + if (status) + _cairo_surface_set_error (surface, status); + } +} + +/** + * cairo_surface_mark_dirty: + * @surface: a #cairo_surface_t + * + * Tells cairo that drawing has been done to surface using means other + * than cairo, and that cairo should reread any cached areas. Note + * that you must call cairo_surface_flush() before doing such drawing. + */ +void +cairo_surface_mark_dirty (cairo_surface_t *surface) +{ + cairo_surface_mark_dirty_rectangle (surface, 0, 0, -1, -1); +} + +/** + * cairo_surface_mark_dirty_rectangle: + * @surface: a #cairo_surface_t + * @x: X coordinate of dirty rectangle + * @y: Y coordinate of dirty rectangle + * @width: width of dirty rectangle + * @height: height of dirty rectangle + * + * Like cairo_surface_mark_dirty(), but drawing has been done only to + * the specified rectangle, so that cairo can retain cached contents + * for other parts of the surface. + */ +void +cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, + int x, + int y, + int width, + int height) +{ + if (surface->status) { + _cairo_surface_set_error (surface, surface->status); + return; + } + + if (surface->finished) { + _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); + return; + } + + if (surface->backend->mark_dirty_rectangle) { + cairo_status_t status; + + status = surface->backend->mark_dirty_rectangle (surface, x, y, width, height); + + if (status) + _cairo_surface_set_error (surface, status); + } +} + /** * cairo_surface_set_device_offset: * @surface: a #cairo_surface_t @@ -374,6 +530,16 @@ cairo_surface_set_device_offset (cairo_surface_t *surface, double x_offset, double y_offset) { + if (surface->status) { + _cairo_surface_set_error (surface, surface->status); + return; + } + + if (surface->finished) { + _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); + return; + } + surface->device_x_offset = x_offset; surface->device_y_offset = y_offset; } @@ -395,7 +561,7 @@ cairo_surface_set_device_offset (cairo_surface_t *surface, * %CAIRO_INT_STATUS_UNSUPPORTED if an image cannot be retrieved for the specified * surface. Or %CAIRO_STATUS_NO_MEMORY. **/ -cairo_private cairo_status_t +cairo_status_t _cairo_surface_acquire_source_image (cairo_surface_t *surface, cairo_image_surface_t **image_out, void **image_extra) @@ -412,7 +578,7 @@ _cairo_surface_acquire_source_image (cairo_surface_t *surface, * * Releases any resources obtained with _cairo_surface_acquire_source_image() **/ -cairo_private void +void _cairo_surface_release_source_image (cairo_surface_t *surface, cairo_image_surface_t *image, void *image_extra) @@ -521,7 +687,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); @@ -548,7 +714,17 @@ typedef struct { void *image_extra; } fallback_state_t; -static cairo_status_t +/** + * _fallback_init: + * + * Acquire destination image surface needed for an image-based + * fallback. + * + * Return value: CAIRO_INT_STATUS_NOTHING_TO_DO if the extents are not + * visible, CAIRO_STATUS_SUCCESS if some portion is visible and all + * went well, or some error status otherwise. + **/ +static cairo_int_status_t _fallback_init (fallback_state_t *state, cairo_surface_t *dst, int x, @@ -556,6 +732,8 @@ _fallback_init (fallback_state_t *state, int width, int height) { + cairo_status_t status; + state->extents.x = x; state->extents.y = y; state->extents.width = width; @@ -563,15 +741,29 @@ _fallback_init (fallback_state_t *state, state->dst = dst; - return _cairo_surface_acquire_dest_image (dst, &state->extents, - &state->image, &state->image_rect, &state->image_extra); + status = _cairo_surface_acquire_dest_image (dst, &state->extents, + &state->image, &state->image_rect, + &state->image_extra); + if (status) + return status; + + /* XXX: This NULL value tucked away in state->image is a rather + * ugly interface. Cleaner would be to push the + * CAIRO_INT_STATUS_NOTHING_TO_DO value down into + * _cairo_surface_acquire_dest_image and its backend + * counterparts. */ + if (state->image == NULL) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + return CAIRO_STATUS_SUCCESS; } static void -_fallback_cleanup (fallback_state_t *state) +_fallback_fini (fallback_state_t *state) { _cairo_surface_release_dest_image (state->dst, &state->extents, - state->image, &state->image_rect, state->image_extra); + state->image, &state->image_rect, + state->image_extra); } static cairo_status_t @@ -592,18 +784,20 @@ _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) { + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + return CAIRO_STATUS_SUCCESS; return status; + } - state.image->base.backend->composite (operator, src, mask, - &state.image->base, - src_x, src_y, mask_x, mask_y, - dst_x - state.image_rect.x, - dst_y - state.image_rect.y, - width, height); + status = state.image->base.backend->composite (operator, src, mask, + &state.image->base, + src_x, src_y, mask_x, mask_y, + dst_x - state.image_rect.x, + dst_y - state.image_rect.y, + width, height); + _fallback_fini (&state); - _fallback_cleanup (&state); - return status; } @@ -623,6 +817,9 @@ _cairo_surface_composite (cairo_operator_t operator, { cairo_int_status_t status; + if (dst->status) + return dst->status; + if (dst->finished) return CAIRO_STATUS_SURFACE_FINISHED; @@ -645,6 +842,21 @@ _cairo_surface_composite (cairo_operator_t operator, width, height); } +/** + * _cairo_surface_fill_rectangle: + * @surface: a #cairo_surface_t + * @operator: the operator to apply to the rectangle + * @color: the source color + * @x: X coordinate of rectangle, in backend coordinates + * @y: Y coordinate of rectangle, in backend coordinates + * @width: width of rectangle, in backend coordinates + * @height: height of rectangle, in backend coordinates + * + * Applies an operator to a rectangle using a solid color as the source. + * See _cairo_surface_fill_rectangles() for full details. + * + * Return value: %CAIRO_STATUS_SUCCESS or the error that occurred + **/ cairo_status_t _cairo_surface_fill_rectangle (cairo_surface_t *surface, cairo_operator_t operator, @@ -656,6 +868,9 @@ _cairo_surface_fill_rectangle (cairo_surface_t *surface, { cairo_rectangle_t rect; + if (surface->status) + return surface->status; + if (surface->finished) return CAIRO_STATUS_SURFACE_FINISHED; @@ -667,6 +882,53 @@ _cairo_surface_fill_rectangle (cairo_surface_t *surface, return _cairo_surface_fill_rectangles (surface, operator, color, &rect, 1); } +/** + * _cairo_surface_fill_region: + * @surface: a #cairo_surface_t + * @operator: the operator to apply to the region + * @color: the source color + * @region: the region to modify, in backend coordinates + * + * Applies an operator to a set of rectangles specified as a + * #pixman_region16_t using a solid color as the source. + * See _cairo_surface_fill_rectangles() for full details. + * + * Return value: %CAIRO_STATUS_SUCCESS or the error that occurred + **/ +cairo_status_t +_cairo_surface_fill_region (cairo_surface_t *surface, + cairo_operator_t operator, + const cairo_color_t *color, + pixman_region16_t *region) +{ + int num_rects = pixman_region_num_rects (region); + pixman_box16_t *boxes = pixman_region_rects (region); + cairo_rectangle_t *rects; + cairo_status_t status; + int i; + + if (!num_rects) + return CAIRO_STATUS_SUCCESS; + + rects = malloc (sizeof (pixman_rectangle_t) * num_rects); + if (!rects) + return CAIRO_STATUS_NO_MEMORY; + + for (i = 0; i < num_rects; i++) { + rects[i].x = boxes[i].x1; + rects[i].y = boxes[i].y1; + rects[i].width = boxes[i].x2 - boxes[i].x1; + rects[i].height = boxes[i].y2 - boxes[i].y1; + } + + status = _cairo_surface_fill_rectangles (surface, operator, + color, rects, num_rects); + + free (rects); + + return status; +} + static cairo_status_t _fallback_fill_rectangles (cairo_surface_t *surface, cairo_operator_t operator, @@ -704,16 +966,19 @@ _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) { + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + return CAIRO_STATUS_SUCCESS; return status; + } /* If the fetched image isn't at 0,0, we need to offset the rectangles */ if (state.image_rect.x != 0 || state.image_rect.y != 0) { offset_rects = malloc (sizeof (cairo_rectangle_t) * num_rects); - if (!offset_rects) { + if (offset_rects == NULL) { status = CAIRO_STATUS_NO_MEMORY; - goto FAIL; + goto DONE; } for (i = 0; i < num_rects; i++) { @@ -726,18 +991,34 @@ _fallback_fill_rectangles (cairo_surface_t *surface, rects = offset_rects; } - state.image->base.backend->fill_rectangles (&state.image->base, operator, color, - rects, num_rects); + status = state.image->base.backend->fill_rectangles (&state.image->base, + operator, color, + rects, num_rects); - if (offset_rects) - free (offset_rects); + free (offset_rects); + + DONE: + _fallback_fini (&state); - FAIL: - _fallback_cleanup (&state); - return status; } +/** + * _cairo_surface_fill_rectangles: + * @surface: a #cairo_surface_t + * @operator: the operator to apply to the region + * @color: the source color + * @rects: the rectangles to modify, in backend coordinates + * @num_rects: the number of rectangles in @rects + * + * Applies an operator to a set of rectangles using a solid color + * as the source. Note that even if the operator is an unbounded operator + * such as %CAIRO_OPERATOR_CLEAR, only the given set of rectangles + * is affected. This differs from _cairo_surface_composite_trapezoids() + * where the entire destination rectangle is cleared. + * + * Return value: %CAIRO_STATUS_SUCCESS or the error that occurred + **/ cairo_status_t _cairo_surface_fill_rectangles (cairo_surface_t *surface, cairo_operator_t operator, @@ -747,6 +1028,9 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface, { cairo_int_status_t status; + if (surface->status) + return surface->status; + if (surface->finished) return CAIRO_STATUS_SURFACE_FINISHED; @@ -765,16 +1049,19 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface, return _fallback_fill_rectangles (surface, operator, color, rects, num_rects); } -cairo_private cairo_int_status_t -_cairo_surface_fill_path (cairo_operator_t operator, - cairo_pattern_t *pattern, - cairo_surface_t *dst, - cairo_path_fixed_t *path) +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_fill_rule_t fill_rule, + double tolerance) { - if (dst->backend->fill_path) - return dst->backend->fill_path (operator, pattern, dst, path); - else - return CAIRO_INT_STATUS_UNSUPPORTED; + if (dst->backend->fill_path) + return dst->backend->fill_path (operator, pattern, dst, path, + fill_rule, tolerance); + else + return CAIRO_INT_STATUS_UNSUPPORTED; } @@ -782,6 +1069,7 @@ static cairo_status_t _fallback_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, cairo_surface_t *dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, @@ -797,8 +1085,11 @@ _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) { + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + return CAIRO_STATUS_SUCCESS; return status; + } /* If the destination image isn't at 0,0, we need to offset the trapezoids */ @@ -810,7 +1101,7 @@ _fallback_composite_trapezoids (cairo_operator_t operator, offset_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps); if (!offset_traps) { status = CAIRO_STATUS_NO_MEMORY; - goto FAIL; + goto DONE; } for (i = 0; i < num_traps; i++) { @@ -831,6 +1122,7 @@ _fallback_composite_trapezoids (cairo_operator_t operator, state.image->base.backend->composite_trapezoids (operator, pattern, &state.image->base, + antialias, src_x, src_y, dst_x - state.image_rect.x, dst_y - state.image_rect.y, @@ -838,17 +1130,17 @@ _fallback_composite_trapezoids (cairo_operator_t operator, if (offset_traps) free (offset_traps); - FAIL: - _fallback_cleanup (&state); + DONE: + _fallback_fini (&state); return status; } - cairo_status_t _cairo_surface_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, cairo_surface_t *dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, @@ -860,12 +1152,16 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator, { cairo_int_status_t status; + if (dst->status) + return dst->status; + if (dst->finished) return CAIRO_STATUS_SURFACE_FINISHED; if (dst->backend->composite_trapezoids) { status = dst->backend->composite_trapezoids (operator, pattern, dst, + antialias, src_x, src_y, dst_x, dst_y, width, height, @@ -874,16 +1170,20 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator, return status; } - return _fallback_composite_trapezoids (operator, pattern, dst, - src_x, src_y, - dst_x, dst_y, - width, height, - traps, num_traps); + return _fallback_composite_trapezoids (operator, pattern, dst, + antialias, + src_x, src_y, + dst_x, dst_y, + width, height, + traps, num_traps); } cairo_status_t _cairo_surface_copy_page (cairo_surface_t *surface) { + if (surface->status) + return surface->status; + if (surface->finished) return CAIRO_STATUS_SURFACE_FINISHED; @@ -891,12 +1191,15 @@ _cairo_surface_copy_page (cairo_surface_t *surface) if (surface->backend->copy_page == NULL) return CAIRO_STATUS_SUCCESS; - return surface->backend->copy_page (surface); + return surface->backend->copy_page (surface); } cairo_status_t _cairo_surface_show_page (cairo_surface_t *surface) { + if (surface->status) + return surface->status; + if (surface->finished) return CAIRO_STATUS_SURFACE_FINISHED; @@ -907,62 +1210,241 @@ _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 + */ +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 except for an in-error surface, (ie. surface->status != + * CAIRO_STATUS_SUCCESS). + */ +unsigned int +_cairo_surface_allocate_clip_serial (cairo_surface_t *surface) +{ + unsigned int serial; + + if (surface->status) + return 0; + + 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_status_t +_cairo_surface_reset_clip (cairo_surface_t *surface) +{ + cairo_status_t status; + + if (surface->status) + return surface->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, + CAIRO_ANTIALIAS_DEFAULT); + 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_status_t +_cairo_surface_set_clip_region (cairo_surface_t *surface, + pixman_region16_t *region, + unsigned int serial) +{ + if (surface->status) + return surface->status; + + 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) +cairo_int_status_t +_cairo_surface_intersect_clip_path (cairo_surface_t *surface, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) { - return _cairo_surface_set_clip_region_internal (surface, region, TRUE, TRUE); + if (surface->status) + return surface->status; + + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; + + assert (surface->backend->intersect_clip_path != NULL); + + return surface->backend->intersect_clip_path (surface, + path, + fill_rule, + tolerance, + antialias); } -cairo_status_t -_cairo_surface_get_clip_extents (cairo_surface_t *surface, - cairo_rectangle_t *rectangle) +static cairo_status_t +_cairo_surface_set_clip_path_recursive (cairo_surface_t *surface, + cairo_clip_path_t *clip_path) { + 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, + clip_path->antialias); +} + +/** + * _cairo_surface_set_clip_path: + * @surface: the #cairo_surface_t to set the clip on + * @clip_path: the clip path to set + * @serial: the clip serial number associated with the clip path + * + * Sets the given clipping path for the surface and assigns the + * clipping serial to the surface. + **/ +static 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->status) + return surface->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; - + status = surface->backend->intersect_clip_path (surface, + NULL, + CAIRO_FILL_RULE_WINDING, + 0, + CAIRO_ANTIALIAS_DEFAULT); + 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_status_t +_cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip) +{ + if (!surface) + return CAIRO_STATUS_NULL_POINTER; + if (clip->serial == _cairo_surface_get_current_clip_serial (surface)) return CAIRO_STATUS_SUCCESS; - } + + if (clip->path) + return _cairo_surface_set_clip_path (surface, + clip->path, + clip->serial); + + if (clip->region) + return _cairo_surface_set_clip_region (surface, + clip->region, + clip->serial); + + return _cairo_surface_reset_clip (surface); +} + +/** + * _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->status) + return surface->status; + + if (surface->finished) + return CAIRO_STATUS_SURFACE_FINISHED; return surface->backend->get_extents (surface, rectangle); } @@ -983,6 +1465,9 @@ _cairo_surface_show_glyphs (cairo_scaled_font_t *scaled_font, { cairo_status_t status; + if (dst->status) + return dst->status; + if (dst->finished) return CAIRO_STATUS_SURFACE_FINISHED; @@ -997,3 +1482,204 @@ _cairo_surface_show_glyphs (cairo_scaled_font_t *scaled_font, return status; } + +static cairo_status_t +_cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst, + cairo_rectangle_t *src_rectangle, + cairo_rectangle_t *mask_rectangle, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_rectangle_t dst_rectangle; + cairo_rectangle_t drawn_rectangle; + pixman_region16_t *drawn_region; + pixman_region16_t *clear_region; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + /* The area that was drawn is the area in the destination rectangle but not within + * the source or the mask. + */ + dst_rectangle.x = dst_x; + dst_rectangle.y = dst_y; + dst_rectangle.width = width; + dst_rectangle.height = height; + + drawn_rectangle = dst_rectangle; + + if (src_rectangle) + _cairo_rectangle_intersect (&drawn_rectangle, src_rectangle); + + if (mask_rectangle) + _cairo_rectangle_intersect (&drawn_rectangle, mask_rectangle); + + /* Now compute the area that is in dst_rectangle but not in drawn_rectangle + */ + drawn_region = _cairo_region_create_from_rectangle (&drawn_rectangle); + clear_region = _cairo_region_create_from_rectangle (&dst_rectangle); + if (!drawn_region || !clear_region) { + status = CAIRO_STATUS_NO_MEMORY; + goto CLEANUP_REGIONS; + } + + if (pixman_region_subtract (clear_region, clear_region, drawn_region) != PIXMAN_REGION_STATUS_SUCCESS) { + status = CAIRO_STATUS_NO_MEMORY; + goto CLEANUP_REGIONS; + } + + status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_SOURCE, + CAIRO_COLOR_TRANSPARENT, + clear_region); + + CLEANUP_REGIONS: + if (drawn_region) + pixman_region_destroy (drawn_region); + if (clear_region) + pixman_region_destroy (clear_region); + + return status; +} + +/** + * _cairo_surface_composite_fixup_unbounded: + * @dst: the destination surface + * @src_attr: source surface attributes (from _cairo_pattern_acquire_surface()) + * @src_width: width of source surface + * @src_height: height of source surface + * @mask_attr: mask surface attributes or %NULL if no mask + * @mask_width: width of mask surface + * @mask_height: height of mask surface + * @src_x: @src_x from _cairo_surface_composite() + * @src_y: @src_y from _cairo_surface_composite() + * @mask_x: @mask_x from _cairo_surface_composite() + * @mask_y: @mask_y from _cairo_surface_composite() + * @dst_x: @dst_x from _cairo_surface_composite() + * @dst_y: @dst_y from _cairo_surface_composite() + * @width: @width from _cairo_surface_composite() + * @height: @height_x from _cairo_surface_composite() + * + * Eeek! Too many parameters! This is a helper function to take care of fixing + * up for bugs in libpixman and RENDER where, when asked to composite an + * untransformed surface with an unbounded operator (like CLEAR or SOURCE) + * only the region inside both the source and the mask is affected. + * This function clears the region that should have been drawn but was wasn't. + **/ +cairo_status_t +_cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst, + cairo_surface_attributes_t *src_attr, + int src_width, + int src_height, + cairo_surface_attributes_t *mask_attr, + int mask_width, + int mask_height, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_rectangle_t src_tmp, mask_tmp; + cairo_rectangle_t *src_rectangle = NULL; + cairo_rectangle_t *mask_rectangle = NULL; + + /* The RENDER/libpixman operators are clipped to the bounds of the untransformed, + * non-repeating sources and masks. Other sources and masks can be ignored. + */ + if (_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) && + src_attr->extend == CAIRO_EXTEND_NONE) + { + src_tmp.x = (dst_x - (src_x + src_attr->x_offset)); + src_tmp.y = (dst_y - (src_y + src_attr->y_offset)); + src_tmp.width = src_width; + src_tmp.height = src_height; + + src_rectangle = &src_tmp; + } + + if (mask_attr && + _cairo_matrix_is_integer_translation (&mask_attr->matrix, NULL, NULL) && + mask_attr->extend == CAIRO_EXTEND_NONE) + { + mask_tmp.x = (dst_x - (mask_x + mask_attr->x_offset)); + mask_tmp.y = (dst_y - (mask_y + mask_attr->y_offset)); + mask_tmp.width = mask_width; + mask_tmp.height = mask_height; + + mask_rectangle = &mask_tmp; + } + + return _cairo_surface_composite_fixup_unbounded_internal (dst, src_rectangle, mask_rectangle, + dst_x, dst_y, width, height); +} + +/** + * _cairo_surface_composite_shape_fixup_unbounded: + * @dst: the destination surface + * @src_attr: source surface attributes (from _cairo_pattern_acquire_surface()) + * @src_width: width of source surface + * @src_height: height of source surface + * @mask_width: width of mask surface + * @mask_height: height of mask surface + * @src_x: @src_x from _cairo_surface_composite() + * @src_y: @src_y from _cairo_surface_composite() + * @mask_x: @mask_x from _cairo_surface_composite() + * @mask_y: @mask_y from _cairo_surface_composite() + * @dst_x: @dst_x from _cairo_surface_composite() + * @dst_y: @dst_y from _cairo_surface_composite() + * @width: @width from _cairo_surface_composite() + * @height: @height_x from _cairo_surface_composite() + * + * Like _cairo_surface_composite_fixup_unbounded(), but instead of + * handling the case where we have a source pattern and a mask + * pattern, handle the case where we are compositing a source pattern + * using a mask we create ourselves, as in + * _cairo_surface_composite_glyphs() or _cairo_surface_composite_trapezoids() + **/ +cairo_status_t +_cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst, + cairo_surface_attributes_t *src_attr, + int src_width, + int src_height, + int mask_width, + int mask_height, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_rectangle_t src_tmp, mask_tmp; + cairo_rectangle_t *src_rectangle = NULL; + cairo_rectangle_t *mask_rectangle = NULL; + + /* The RENDER/libpixman operators are clipped to the bounds of the untransformed, + * non-repeating sources and masks. Other sources and masks can be ignored. + */ + if (_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) && + src_attr->extend == CAIRO_EXTEND_NONE) + { + src_tmp.x = (dst_x - (src_x + src_attr->x_offset)); + src_tmp.y = (dst_y - (src_y + src_attr->y_offset)); + src_tmp.width = src_width; + src_tmp.height = src_height; + + src_rectangle = &src_tmp; + } + + mask_tmp.x = dst_x - mask_x; + mask_tmp.y = dst_y - mask_y; + mask_tmp.width = mask_width; + mask_tmp.height = mask_height; + + mask_rectangle = &mask_tmp; + + return _cairo_surface_composite_fixup_unbounded_internal (dst, src_rectangle, mask_rectangle, + dst_x, dst_y, width, height); +} diff --git a/gfx/cairo/cairo/src/cairo-traps.c b/gfx/cairo/cairo/src/cairo-traps.c index 15dfc1bca420..18b944c1d601 100644 --- a/gfx/cairo/cairo/src/cairo-traps.c +++ b/gfx/cairo/cairo/src/cairo-traps.c @@ -229,6 +229,35 @@ _compare_point_fixed_by_y (const void *av, const void *bv) return ret; } +void +_cairo_traps_translate (cairo_traps_t *traps, int x, int y) +{ + cairo_fixed_t xoff, yoff; + cairo_trapezoid_t *t; + int i; + + /* Ugh. The cairo_composite/(Render) interface doesn't allow + an offset for the trapezoids. Need to manually shift all + the coordinates to align with the offset origin of the + intermediate surface. */ + + xoff = _cairo_fixed_from_int (x); + yoff = _cairo_fixed_from_int (y); + + for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) { + t->top += yoff; + t->bottom += yoff; + t->left.p1.x += xoff; + t->left.p1.y += yoff; + t->left.p2.x += xoff; + t->left.p2.y += yoff; + t->right.p1.x += xoff; + t->right.p1.y += yoff; + t->right.p2.x += xoff; + t->right.p2.y += yoff; + } +} + cairo_status_t _cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3]) { @@ -820,7 +849,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/gfx/cairo/cairo/src/cairo-wideint.c b/gfx/cairo/cairo/src/cairo-wideint.c index d34960905257..0043ca530a2e 100644 --- a/gfx/cairo/cairo/src/cairo-wideint.c +++ b/gfx/cairo/cairo/src/cairo-wideint.c @@ -1,5 +1,5 @@ /* - * $Id: cairo-wideint.c,v 1.1 2005/06/04 07:03:27 vladimir%pobox.com Exp $ + * $Id: cairo-wideint.c,v 1.6 2006/02/03 04:49:23 vladimir%pobox.com Exp $ * * Copyright © 2004 Keith Packard * @@ -36,22 +36,6 @@ #include "cairoint.h" -#if !HAVE_UINT64_T || !HAVE_UINT128_T - -static const unsigned char top_bit[256] = -{ - 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, -}; - -#endif - #if HAVE_UINT64_T #define _cairo_uint32s_to_uint64(h,l) ((uint64_t) (h) << 32 | (l)) @@ -157,7 +141,8 @@ _cairo_uint32x32_64_mul (uint32_t a, uint32_t b) cairo_int64_t _cairo_int32x32_64_mul (int32_t a, int32_t b) { - s = _cairo_uint32x32_64_mul ((uint32_t) a, (uint32_t b)); + cairo_int64_t s; + s = _cairo_uint32x32_64_mul ((uint32_t) a, (uint32_t) b); if (a < 0) s.hi -= b; if (b < 0) @@ -270,198 +255,38 @@ _cairo_uint64_negate (cairo_uint64_t a) } /* - * The design of this algorithm comes from GCC, - * but the actual implementation is new + * Simple bit-at-a-time divide. */ - -static const int -_cairo_leading_zeros32 (uint32_t i) -{ - int top; - - if (i < 0x100) - top = 0; - else if (i < 0x10000) - top = 8; - else if (i < 0x1000000) - top = 16; - else - top = 24; - top = top + top_bit [i >> top]; - return 32 - top; -} - -typedef struct _cairo_uquorem32_t { - uint32_t quo; - uint32_t rem; -} cairo_uquorem32_t; - -/* - * den >= num.hi - */ -static const cairo_uquorem32_t -_cairo_uint64x32_normalized_divrem (cairo_uint64_t num, uint32_t den) -{ - cairo_uquorem32_t qr; - uint32_t q0, q1, r0, r1; - uint16_t d0, d1; - uint32_t t; - - d0 = den & 0xffff; - d1 = den >> 16; - - q1 = num.hi / d1; - r1 = num.hi % d1; - - t = q1 * d0; - r1 = (r1 << 16) | (num.lo >> 16); - if (r1 < t) - { - q1--; - r1 += den; - if (r1 >= den && r1 < t) - { - q1--; - r1 += den; - } - } - - r1 -= t; - - q0 = r1 / d1; - r0 = r1 % d1; - t = q0 * d0; - r0 = (r0 << 16) | (num.lo & 0xffff); - if (r0 < t) - { - q0--; - r0 += den; - if (r0 >= den && r0 < t) - { - q0--; - r0 += den; - } - } - r0 -= t; - qr.quo = (q1 << 16) | q0; - qr.rem = r0; - return qr; -} - cairo_uquorem64_t _cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den) { - cairo_uquorem32_t qr32; cairo_uquorem64_t qr; - int norm; - uint32_t q1, q0, r1, r0; - - if (den.hi == 0) + cairo_uint64_t bit; + cairo_uint64_t quo; + + bit = _cairo_uint32_to_uint64 (1); + + /* normalize to make den >= num, but not overflow */ + while (_cairo_uint64_lt (den, num) && (den.hi & 0x80000000) == 0) { - if (den.lo > num.hi) - { - /* 0q = nn / 0d */ - - norm = _cairo_leading_zeros32 (den.lo); - if (norm) - { - den.lo <<= norm; - num = _cairo_uint64_lsl (num, norm); - } - q1 = 0; - } - else - { - /* qq = NN / 0d */ - - if (den.lo == 0) - den.lo = 1 / den.lo; - - norm = _cairo_leading_zeros32 (den.lo); - if (norm) - { - cairo_uint64_t num1; - den.lo <<= norm; - num1 = _cairo_uint64_rsl (num, 32 - norm); - qr32 = _cairo_uint64x32_normalized_divrem (num1, den.lo); - q1 = qr32.quo; - num.hi = qr32.rem; - num.lo <<= norm; - } - else - { - num.hi -= den.lo; - q1 = 1; - } - } - qr32 = _cairo_uint64x32_normalized_divrem (num, den.lo); - q0 = qr32.quo; - r1 = 0; - r0 = qr32.rem >> norm; + bit = _cairo_uint64_lsl (bit, 1); + den = _cairo_uint64_lsl (den, 1); } - else + quo = _cairo_uint32_to_uint64 (0); + + /* generate quotient, one bit at a time */ + while (bit.hi | bit.lo) { - if (den.hi > num.hi) + if (_cairo_uint64_le (den, num)) { - /* 00 = nn / DD */ - q0 = q1 = 0; - r0 = num.lo; - r1 = num.hi; - } - else - { - /* 0q = NN / dd */ - - norm = _cairo_leading_zeros32 (den.hi); - if (norm == 0) - { - if (num.hi > den.hi || num.lo >= den.lo) - { - q0 = 1; - num = _cairo_uint64_sub (num, den); - } - else - q0 = 0; - - q1 = 0; - r0 = num.lo; - r1 = num.hi; - } - else - { - cairo_uint64_t num1; - cairo_uint64_t part; - - num1 = _cairo_uint64_rsl (num, 32 - norm); - den = _cairo_uint64_lsl (den, norm); - - qr32 = _cairo_uint64x32_normalized_divrem (num1, den.hi); - part = _cairo_uint32x32_64_mul (qr32.quo, den.lo); - - q0 = qr32.quo; - - num.lo <<= norm; - num.hi = qr32.rem; - - if (_cairo_uint64_gt (part, num)) - { - q0--; - part = _cairo_uint64_sub (part, den); - } - - q1 = 0; - - num = _cairo_uint64_sub (num, part); - num = _cairo_uint64_rsl (num, norm); - r0 = num.lo; - r1 = num.hi; - } + num = _cairo_uint64_sub (num, den); + quo = _cairo_uint64_add (quo, bit); } + bit = _cairo_uint64_rsl (bit, 1); + den = _cairo_uint64_rsl (den, 1); } - qr.quo.lo = q0; - qr.quo.hi = q1; - qr.rem.lo = r0; - qr.rem.hi = r1; + qr.quo = quo; + qr.rem = num; return qr; } @@ -752,232 +577,42 @@ _cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b) _cairo_uint64_eq (a.lo, b.lo)); } -/* - * The design of this algorithm comes from GCC, - * but the actual implementation is new - */ - -/* - * den >= num.hi - */ -static cairo_uquorem64_t -_cairo_uint128x64_normalized_divrem (cairo_uint128_t num, cairo_uint64_t den) -{ - cairo_uquorem64_t qr64; - cairo_uquorem64_t qr; - uint32_t q0, q1; - cairo_uint64_t r0, r1; - uint32_t d0, d1; - cairo_uint64_t t; - - d0 = uint64_lo32 (den); - d1 = uint64_hi32 (den); - - qr64 = _cairo_uint64_divrem (num.hi, _cairo_uint32_to_uint64 (d1)); - q1 = _cairo_uint64_to_uint32 (qr64.quo); - r1 = qr64.rem; - - t = _cairo_uint32x32_64_mul (q1, d0); - - r1 = _cairo_uint64_add (_cairo_uint64_lsl (r1, 32), - _cairo_uint64_rsl (num.lo, 32)); - - if (_cairo_uint64_lt (r1, t)) - { - q1--; - r1 = _cairo_uint64_add (r1, den); - if (_cairo_uint64_ge (r1, den) && _cairo_uint64_lt (r1, t)) - { - q1--; - r1 = _cairo_uint64_add (r1, den); - } - } - - r1 = _cairo_uint64_sub (r1, t); - - qr64 = _cairo_uint64_divrem (r1, _cairo_uint32_to_uint64 (d1)); - - q0 = _cairo_uint64_to_uint32 (qr64.quo); - r0 = qr64.rem; - - t = _cairo_uint32x32_64_mul (q0, d0); - - r0 = _cairo_uint64_add (_cairo_uint64_lsl (r0, 32), - _cairo_uint32_to_uint64 (_cairo_uint64_to_uint32 (num.lo))); - if (_cairo_uint64_lt (r0, t)) - { - q0--; - r0 = _cairo_uint64_add (r0, den); - if (_cairo_uint64_ge (r0, den) && _cairo_uint64_lt (r0, t)) - { - q0--; - r0 = _cairo_uint64_add (r0, den); - } - } - - r0 = _cairo_uint64_sub (r0, t); - - qr.quo = _cairo_uint32s_to_uint64 (q1, q0); - qr.rem = r0; - return qr; -} - #if HAVE_UINT64_T - -static int -_cairo_leading_zeros64 (cairo_uint64_t q) -{ - int top = 0; - - if (q >= (uint64_t) 0x10000 << 16) - { - top += 32; - q >>= 32; - } - if (q >= (uint64_t) 0x10000) - { - top += 16; - q >>= 16; - } - if (q >= (uint64_t) 0x100) - { - top += 8; - q >>= 8; - } - top += top_bit [q]; - return 64 - top; -} - +#define _cairo_msbset64(q) (q & ((uint64_t) 1 << 63)) #else - -static const int -_cairo_leading_zeros64 (cairo_uint64_t d) -{ - if (d.hi) - return _cairo_leading_zeros32 (d.hi); - else - return 32 + _cairo_leading_zeros32 (d.lo); -} - +#define _cairo_msbset64(q) (q.hi & ((uint32_t) 1 << 31)) #endif cairo_uquorem128_t _cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den) { - cairo_uquorem64_t qr64; cairo_uquorem128_t qr; - int norm; - cairo_uint64_t q1, q0, r1, r0; - - if (_cairo_uint64_eq (den.hi, _cairo_uint32_to_uint64 (0))) + cairo_uint128_t bit; + cairo_uint128_t quo; + + bit = _cairo_uint32_to_uint128 (1); + + /* normalize to make den >= num, but not overflow */ + while (_cairo_uint128_lt (den, num) && !_cairo_msbset64(den.hi)) { - if (_cairo_uint64_gt (den.lo, num.hi)) - { - /* 0q = nn / 0d */ - - norm = _cairo_leading_zeros64 (den.lo); - if (norm) - { - den.lo = _cairo_uint64_lsl (den.lo, norm); - num = _cairo_uint128_lsl (num, norm); - } - q1 = _cairo_uint32_to_uint64 (0); - } - else - { - /* qq = NN / 0d */ - - if (_cairo_uint64_eq (den.lo, _cairo_uint32_to_uint64 (0))) - den.lo = _cairo_uint64_divrem (_cairo_uint32_to_uint64 (1), - den.lo).quo; - - norm = _cairo_leading_zeros64 (den.lo); - if (norm) - { - cairo_uint128_t num1; - - den.lo = _cairo_uint64_lsl (den.lo, norm); - num1 = _cairo_uint128_rsl (num, 64 - norm); - qr64 = _cairo_uint128x64_normalized_divrem (num1, den.lo); - q1 = qr64.quo; - num.hi = qr64.rem; - num.lo = _cairo_uint64_lsl (num.lo, norm); - } - else - { - num.hi = _cairo_uint64_sub (num.hi, den.lo); - q1 = _cairo_uint32_to_uint64 (1); - } - } - qr64 = _cairo_uint128x64_normalized_divrem (num, den.lo); - q0 = qr64.quo; - r1 = _cairo_uint32_to_uint64 (0); - r0 = _cairo_uint64_rsl (qr64.rem, norm); + bit = _cairo_uint128_lsl (bit, 1); + den = _cairo_uint128_lsl (den, 1); } - else + quo = _cairo_uint32_to_uint128 (0); + + /* generate quotient, one bit at a time */ + while (_cairo_uint128_ne (bit, _cairo_uint32_to_uint128(0))) { - if (_cairo_uint64_gt (den.hi, num.hi)) + if (_cairo_uint128_le (den, num)) { - /* 00 = nn / DD */ - q0 = q1 = _cairo_uint32_to_uint64 (0); - r0 = num.lo; - r1 = num.hi; - } - else - { - /* 0q = NN / dd */ - - norm = _cairo_leading_zeros64 (den.hi); - if (norm == 0) - { - if (_cairo_uint64_gt (num.hi, den.hi) || - _cairo_uint64_ge (num.lo, den.lo)) - { - q0 = _cairo_uint32_to_uint64 (1); - num = _cairo_uint128_sub (num, den); - } - else - q0 = _cairo_uint32_to_uint64 (0); - - q1 = _cairo_uint32_to_uint64 (0); - r0 = num.lo; - r1 = num.hi; - } - else - { - cairo_uint128_t num1; - cairo_uint128_t part; - - num1 = _cairo_uint128_rsl (num, 64 - norm); - den = _cairo_uint128_lsl (den, norm); - - qr64 = _cairo_uint128x64_normalized_divrem (num1, den.hi); - part = _cairo_uint64x64_128_mul (qr64.quo, den.lo); - - q0 = qr64.quo; - - num.lo = _cairo_uint64_lsl (num.lo, norm); - num.hi = qr64.rem; - - if (_cairo_uint128_gt (part, num)) - { - q0 = _cairo_uint64_sub (q0, _cairo_uint32_to_uint64 (1)); - part = _cairo_uint128_sub (part, den); - } - - q1 = _cairo_uint32_to_uint64 (0); - - num = _cairo_uint128_sub (num, part); - num = _cairo_uint128_rsl (num, norm); - r0 = num.lo; - r1 = num.hi; - } + num = _cairo_uint128_sub (num, den); + quo = _cairo_uint128_add (quo, bit); } + bit = _cairo_uint128_rsl (bit, 1); + den = _cairo_uint128_rsl (den, 1); } - qr.quo.lo = q0; - qr.quo.hi = q1; - qr.rem.lo = r0; - qr.rem.hi = r1; + qr.quo = quo; + qr.rem = num; return qr; } diff --git a/gfx/cairo/cairo/src/cairo-wideint.h b/gfx/cairo/cairo/src/cairo-wideint.h index 7137056fb455..3050a5ebbb7a 100644 --- a/gfx/cairo/cairo/src/cairo-wideint.h +++ b/gfx/cairo/cairo/src/cairo-wideint.h @@ -1,5 +1,5 @@ /* - * $Id: cairo-wideint.h,v 1.6 2005/06/04 07:03:27 vladimir%pobox.com Exp $ + * $Id: cairo-wideint.h,v 1.11 2006/02/03 04:49:23 vladimir%pobox.com Exp $ * * Copyright © 2004 Keith Packard * @@ -44,8 +44,20 @@ # include #elif HAVE_SYS_INT_TYPES_H # include +#elif defined(_MSC_VER) + typedef __int8 int8_t; + typedef unsigned __int8 uint8_t; + typedef __int16 int16_t; + typedef unsigned __int16 uint16_t; + typedef __int32 int32_t; + typedef unsigned __int32 uint32_t; + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; +# ifndef HAVE_UINT64_T +# define HAVE_UINT64_T 1 +# endif #else -# include "mozstdint.h" +#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.) #endif /* @@ -85,7 +97,7 @@ cairo_int64_t I _cairo_int32_to_int64(int32_t i); #define _cairo_int64_add(a,b) _cairo_uint64_add (a,b) #define _cairo_int64_sub(a,b) _cairo_uint64_sub (a,b) #define _cairo_int64_mul(a,b) _cairo_uint64_mul (a,b) -int I _cairo_int32x32_64_mul (int32_t a, int32_t b); +cairo_int64_t I _cairo_int32x32_64_mul (int32_t a, int32_t b); int I _cairo_int64_lt (cairo_uint64_t a, cairo_uint64_t b); #define _cairo_int64_eq(a,b) _cairo_uint64_eq (a,b) #define _cairo_int64_lsl(a,b) _cairo_uint64_lsl (a,b) @@ -208,7 +220,7 @@ cairo_int128_t I _cairo_int64_to_int128 (cairo_int64_t i); #define _cairo_int128_add(a,b) _cairo_uint128_add(a,b) #define _cairo_int128_sub(a,b) _cairo_uint128_sub(a,b) #define _cairo_int128_mul(a,b) _cairo_uint128_mul(a,b) -cairo_uint128_t I _cairo_int64x64_128_mul (cairo_int64_t a, cairo_int64_t b); +cairo_int128_t I _cairo_int64x64_128_mul (cairo_int64_t a, cairo_int64_t b); #define _cairo_int128_lsl(a,b) _cairo_uint128_lsl(a,b) #define _cairo_int128_rsl(a,b) _cairo_uint128_rsl(a,b) #define _cairo_int128_rsa(a,b) _cairo_uint128_rsa(a,b) diff --git a/gfx/cairo/cairo/src/cairo-win32-font.c b/gfx/cairo/cairo/src/cairo-win32-font.c index f48280856dcb..947f8c3c4964 100644 --- a/gfx/cairo/cairo/src/cairo-win32-font.c +++ b/gfx/cairo/cairo/src/cairo-win32-font.c @@ -46,6 +46,9 @@ #ifndef CLEARTYPE_QUALITY #define CLEARTYPE_QUALITY 5 #endif +#ifndef TT_PRIM_CSPLINE +#define TT_PRIM_CSPLINE 3 +#endif const cairo_scaled_font_backend_t cairo_win32_scaled_font_backend; @@ -104,6 +107,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,39 +159,47 @@ _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 cairo_bool_t +_have_cleartype_quality (void) +{ + OSVERSIONINFO version_info; + + version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); + + if (!GetVersionEx (&version_info)) { + _cairo_win32_print_gdi_error ("_have_cleartype_quality"); + return FALSE; + } + + return (version_info.dwMajorVersion > 5 || + (version_info.dwMajorVersion == 5 && + version_info.dwMinorVersion >= 1)); /* XP or newer */ +} + + static BYTE _get_system_quality (void) { BOOL font_smoothing; + UINT smoothing_type; if (!SystemParametersInfo (SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) { _cairo_win32_print_gdi_error ("_get_system_quality"); - return FALSE; + return DEFAULT_QUALITY; } if (font_smoothing) { - OSVERSIONINFO version_info; - - version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); - - if (!GetVersionEx (&version_info)) { - _cairo_win32_print_gdi_error ("_get_system_quality"); - return FALSE; - } - - if (version_info.dwMajorVersion > 5 || - (version_info.dwMajorVersion == 5 && - version_info.dwMinorVersion >= 1)) { /* XP or newer */ - UINT smoothing_type; - + if (_have_cleartype_quality ()) { if (!SystemParametersInfo (SPI_GETFONTSMOOTHINGTYPE, 0, &smoothing_type, 0)) { _cairo_win32_print_gdi_error ("_get_system_quality"); - return FALSE; + return DEFAULT_QUALITY; } if (smoothing_type == FE_FONTSMOOTHINGCLEARTYPE) @@ -194,24 +207,54 @@ _get_system_quality (void) } return ANTIALIASED_QUALITY; - } else + } else { return DEFAULT_QUALITY; + } } static cairo_scaled_font_t * -_win32_scaled_font_create (LOGFONTW *logfont, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm) +_win32_scaled_font_create (LOGFONTW *logfont, + cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options) { cairo_win32_scaled_font_t *f; cairo_matrix_t scale; f = malloc (sizeof(cairo_win32_scaled_font_t)); - if (f == NULL) - return NULL; + if (f == NULL) + return NULL; f->logfont = *logfont; - f->quality = _get_system_quality (); + + /* We don't have any control over the hinting style or subpixel + * order in the Win32 font API, so we ignore those parts of + * cairo_font_options_t. We use the 'antialias' field to set + * the 'quality'. + * + * XXX: The other option we could pay attention to, but don't + * here is the hint_metrics options. + */ + if (options->antialias == CAIRO_ANTIALIAS_DEFAULT) + f->quality = _get_system_quality (); + else { + switch (options->antialias) { + case CAIRO_ANTIALIAS_NONE: + f->quality = NONANTIALIASED_QUALITY; + break; + case CAIRO_ANTIALIAS_GRAY: + f->quality = ANTIALIASED_QUALITY; + break; + case CAIRO_ANTIALIAS_SUBPIXEL: + if (_have_cleartype_quality ()) + f->quality = CLEARTYPE_QUALITY; + else + f->quality = ANTIALIASED_QUALITY; + break; + } + } + f->em_square = 0; f->scaled_hfont = NULL; f->unscaled_hfont = NULL; @@ -219,7 +262,9 @@ _win32_scaled_font_create (LOGFONTW *logfont, cairo_matrix_multiply (&scale, font_matrix, ctm); _compute_transform (f, &scale); - _cairo_scaled_font_init (&f->base, font_matrix, ctm, &cairo_win32_scaled_font_backend); + _cairo_scaled_font_init (&f->base, font_face, + font_matrix, ctm, options, + &cairo_win32_scaled_font_backend); return &f->base; } @@ -367,7 +412,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; } @@ -385,12 +430,11 @@ _cairo_win32_scaled_font_done_unscaled_font (cairo_scaled_font_t *scaled_font) /* implement the font backend interface */ static cairo_status_t -_cairo_win32_scaled_font_create (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - cairo_scaled_font_t **scaled_font_out) +_cairo_win32_scaled_font_create_toy (cairo_toy_font_face_t *toy_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font_out) { LOGFONTW logfont; cairo_scaled_font_t *scaled_font; @@ -398,8 +442,9 @@ _cairo_win32_scaled_font_create (const char *family, int face_name_len; cairo_status_t status; - status = _cairo_utf8_to_utf16 (family, -1, &face_name, &face_name_len); - if (!CAIRO_OK (status)) + status = _cairo_utf8_to_utf16 (toy_face->family, -1, + &face_name, &face_name_len); + if (status) return status; if (face_name_len > LF_FACESIZE - 1) { @@ -415,7 +460,7 @@ _cairo_win32_scaled_font_create (const char *family, logfont.lfEscapement = 0; /* filled in later */ logfont.lfOrientation = 0; /* filled in later */ - switch (weight) { + switch (toy_face->weight) { case CAIRO_FONT_WEIGHT_NORMAL: default: logfont.lfWeight = FW_NORMAL; @@ -425,7 +470,7 @@ _cairo_win32_scaled_font_create (const char *family, break; } - switch (slant) { + switch (toy_face->slant) { case CAIRO_FONT_SLANT_NORMAL: default: logfont.lfItalic = FALSE; @@ -451,7 +496,8 @@ _cairo_win32_scaled_font_create (const char *family, if (!logfont.lfFaceName) return CAIRO_STATUS_NO_MEMORY; - scaled_font = _win32_scaled_font_create (&logfont, font_matrix, ctm); + scaled_font = _win32_scaled_font_create (&logfont, toy_face, + font_matrix, ctm, options); if (!scaled_font) return CAIRO_STATUS_NO_MEMORY; @@ -461,10 +507,13 @@ _cairo_win32_scaled_font_create (const char *family, } static void -_cairo_win32_scaled_font_destroy (void *abstract_font) +_cairo_win32_scaled_font_fini (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 +545,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 +567,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 +659,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 +678,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 +721,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); @@ -745,7 +794,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 +893,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 +939,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 +951,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; } @@ -910,7 +959,7 @@ _draw_glyphs_on_surface (cairo_win32_surface_t *surface, _finish_glyphs (&state); cairo_win32_scaled_font_done_font (&scaled_font->base); FAIL1: - RestoreDC (surface->dc, 1); + RestoreDC (surface->dc, -1); return status; } @@ -961,7 +1010,7 @@ _compute_a8_mask (cairo_win32_surface_t *mask_surface) image8 = (cairo_image_surface_t *)cairo_image_surface_create (CAIRO_FORMAT_A8, image24->width, image24->height); - if (!image8) + if (image8->base.status) return NULL; for (i = 0; i < image24->height; i++) { @@ -1011,7 +1060,6 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font, */ COLORREF new_color; - /* XXX Use the unpremultiplied or premultiplied color? */ new_color = RGB (((int)solid_pattern->color.red_short) >> 8, ((int)solid_pattern->color.green_short) >> 8, ((int)solid_pattern->color.blue_short) >> 8); @@ -1034,7 +1082,7 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font, RECT r; tmp_surface = (cairo_win32_surface_t *)_cairo_win32_surface_create_dib (CAIRO_FORMAT_ARGB32, width, height); - if (!tmp_surface) + if (tmp_surface->base.status) return CAIRO_STATUS_NO_MEMORY; r.left = 0; @@ -1093,25 +1141,148 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font, } } -static cairo_status_t -_cairo_win32_scaled_font_glyph_path (void *abstract_font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_path_fixed_t *path) +static cairo_fixed_t +_cairo_fixed_from_FIXED (FIXED f) { - return CAIRO_STATUS_SUCCESS; + return *((cairo_fixed_t *)&f); +} + +static cairo_status_t +_cairo_win32_scaled_font_glyph_path (void *abstract_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_fixed_t *path) +{ + static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, -1 } }; + cairo_win32_scaled_font_t *scaled_font = abstract_font; + cairo_status_t status; + GLYPHMETRICS metrics; + HDC hdc; + int i; + + hdc = _get_global_font_dc (); + if (!hdc) + return CAIRO_STATUS_NO_MEMORY; + + status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); + if (status) + return status; + + for (i = 0; i < num_glyphs; i++) + { + DWORD bytesGlyph; + unsigned char *buffer, *ptr; + + cairo_fixed_t x = _cairo_fixed_from_double (glyphs[i].x); + cairo_fixed_t y = _cairo_fixed_from_double (glyphs[i].y); + + bytesGlyph = GetGlyphOutlineW (hdc, glyphs[i].index, + GGO_NATIVE | GGO_GLYPH_INDEX, + &metrics, 0, NULL, &matrix); + + if (bytesGlyph == GDI_ERROR) { + status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_glyph_path"); + goto FAIL; + } + + ptr = buffer = malloc (bytesGlyph); + + if (!buffer) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; + } + + if (GetGlyphOutlineW (hdc, glyphs[i].index, + GGO_NATIVE | GGO_GLYPH_INDEX, + &metrics, bytesGlyph, buffer, &matrix) == GDI_ERROR) { + status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_glyph_path"); + free (buffer); + goto FAIL; + } + + while (ptr < buffer + bytesGlyph) { + TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)ptr; + unsigned char *endPoly = ptr + header->cb; + + ptr += sizeof (TTPOLYGONHEADER); + + _cairo_path_fixed_move_to (path, + _cairo_fixed_from_FIXED (header->pfxStart.x) + x, + _cairo_fixed_from_FIXED (header->pfxStart.y) + y); + + while (ptr < endPoly) { + TTPOLYCURVE *curve = (TTPOLYCURVE *)ptr; + POINTFX *points = curve->apfx; + int i; + switch (curve->wType) { + case TT_PRIM_LINE: + for (i = 0; i < curve->cpfx; i++) { + _cairo_path_fixed_line_to (path, + _cairo_fixed_from_FIXED (points[i].x) + x, + _cairo_fixed_from_FIXED (points[i].y) + y); + } + break; + case TT_PRIM_QSPLINE: + for (i = 0; i < curve->cpfx - 1; i++) { + cairo_fixed_t p1x, p1y, p2x, p2y, cx, cy, c1x, c1y, c2x, c2y; + _cairo_path_fixed_get_current_point (path, &p1x, &p1y); + cx = _cairo_fixed_from_FIXED (points[i].x) + x; + cy = _cairo_fixed_from_FIXED (points[i].y) + y; + + if (i + 1 == curve->cpfx - 1) { + p2x = _cairo_fixed_from_FIXED (points[i + 1].x) + x; + p2y = _cairo_fixed_from_FIXED (points[i + 1].y) + y; + } else { + /* records with more than one curve use interpolation for + control points, per http://support.microsoft.com/kb/q87115/ */ + p2x = (cx + _cairo_fixed_from_FIXED (points[i + 1].x) + x) / 2; + p2y = (cy + _cairo_fixed_from_FIXED (points[i + 1].y) + y) / 2; + } + + c1x = 2 * cx / 3 + p1x / 3; + c1y = 2 * cy / 3 + p1y / 3; + c2x = 2 * cx / 3 + p2x / 3; + c2y = 2 * cy / 3 + p2y / 3; + + _cairo_path_fixed_curve_to (path, c1x, c1y, c2x, c2y, p2x, p2y); + } + break; + case TT_PRIM_CSPLINE: + for (i = 0; i < curve->cpfx - 2; i += 2) { + _cairo_path_fixed_curve_to (path, + _cairo_fixed_from_FIXED (points[i].x) + x, + _cairo_fixed_from_FIXED (points[i].y) + y, + _cairo_fixed_from_FIXED (points[i + 1].x) + x, + _cairo_fixed_from_FIXED (points[i + 1].y) + y, + _cairo_fixed_from_FIXED (points[i + 2].x) + x, + _cairo_fixed_from_FIXED (points[i + 2].y) + y); + } + break; + } + ptr += sizeof(TTPOLYCURVE) + sizeof (POINTFX) * (curve->cpfx - 1); + } + _cairo_path_fixed_close_path (path); + } + free(buffer); + } + +FAIL: + + cairo_win32_scaled_font_done_font (&scaled_font->base); + + return status; } const cairo_scaled_font_backend_t cairo_win32_scaled_font_backend = { - _cairo_win32_scaled_font_create, - _cairo_win32_scaled_font_destroy, + _cairo_win32_scaled_font_create_toy, + _cairo_win32_scaled_font_fini, _cairo_win32_scaled_font_font_extents, _cairo_win32_scaled_font_text_to_glyphs, _cairo_win32_scaled_font_glyph_extents, _cairo_win32_scaled_font_glyph_bbox, _cairo_win32_scaled_font_show_glyphs, _cairo_win32_scaled_font_glyph_path, - _cairo_win32_scaled_font_get_glyph_cache_key, + _cairo_win32_scaled_font_get_glyph_cache_key }; /* cairo_win32_font_face_t */ @@ -1131,15 +1302,17 @@ _cairo_win32_font_face_destroy (void *abstract_face) } static cairo_status_t -_cairo_win32_font_face_create_font (void *abstract_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - cairo_scaled_font_t **font) +_cairo_win32_font_face_scaled_font_create (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **font) { cairo_win32_font_face_t *font_face = abstract_face; *font = _win32_scaled_font_create (&font_face->logfont, - font_matrix, ctm); + font_face, + font_matrix, ctm, options); if (*font) return CAIRO_STATUS_SUCCESS; else @@ -1148,11 +1321,11 @@ _cairo_win32_font_face_create_font (void *abstract_face, static const cairo_font_face_backend_t _cairo_win32_font_face_backend = { _cairo_win32_font_face_destroy, - _cairo_win32_font_face_create_font, + _cairo_win32_font_face_scaled_font_create }; /** - * 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. @@ -1172,8 +1345,10 @@ cairo_win32_font_face_create_for_logfontw (LOGFONTW *logfont) cairo_win32_font_face_t *font_face; font_face = malloc (sizeof (cairo_win32_font_face_t)); - if (!font_face) - return NULL; + if (!font_face) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *)&_cairo_font_face_nil; + } font_face->logfont = *logfont; @@ -1215,6 +1390,11 @@ cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font, HFONT old_hfont = NULL; int old_mode; + if (scaled_font->status) { + _cairo_scaled_font_set_error (scaled_font, scaled_font->status); + return scaled_font->status; + } + hfont = _win32_scaled_font_get_scaled_hfont ((cairo_win32_scaled_font_t *)scaled_font); if (!hfont) return CAIRO_STATUS_NO_MEMORY; @@ -1231,7 +1411,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/gfx/cairo/cairo/src/cairo-win32-surface.c b/gfx/cairo/cairo/src/cairo-win32-surface.c index bc1431286181..c2a99e360b62 100644 --- a/gfx/cairo/cairo/src/cairo-win32-surface.c +++ b/gfx/cairo/cairo/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 @@ -240,27 +240,32 @@ _create_dc_and_bitmap (cairo_win32_surface_t *surface, static cairo_surface_t * _cairo_win32_surface_create_for_dc (HDC original_dc, cairo_format_t format, - int drawable, int width, int height) { + cairo_status_t status; cairo_win32_surface_t *surface; char *bits; int rowstride; surface = malloc (sizeof (cairo_win32_surface_t)); - if (!surface) - return NULL; + if (surface == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return &_cairo_surface_nil; + } - if (_create_dc_and_bitmap (surface, original_dc, format, - width, height, - &bits, &rowstride) != CAIRO_STATUS_SUCCESS) + status = _create_dc_and_bitmap (surface, original_dc, format, + width, height, + &bits, &rowstride); + if (status) goto FAIL; surface->image = cairo_image_surface_create_for_data (bits, format, width, height, rowstride); - if (!surface->image) + if (surface->image->status) { + status = CAIRO_STATUS_NO_MEMORY; goto FAIL; + } surface->format = format; @@ -284,22 +289,26 @@ _cairo_win32_surface_create_for_dc (HDC original_dc, } if (surface) free (surface); - - return NULL; - + + if (status == CAIRO_STATUS_NO_MEMORY) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return &_cairo_surface_nil; + } else { + _cairo_error (status); + return &_cairo_surface_nil; + } } static cairo_surface_t * _cairo_win32_surface_create_similar (void *abstract_src, - cairo_format_t format, - int drawable, + cairo_content_t content, int width, int height) { cairo_win32_surface_t *src = abstract_src; + cairo_format_t format = _cairo_format_from_content (content); - return _cairo_win32_surface_create_for_dc (src->dc, format, drawable, - width, height); + return _cairo_win32_surface_create_for_dc (src->dc, format, width, height); } /** @@ -320,8 +329,7 @@ _cairo_win32_surface_create_dib (cairo_format_t format, int width, int height) { - return _cairo_win32_surface_create_for_dc (NULL, format, TRUE, - width, height); + return _cairo_win32_surface_create_for_dc (NULL, format, width, height); } static cairo_status_t @@ -332,8 +340,9 @@ _cairo_win32_surface_finish (void *abstract_surface) if (surface->image) cairo_surface_destroy (surface->image); - if (surface->saved_clip) + if (surface->saved_clip) { DeleteObject (surface->saved_clip); + } /* If we created the Bitmap and DC, destroy them */ if (surface->bitmap) { @@ -355,13 +364,14 @@ _cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface, { cairo_win32_surface_t *local; cairo_status_t status; + cairo_content_t content = _cairo_content_from_format (surface->format); local = (cairo_win32_surface_t *) _cairo_win32_surface_create_similar (surface, - surface->format, - 0, - width, height); - if (!local) + content, + width, + height); + if (local->base.status) return CAIRO_STATUS_NO_MEMORY; if (!BitBlt (local->dc, @@ -404,12 +414,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 +486,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 @@ -628,7 +640,6 @@ _cairo_win32_surface_composite (cairo_operator_t operator, } else if (integer_transform && (src->format == CAIRO_FORMAT_RGB24 || src->format == CAIRO_FORMAT_ARGB32) && dst->format == CAIRO_FORMAT_RGB24 && - !src->base.repeat && operator == CAIRO_OPERATOR_OVER) { BLENDFUNCTION blend_function; @@ -729,6 +740,9 @@ categorize_solid_dest_operator (cairo_operator_t operator, return DO_UNSUPPORTED; break; } + + ASSERT_NOT_REACHED; + return DO_UNSUPPORTED; } static cairo_int_status_t @@ -758,7 +772,7 @@ _cairo_win32_surface_fill_rectangles (void *abstract_surface, new_color = RGB (0, 0, 0); break; case DO_SOURCE: - new_color = RGB (color->red_short >> 8, color->blue_short >> 8, color->green_short >> 8); + new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8); break; case DO_NOTHING: return CAIRO_STATUS_SUCCESS; @@ -805,8 +819,12 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface, /* If we are in-memory, then we set the clip on the image surface * as well as on the underlying GDI surface. */ - if (surface->image) - _cairo_surface_set_clip_region (surface->image, region); + if (surface->image) { + unsigned int serial; + + serial = _cairo_surface_allocate_clip_serial (surface->image); + _cairo_surface_set_clip_region (surface->image, region, serial); + } /* The semantics we want is that any clip set by cairo combines * is intersected with the clip on device context that the @@ -829,7 +847,6 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface, surface->set_clip = 0; } - return CAIRO_STATUS_SUCCESS; } else { @@ -930,6 +947,12 @@ _cairo_win32_surface_get_extents (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } +static cairo_status_t +_cairo_win32_surface_flush (void *abstract_surface) +{ + return _cairo_surface_reset_clip (abstract_surface); +} + cairo_surface_t * cairo_win32_surface_create (HDC hdc) { @@ -940,12 +963,16 @@ cairo_win32_surface_create (HDC hdc) */ if (GetClipBox (hdc, &rect) == ERROR) { _cairo_win32_print_gdi_error ("cairo_win32_surface_create"); - return NULL; + /* XXX: Can we make a more reasonable guess at the error cause here? */ + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return &_cairo_surface_nil; } surface = malloc (sizeof (cairo_win32_surface_t)); - if (!surface) - return NULL; + if (surface == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return &_cairo_surface_nil; + } surface->image = NULL; surface->format = CAIRO_FORMAT_RGB24; @@ -995,6 +1022,11 @@ 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 */ + NULL, /* show_glyphs */ + NULL, /* fill_path */ + NULL, /* get_font_options */ + _cairo_win32_surface_flush, + NULL /* mark_dirty_rectangle */ }; diff --git a/gfx/cairo/cairo/src/cairo-win32.h b/gfx/cairo/cairo/src/cairo-win32.h index 38f9360beba9..93983456fcad 100644 --- a/gfx/cairo/cairo/src/cairo-win32.h +++ b/gfx/cairo/cairo/src/cairo-win32.h @@ -38,7 +38,7 @@ #include -#ifdef CAIRO_HAS_WIN32_SURFACE +#if CAIRO_HAS_WIN32_SURFACE #include diff --git a/gfx/cairo/cairo/src/cairo-xcb-surface.c b/gfx/cairo/cairo/src/cairo-xcb-surface.c index 95568d608e1f..19e4c49f7012 100644 --- a/gfx/cairo/cairo/src/cairo-xcb-surface.c +++ b/gfx/cairo/cairo/src/cairo-xcb-surface.c @@ -228,8 +228,7 @@ _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, + cairo_content_t content, int width, int height) { @@ -237,6 +236,7 @@ _cairo_xcb_surface_create_similar (void *abstract_src, XCBConnection *dpy = src->dpy; XCBDRAWABLE d; cairo_xcb_surface_t *surface; + cairo_format_t format = _cairo_format_from_content (content); XCBRenderPICTFORMINFO xrender_format = _format_from_cairo (dpy, format); /* As a good first approximation, if the display doesn't have COMPOSITE, @@ -256,6 +256,10 @@ _cairo_xcb_surface_create_similar (void *abstract_src, cairo_xcb_surface_create_with_xrender_format (dpy, d, &xrender_format, width, height); + if (surface->base.status) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } surface->owns_pixmap = TRUE; @@ -371,7 +375,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; @@ -477,10 +481,10 @@ _get_image_surface (cairo_xcb_surface_t *surface, masks.blue_mask = surface->visual->blue_mask; } else if (surface->has_format) { masks.bpp = bpp; - masks.red_mask = surface->format.direct.red_mask << surface->format.direct.red_shift; - masks.green_mask = surface->format.direct.green_mask << surface->format.direct.green_shift; - masks.blue_mask = surface->format.direct.blue_mask << surface->format.direct.blue_shift; - masks.alpha_mask = surface->format.direct.alpha_mask << surface->format.direct.alpha_shift; + masks.red_mask = (unsigned long)surface->format.direct.red_mask << surface->format.direct.red_shift; + masks.green_mask = (unsigned long)surface->format.direct.green_mask << surface->format.direct.green_shift; + masks.blue_mask = (unsigned long)surface->format.direct.blue_mask << surface->format.direct.blue_shift; + masks.alpha_mask = (unsigned long)surface->format.direct.alpha_mask << surface->format.direct.alpha_shift; } else { masks.bpp = bpp; masks.red_mask = 0; @@ -503,6 +507,8 @@ _get_image_surface (cairo_xcb_surface_t *surface, x2 - x1, y2 - y1, bytes_per_line); + if (image->base.status) + goto FAIL; } else { /* * XXX This can't work. We must convert the data to one of the @@ -510,22 +516,25 @@ _get_image_surface (cairo_xcb_surface_t *surface, * which takes data in an arbitrary format and converts it * to something supported by that library. */ - image = _cairo_image_surface_create_with_masks (data, - &masks, - x2 - x1, - y2 - y1, - bytes_per_line); - + image = (cairo_image_surface_t *) + _cairo_image_surface_create_with_masks (data, + &masks, + x2 - x1, + y2 - y1, + bytes_per_line); + if (image->base.status) + goto FAIL; } /* 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; + + FAIL: + free (data); + return CAIRO_STATUS_NO_MEMORY; } static void @@ -569,10 +578,13 @@ _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; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; } static void @@ -595,10 +607,13 @@ _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; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; } static void @@ -628,18 +643,21 @@ _cairo_xcb_surface_clone_similar (void *abstract_surface, cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src; if (xcb_src->dpy == surface->dpy) { - *clone_out = src; - cairo_surface_reference (src); + *clone_out = cairo_surface_reference (src); return CAIRO_STATUS_SUCCESS; } } else if (_cairo_surface_is_image (src)) { cairo_image_surface_t *image_src = (cairo_image_surface_t *)src; + cairo_content_t content = _cairo_content_from_format (image_src->format); + + if (surface->base.status) + return surface->base.status; clone = (cairo_xcb_surface_t *) - _cairo_xcb_surface_create_similar (surface, image_src->format, 0, + _cairo_xcb_surface_create_similar (surface, content, image_src->width, image_src->height); - if (clone == NULL) + if (clone->base.status) return CAIRO_STATUS_NO_MEMORY; _draw_image_surface (clone, image_src, 0, 0); @@ -850,12 +868,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, @@ -886,9 +904,9 @@ _cairo_xcb_surface_composite (cairo_operator_t operator, } if (mask) - _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr); + _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr); - _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr); + _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr); return status; } @@ -924,6 +942,7 @@ static cairo_int_status_t _cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, void *abstract_dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, @@ -962,11 +981,19 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator, render_src_x = src_x + render_reference_x - dst_x; render_src_y = src_y + render_reference_y - dst_y; + switch (antialias) { + case CAIRO_ANTIALIAS_NONE: + render_format = _format_from_cairo (dst->dpy, CAIRO_FORMAT_A1); + break; + default: + render_format = _format_from_cairo (dst->dpy, CAIRO_FORMAT_A8); + break; + } + /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */ /* 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, @@ -975,19 +1002,11 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator, render_src_y + attributes.y_offset, num_traps, (XCBRenderTRAP *) traps); - _cairo_pattern_release_surface (&dst->base, &src->base, &attributes); + _cairo_pattern_release_surface (pattern, &src->base, &attributes); return status; } -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 +1035,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 */ }; @@ -1067,8 +1087,10 @@ _cairo_xcb_surface_create_internal (XCBConnection *dpy, cairo_xcb_surface_t *surface; surface = malloc (sizeof (cairo_xcb_surface_t)); - if (surface == NULL) - return NULL; + if (surface == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } _cairo_surface_init (&surface->base, &cairo_xcb_surface_backend); diff --git a/gfx/cairo/cairo/src/cairo-xcb-xrender.h b/gfx/cairo/cairo/src/cairo-xcb-xrender.h index 2c3258c62e1d..ef4baa991231 100644 --- a/gfx/cairo/cairo/src/cairo-xcb-xrender.h +++ b/gfx/cairo/cairo/src/cairo-xcb-xrender.h @@ -39,7 +39,7 @@ #include -#ifdef CAIRO_HAS_XCB_SURFACE +#if CAIRO_HAS_XCB_SURFACE #include #include diff --git a/gfx/cairo/cairo/src/cairo-xcb.h b/gfx/cairo/cairo/src/cairo-xcb.h index 1646ebcb50f0..17dfafa02645 100644 --- a/gfx/cairo/cairo/src/cairo-xcb.h +++ b/gfx/cairo/cairo/src/cairo-xcb.h @@ -39,7 +39,7 @@ #include -#ifdef CAIRO_HAS_XCB_SURFACE +#if CAIRO_HAS_XCB_SURFACE #include @@ -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/gfx/cairo/cairo/src/cairo-xlib-private.h b/gfx/cairo/cairo/src/cairo-xlib-private.h new file mode 100644 index 000000000000..966a08d184b2 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-xlib-private.h @@ -0,0 +1,54 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + */ + +#ifndef CAIRO_XLIB_PRIVATE_H +#define CAIRO_XLIB_PRIVATE_H + +#include "cairoint.h" +#include "cairo-xlib.h" + +typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t; + +struct _cairo_xlib_screen_info { + cairo_xlib_screen_info_t *next; + + Display *display; + Screen *screen; + cairo_bool_t has_render; + + cairo_font_options_t font_options; +}; + +cairo_private cairo_xlib_screen_info_t * +_cairo_xlib_screen_info_get (Display *display, Screen *screen); + +#endif /* CAIRO_XLIB_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-xlib-screen.c b/gfx/cairo/cairo/src/cairo-xlib-screen.c new file mode 100644 index 000000000000..e71d10ecc16b --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-xlib-screen.c @@ -0,0 +1,381 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Partially on code from xftdpy.c + * + * Copyright © 2000 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include + +#include "cairo-xlib-private.h" + +#include + +#include /* For XESetCloseDisplay */ +#include + +static int +parse_boolean (const char *v) +{ + char c0, c1; + + c0 = *v; + if (c0 == 't' || c0 == 'T' || c0 == 'y' || c0 == 'Y' || c0 == '1') + return 1; + if (c0 == 'f' || c0 == 'F' || c0 == 'n' || c0 == 'N' || c0 == '0') + return 0; + if (c0 == 'o') + { + c1 = v[1]; + if (c1 == 'n' || c1 == 'N') + return 1; + if (c1 == 'f' || c1 == 'F') + return 0; + } + + return -1; +} + +static cairo_bool_t +get_boolean_default (Display *dpy, + const char *option, + cairo_bool_t *value) +{ + char *v; + int i; + + v = XGetDefault (dpy, "Xft", option); + if (v) { + i = parse_boolean (v); + if (i >= 0) { + *value = i; + return TRUE; + } + } + + return FALSE; +} + +static cairo_bool_t +get_integer_default (Display *dpy, + const char *option, + int *value) +{ + int i; + char *v, *e; + + v = XGetDefault (dpy, "Xft", option); + if (v) { + if (FcNameConstant ((FcChar8 *) v, value)) + return TRUE; + + i = strtol (v, &e, 0); + if (e != v) + return TRUE; + } + + return FALSE; +} + +/* Old versions of fontconfig didn't have these options */ +#ifndef FC_HINT_NONE +#define FC_HINT_NONE 0 +#define FC_HINT_SLIGHT 1 +#define FC_HINT_MEDIUM 2 +#define FC_HINT_FULL 3 +#endif + +static void +_cairo_xlib_init_screen_font_options (cairo_xlib_screen_info_t *info) +{ + cairo_bool_t xft_hinting; + cairo_bool_t xft_antialias; + int xft_hintstyle; + int xft_rgba; + cairo_antialias_t antialias; + cairo_subpixel_order_t subpixel_order; + cairo_hint_style_t hint_style; + + if (!get_boolean_default (info->display, "antialias", &xft_antialias)) + xft_antialias = TRUE; + + if (!get_boolean_default (info->display, "hinting", &xft_hinting)) + xft_hinting = TRUE; + + if (!get_integer_default (info->display, "hintstyle", &xft_hintstyle)) + xft_hintstyle = FC_HINT_FULL; + + if (!get_integer_default (info->display, "rgba", &xft_rgba)) + { + xft_rgba = FC_RGBA_UNKNOWN; + +#if RENDER_MAJOR > 0 || RENDER_MINOR >= 6 + if (info->has_render) + { + int render_order = XRenderQuerySubpixelOrder (info->display, + XScreenNumberOfScreen (info->screen)); + + switch (render_order) + { + default: + case SubPixelUnknown: + xft_rgba = FC_RGBA_UNKNOWN; + break; + case SubPixelHorizontalRGB: + xft_rgba = FC_RGBA_RGB; + break; + case SubPixelHorizontalBGR: + xft_rgba = FC_RGBA_BGR; + break; + case SubPixelVerticalRGB: + xft_rgba = FC_RGBA_VRGB; + break; + case SubPixelVerticalBGR: + xft_rgba = FC_RGBA_VBGR; + break; + case SubPixelNone: + xft_rgba = FC_RGBA_NONE; + break; + } + } +#endif + } + + if (xft_hinting) { + switch (xft_hintstyle) { + case FC_HINT_NONE: + hint_style = CAIRO_HINT_STYLE_NONE; + break; + case FC_HINT_SLIGHT: + hint_style = CAIRO_HINT_STYLE_SLIGHT; + break; + case FC_HINT_MEDIUM: + hint_style = CAIRO_HINT_STYLE_MEDIUM; + break; + case FC_HINT_FULL: + hint_style = CAIRO_HINT_STYLE_FULL; + break; + default: + hint_style = CAIRO_HINT_STYLE_DEFAULT; + } + } else { + hint_style = CAIRO_HINT_STYLE_NONE; + } + + switch (xft_rgba) { + case FC_RGBA_RGB: + subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB; + break; + case FC_RGBA_BGR: + subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR; + break; + case FC_RGBA_VRGB: + subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB; + break; + case FC_RGBA_VBGR: + subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR; + break; + case FC_RGBA_UNKNOWN: + case FC_RGBA_NONE: + default: + subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; + } + + if (xft_antialias) { + if (subpixel_order == CAIRO_SUBPIXEL_ORDER_DEFAULT) + antialias = CAIRO_ANTIALIAS_GRAY; + else + antialias = CAIRO_ANTIALIAS_SUBPIXEL; + } else { + antialias = CAIRO_ANTIALIAS_NONE; + } + + _cairo_font_options_init_default (&info->font_options); + cairo_font_options_set_hint_style (&info->font_options, hint_style); + cairo_font_options_set_antialias (&info->font_options, antialias); + cairo_font_options_set_subpixel_order (&info->font_options, subpixel_order); +} + +CAIRO_MUTEX_DECLARE(_xlib_screen_mutex); + +static cairo_xlib_screen_info_t *_cairo_xlib_screen_list = NULL; + +static int +_cairo_xlib_close_display (Display *dpy, XExtCodes *codes) +{ + cairo_xlib_screen_info_t *info, *prev; + + /* + * Unhook from the global list + */ + CAIRO_MUTEX_LOCK (_xlib_screen_mutex); + + prev = NULL; + for (info = _cairo_xlib_screen_list; info; info = info->next) { + if (info->display == dpy) { + if (prev) + prev->next = info->next; + else + _cairo_xlib_screen_list = info->next; + free (info); + break; + } + prev = info; + } + CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); + + /* Return value in accordance with requirements of + * XESetCloseDisplay */ + return 0; +} + +static void +_cairo_xlib_screen_info_reset (void) +{ + cairo_xlib_screen_info_t *info, *next; + + /* + * Delete everything in the list. + */ + CAIRO_MUTEX_LOCK (_xlib_screen_mutex); + + for (info = _cairo_xlib_screen_list; info; info = next) { + next = info->next; + free (info); + } + + _cairo_xlib_screen_list = NULL; + + CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); + +} + +cairo_xlib_screen_info_t * +_cairo_xlib_screen_info_get (Display *dpy, Screen *screen) +{ + cairo_xlib_screen_info_t *info; + cairo_xlib_screen_info_t **prev; + int event_base, error_base; + XExtCodes *codes; + cairo_bool_t seen_display = FALSE; + + /* There is an apparent deadlock between this mutex and the + * mutex for the display, but it's actually safe. For the + * app to call XCloseDisplay() while any other thread is + * inside this function would be an error in the logic + * app, and the CloseDisplay hook is the only other place we + * acquire this mutex. + */ + CAIRO_MUTEX_LOCK (_xlib_screen_mutex); + + for (prev = &_cairo_xlib_screen_list; (info = *prev); prev = &(*prev)->next) + { + if (info->display == dpy) { + seen_display = TRUE; + if (info->screen == screen) + { + /* + * MRU the list + */ + if (prev != &_cairo_xlib_screen_list) + { + *prev = info->next; + info->next = _cairo_xlib_screen_list; + _cairo_xlib_screen_list = info; + } + break; + } + } + } + + if (info) + goto out; + + info = malloc (sizeof (cairo_xlib_screen_info_t)); + if (!info) + goto out; + + if (!seen_display) { + codes = XAddExtension (dpy); + if (!codes) { + free (info); + info = NULL; + goto out; + } + + XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display); + } + + info->display = dpy; + info->screen = screen; + info->has_render = (XRenderQueryExtension (dpy, &event_base, &error_base) && + (XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != 0)); + + _cairo_xlib_init_screen_font_options (info); + + info->next = _cairo_xlib_screen_list; + _cairo_xlib_screen_list = info; + + out: + CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); + + return info; +} + +void +_cairo_xlib_screen_reset_static_data (void) +{ + _cairo_xlib_screen_info_reset (); + +#if HAVE_XRMFINALIZE + XrmFinalize (); +#endif + +} diff --git a/gfx/cairo/cairo/src/cairo-xlib-surface.c b/gfx/cairo/cairo/src/cairo-xlib-surface.c index 41fb00c44489..e778857ebbc1 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-surface.c +++ b/gfx/cairo/cairo/src/cairo-xlib-surface.c @@ -1,6 +1,7 @@ /* cairo - a vector graphics library with display and print output * * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -38,6 +39,7 @@ #include "cairo-xlib.h" #include "cairo-xlib-xrender.h" #include "cairo-xlib-test.h" +#include "cairo-xlib-private.h" #include /* Xlib doesn't define a typedef, so define one ourselves */ @@ -46,7 +48,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, @@ -60,8 +72,11 @@ struct _cairo_xlib_surface { cairo_surface_t base; Display *dpy; + cairo_xlib_screen_info_t *screen_info; + GC gc; Drawable drawable; + Screen *screen; cairo_bool_t owns_pixmap; Visual *visual; @@ -70,11 +85,33 @@ 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. + * + * We also use this variable as a guard against a second + * independent bug with transformed repeating pictures: + * + * http://lists.freedesktop.org/archives/cairo/2004-September/001839.html + * + * Both are fixed in xorg >= 6.9 and hopefully in > 6.8.2, so + * we can reuse the test for now. + */ + 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; }; @@ -155,17 +192,16 @@ _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, +_cairo_xlib_surface_create_similar (void *abstract_src, + cairo_content_t content, int width, int height) { cairo_xlib_surface_t *src = abstract_src; Display *dpy = src->dpy; - int scr; Pixmap pix; cairo_xlib_surface_t *surface; + cairo_format_t format = _cairo_format_from_content (content); int depth = _CAIRO_FORMAT_DEPTH (format); XRenderPictFormat *xrender_format = _CAIRO_FORMAT_XRENDER_FORMAT (dpy, format); @@ -177,16 +213,18 @@ _cairo_xlib_surface_create_similar (void *abstract_src, return cairo_image_surface_create (format, width, height); } - scr = DefaultScreen (dpy); - - pix = XCreatePixmap (dpy, DefaultRootWindow (dpy), + pix = XCreatePixmap (dpy, RootWindowOfScreen (src->screen), width <= 0 ? 1 : width, height <= 0 ? 1 : height, depth); surface = (cairo_xlib_surface_t *) - cairo_xlib_surface_create_with_xrender_format (dpy, pix, + cairo_xlib_surface_create_with_xrender_format (dpy, pix, src->screen, xrender_format, width, height); + if (surface->base.status) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } surface->owns_pixmap = TRUE; @@ -197,8 +235,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 +247,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 +325,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; @@ -377,10 +421,10 @@ _get_image_surface (cairo_xlib_surface_t *surface, masks.blue_mask = surface->visual->blue_mask; } else if (surface->format) { masks.bpp = ximage->bits_per_pixel; - masks.red_mask = surface->format->direct.redMask << surface->format->direct.red; - masks.green_mask = surface->format->direct.greenMask << surface->format->direct.green; - masks.blue_mask = surface->format->direct.blueMask << surface->format->direct.blue; - masks.alpha_mask = surface->format->direct.alphaMask << surface->format->direct.alpha; + masks.red_mask = (unsigned long)surface->format->direct.redMask << surface->format->direct.red; + masks.green_mask = (unsigned long)surface->format->direct.greenMask << surface->format->direct.green; + masks.blue_mask = (unsigned long)surface->format->direct.blueMask << surface->format->direct.blue; + masks.alpha_mask = (unsigned long)surface->format->direct.alphaMask << surface->format->direct.alpha; } else { masks.bpp = ximage->bits_per_pixel; masks.red_mask = 0; @@ -398,11 +442,14 @@ _get_image_surface (cairo_xlib_surface_t *surface, */ if (_CAIRO_MASK_FORMAT (&masks, &format)) { - image = (cairo_image_surface_t *) cairo_image_surface_create_for_data ((unsigned char *) ximage->data, - format, - ximage->width, - ximage->height, - ximage->bytes_per_line); + image = (cairo_image_surface_t*) + cairo_image_surface_create_for_data ((unsigned char *) ximage->data, + format, + ximage->width, + ximage->height, + ximage->bytes_per_line); + if (image->base.status) + goto FAIL; } else { @@ -412,26 +459,72 @@ _get_image_surface (cairo_xlib_surface_t *surface, * which takes data in an arbitrary format and converts it * to something supported by that library. */ - image = _cairo_image_surface_create_with_masks ((unsigned char *) ximage->data, - &masks, - ximage->width, - ximage->height, - ximage->bytes_per_line); + image = (cairo_image_surface_t*) + _cairo_image_surface_create_with_masks ((unsigned char *) ximage->data, + &masks, + ximage->width, + ximage->height, + ximage->bytes_per_line); + if (image->base.status) + goto FAIL; } /* Let the surface take ownership of the data */ - /* XXX: Can probably come up with a cleaner API here. */ _cairo_image_surface_assume_ownership_of_data (image); ximage->data = NULL; XDestroyImage (ximage); - _cairo_image_surface_set_repeat (image, surface->base.repeat); - _cairo_image_surface_set_matrix (image, &(surface->base.matrix)); - *image_out = image; return CAIRO_STATUS_SUCCESS; + + FAIL: + XDestroyImage (ximage); + return CAIRO_STATUS_NO_MEMORY; } +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) { @@ -443,6 +536,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 +593,13 @@ _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; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; } static void @@ -525,10 +622,13 @@ _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; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; } static void @@ -546,6 +646,18 @@ _cairo_xlib_surface_release_dest_image (void *abstract_surface cairo_surface_destroy (&image->base); } +/* + * Return whether two xlib surfaces share the same + * screen. Both core and Render drawing require this + * when using multiple drawables in an operation. + */ +static cairo_bool_t +_cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst, + cairo_xlib_surface_t *src) +{ + return dst->dpy == src->dpy && dst->screen == src->screen; +} + static cairo_status_t _cairo_xlib_surface_clone_similar (void *abstract_surface, cairo_surface_t *src, @@ -557,19 +669,19 @@ _cairo_xlib_surface_clone_similar (void *abstract_surface, if (src->backend == surface->base.backend ) { cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src; - if (xlib_src->dpy == surface->dpy) { - *clone_out = src; - cairo_surface_reference (src); + if (_cairo_xlib_surface_same_screen (surface, xlib_src)) { + *clone_out = cairo_surface_reference (src); return CAIRO_STATUS_SUCCESS; } } else if (_cairo_surface_is_image (src)) { cairo_image_surface_t *image_src = (cairo_image_surface_t *)src; + cairo_content_t content = _cairo_content_from_format (image_src->format); clone = (cairo_xlib_surface_t *) - _cairo_xlib_surface_create_similar (surface, image_src->format, 0, + _cairo_xlib_surface_create_similar (surface, content, image_src->width, image_src->height); - if (clone == NULL) + if (clone->base.status) return CAIRO_STATUS_NO_MEMORY; _draw_image_surface (clone, image_src, 0, 0); @@ -588,7 +700,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 +729,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 +740,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 +772,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 +784,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 +801,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 +825,196 @@ _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 *dst, + cairo_xlib_surface_t *src) +{ + /* same screen */ + if (!_cairo_xlib_surface_same_screen (dst, src)) + return FALSE; + + /* same depth (for core) */ + if (src->depth != dst->depth) + return FALSE; + + /* if Render is supported, match picture formats */ + if (src->format != NULL && src->format == dst->format) + return TRUE; + + /* Without Render, match visuals instead */ + if (src->visual == dst->visual) + return TRUE; + + return FALSE; +} + +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; + } +} + +/* Returns true if the given operator and source-alpha combination + * requires alpha compositing to complete. + */ +static cairo_bool_t +_operator_needs_alpha_composite (cairo_operator_t operator, + cairo_bool_t surface_has_alpha) +{ + if (operator == CAIRO_OPERATOR_SOURCE || + (!surface_has_alpha && + (operator == CAIRO_OPERATOR_OVER || + operator == CAIRO_OPERATOR_ATOP || + operator == CAIRO_OPERATOR_IN))) + return FALSE; + + return TRUE; +} + +/* There is a bug in most older X servers with compositing using a + * untransformed repeating source pattern when the source is in off-screen + * video memory, and another with repeated transformed images using a + * general tranform matrix. When these bugs 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 for the first bug, otherwise, we need + * a software fallback. + * + * We can also often optimize a compositing operation by calling XCopyArea + * for some common cases where there is no alpha compositing to be done. + * We figure that out here as well. + */ +typedef enum { + DO_RENDER, /* use render */ + DO_XCOPYAREA, /* core protocol XCopyArea optimization/fallback */ + DO_XTILE, /* core protocol XSetTile optimization/fallback */ + DO_UNSUPPORTED /* software fallback */ +} composite_operation_t; + +/* Initial check for the render bugs; we need to recheck for the + * offscreen-memory bug after we turn patterns into surfaces, since that + * may introduce a repeating pattern for gradient patterns. We don't need + * to check for the repeat+transform bug because gradient surfaces aren't + * transformed. + * + * 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_operation (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 the bug involving + * untransformed repeating source patterns with off-screen + * video memory; 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 these are on the same screen but otherwise incompatible, + * make a copy as core drawing can't cross depths and doesn't + * work rightacross visuals of the same depth + */ + if (_cairo_xlib_surface_same_screen (dst, src) && + !_surfaces_compatible (dst, src)) + return DO_UNSUPPORTED; + } + } + + /* Check for the other bug involving repeat patterns with general + * transforms. */ + if (!_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) && + src_pattern->extend == CAIRO_EXTEND_REPEAT) + 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. + * + * Also check here if we can just use XCopyArea, instead of going through + * Render. + */ +static composite_operation_t +_recategorize_composite_operation (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) +{ + cairo_bool_t is_integer_translation = + _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL); + cairo_bool_t needs_alpha_composite = + _operator_needs_alpha_composite (operator, _surface_has_alpha (src)); + + if (!have_mask && + is_integer_translation && + src_attr->extend == CAIRO_EXTEND_NONE && + !needs_alpha_composite && + _surfaces_compatible(src, dst)) + { + return DO_XCOPYAREA; + } + + if (!dst->buggy_repeat) + return DO_RENDER; + + if (is_integer_translation && + src_attr->extend == CAIRO_EXTEND_REPEAT && + (src->width != 1 || src->height != 1)) + { + if (!have_mask && + !needs_alpha_composite && + _surfaces_compatible (dst, src)) + { + return DO_XTILE; + } + + return DO_UNSUPPORTED; + } + + return DO_RENDER; +} + static int _render_operator (cairo_operator_t operator) { @@ -770,10 +1074,17 @@ _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; + int itx, ity; if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; + operation = _categorize_composite_operation (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,40 +1096,104 @@ _cairo_xlib_surface_composite (cairo_operator_t operator, if (status) return status; + operation = _recategorize_composite_operation (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; + + switch (operation) + { + case DO_RENDER: + _cairo_xlib_surface_ensure_dst_picture (dst); if (mask) { status = _cairo_xlib_surface_set_attributes (mask, &mask_attr); - if (CAIRO_OK (status)) - XRenderComposite (dst->dpy, - _render_operator (operator), - src->picture, - mask->picture, - dst->picture, - src_x + src_attr.x_offset, - src_y + src_attr.y_offset, - mask_x + mask_attr.x_offset, - mask_y + mask_attr.y_offset, - dst_x, dst_y, - width, height); + if (status) + goto FAIL; + + XRenderComposite (dst->dpy, + _render_operator (operator), + 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, + mask_y + mask_attr.y_offset, + dst_x, dst_y, + width, height); } 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, dst_x, dst_y, width, height); } + + if (!_cairo_operator_bounded (operator)) + status = _cairo_surface_composite_fixup_unbounded (&dst->base, + &src_attr, src->width, src->height, + mask ? &mask_attr : NULL, + mask ? mask->width : 0, + mask ? mask->height : 0, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, width, height); + break; + + case DO_XCOPYAREA: + _cairo_xlib_surface_ensure_gc (dst); + XCopyArea (dst->dpy, + src->drawable, + dst->drawable, + dst->gc, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + width, height, + dst_x, dst_y); + break; + + case DO_XTILE: + /* 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_operation. + */ + + _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); + break; + + default: + ASSERT_NOT_REACHED; } + FAIL: + if (mask) - _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr); + _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr); - _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr); + _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr); return status; } @@ -842,18 +1217,110 @@ _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; } +/* Creates an A8 picture of size @width x @height, initialized with @color + */ +static Picture +_create_a8_picture (cairo_xlib_surface_t *surface, + XRenderColor *color, + int width, + int height, + cairo_bool_t repeat) +{ + XRenderPictureAttributes pa; + unsigned long mask = 0; + + Pixmap pixmap = XCreatePixmap (surface->dpy, surface->drawable, + width, height, + 8); + Picture picture; + + if (repeat) { + pa.repeat = TRUE; + mask = CPRepeat; + } + + picture = XRenderCreatePicture (surface->dpy, pixmap, + XRenderFindStandardFormat (surface->dpy, PictStandardA8), + mask, &pa); + XRenderFillRectangle (surface->dpy, PictOpSrc, picture, color, + 0, 0, width, height); + XFreePixmap (surface->dpy, pixmap); + + return picture; +} + +/* Creates a temporary mask for the trapezoids covering the area + * [@dst_x, @dst_y, @width, @height] of the destination surface. + */ +static Picture +_create_trapezoid_mask (cairo_xlib_surface_t *dst, + cairo_trapezoid_t *traps, + int num_traps, + int dst_x, + int dst_y, + int width, + int height, + XRenderPictFormat *pict_format) +{ + XRenderColor transparent = { 0, 0, 0, 0 }; + XRenderColor solid = { 0xffff, 0xffff, 0xffff, 0xffff }; + Picture mask_picture, solid_picture; + XTrapezoid *offset_traps; + int i; + + /* This would be considerably simpler using XRenderAddTraps(), but since + * we are only using this in the unbounded-operator case, we stick with + * XRenderCompositeTrapezoids, which is available on older versions + * of RENDER rather than conditionalizing. We should still hit an + * optimization that avoids creating another intermediate surface on + * the servers that have XRenderAddTraps(). + */ + mask_picture = _create_a8_picture (dst, &transparent, width, height, FALSE); + solid_picture = _create_a8_picture (dst, &solid, width, height, TRUE); + + offset_traps = malloc (sizeof (XTrapezoid) * num_traps); + if (!offset_traps) + return None; + + for (i = 0; i < num_traps; i++) { + offset_traps[i].top = traps[i].top - 0x10000 * dst_y; + offset_traps[i].bottom = traps[i].bottom - 0x10000 * dst_y; + offset_traps[i].left.p1.x = traps[i].left.p1.x - 0x10000 * dst_x; + offset_traps[i].left.p1.y = traps[i].left.p1.y - 0x10000 * dst_y; + offset_traps[i].left.p2.x = traps[i].left.p2.x - 0x10000 * dst_x; + offset_traps[i].left.p2.y = traps[i].left.p2.y - 0x10000 * dst_y; + offset_traps[i].right.p1.x = traps[i].right.p1.x - 0x10000 * dst_x; + offset_traps[i].right.p1.y = traps[i].right.p1.y - 0x10000 * dst_y; + offset_traps[i].right.p2.x = traps[i].right.p2.x - 0x10000 * dst_x; + offset_traps[i].right.p2.y = traps[i].right.p2.y - 0x10000 * dst_y; + } + + XRenderCompositeTrapezoids (dst->dpy, PictOpAdd, + solid_picture, mask_picture, + pict_format, + 0, 0, + offset_traps, num_traps); + + XRenderFreePicture (dst->dpy, solid_picture); + free (offset_traps); + + return mask_picture; +} + static cairo_int_status_t _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, void *abstract_dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, @@ -867,11 +1334,17 @@ _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; + XRenderPictFormat *pict_format; if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; + + operation = _categorize_composite_operation (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 +1352,22 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, &attributes); if (status) return status; - + + operation = _recategorize_composite_operation (dst, operator, src, &attributes, TRUE); + if (operation == DO_UNSUPPORTED) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto FAIL; + } + + switch (antialias) { + case CAIRO_ANTIALIAS_NONE: + pict_format = XRenderFindStandardFormat (dst->dpy, PictStandardA1); + break; + default: + pict_format = XRenderFindStandardFormat (dst->dpy, PictStandardA8); + break; + } + 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); @@ -891,18 +1379,63 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, render_src_x = src_x + render_reference_x - dst_x; render_src_y = src_y + render_reference_y - dst_y; - /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */ + _cairo_xlib_surface_ensure_dst_picture (dst); status = _cairo_xlib_surface_set_attributes (src, &attributes); - if (CAIRO_OK (status)) + if (status) + goto FAIL; + + if (!_cairo_operator_bounded (operator)) { + /* XRenderCompositeTrapezoids() creates a mask only large enough for the + * trapezoids themselves, but if the operator is unbounded, then we need + * to actually composite all the way out to the bounds, so we create + * the mask and composite ourselves. There actually would + * be benefit to doing this in all cases, since RENDER implementations + * will frequently create a too temporary big mask, ignoring destination + * bounds and clip. (XRenderAddTraps() could be used to make creating + * the mask somewhat cheaper.) + */ + Picture mask_picture = _create_trapezoid_mask (dst, traps, num_traps, + dst_x, dst_y, width, height, + pict_format); + if (!mask_picture) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; + } + + XRenderComposite (dst->dpy, + _render_operator (operator), + src->src_picture, + mask_picture, + dst->dst_picture, + src_x + attributes.x_offset, + src_y + attributes.y_offset, + 0, 0, + dst_x, dst_y, + width, height); + + XRenderFreePicture (dst->dpy, mask_picture); + + status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base, + &attributes, src->width, src->height, + width, height, + src_x, src_y, + 0, 0, + dst_x, dst_y, width, height); + + + } else { + /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */ XRenderCompositeTrapezoids (dst->dpy, _render_operator (operator), - src->picture, dst->picture, - XRenderFindStandardFormat (dst->dpy, PictStandardA8), + src->src_picture, dst->dst_picture, + pict_format, render_src_x + attributes.x_offset, render_src_y + attributes.y_offset, (XTrapezoid *) traps, num_traps); + } - _cairo_pattern_release_surface (&dst->base, &src->base, &attributes); + FAIL: + _cairo_pattern_release_surface (pattern, &src->base, &attributes); return status; } @@ -913,14 +1446,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 +1487,15 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, rects[i].height = boxes[i].y2 - boxes[i].y1; } - if (surface->gc) - XSetClipRectangles(surface->dpy, surface->gc, - 0, 0, rects, n_boxes, YXSorted); - if (surface->picture) - XRenderSetPictureClipRectangles (surface->dpy, surface->picture, - 0, 0, rects, n_boxes); + surface->have_clip_rects = TRUE; + surface->clip_rects = rects; + surface->num_clip_rects = n_boxes; - if (rects) - free (rects); + if (surface->gc) + _cairo_xlib_surface_set_gc_clip_rects (surface); + + if (surface->dst_picture) + _cairo_xlib_surface_set_picture_clip_rects (surface); } return CAIRO_STATUS_SUCCESS; @@ -975,6 +1516,18 @@ _cairo_xlib_surface_get_extents (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } +static void +_cairo_xlib_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + cairo_xlib_surface_t *surface = abstract_surface; + + *options = surface->screen_info->font_options; + + if (_surface_has_alpha (surface) && options->antialias == CAIRO_ANTIALIAS_SUBPIXEL) + options->antialias = CAIRO_ANTIALIAS_GRAY; +} + static cairo_int_status_t _cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font, cairo_operator_t operator, @@ -1003,8 +1556,11 @@ 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 + _cairo_xlib_surface_show_glyphs, + NULL, /* fill_path */ + _cairo_xlib_surface_get_font_options }; /** @@ -1024,6 +1580,7 @@ _cairo_surface_is_xlib (cairo_surface_t *surface) static cairo_surface_t * _cairo_xlib_surface_create_internal (Display *dpy, Drawable drawable, + Screen *screen, Visual *visual, XRenderPictFormat *format, int width, @@ -1031,42 +1588,47 @@ _cairo_xlib_surface_create_internal (Display *dpy, int depth) { cairo_xlib_surface_t *surface; + cairo_xlib_screen_info_t *screen_info; + + screen_info = _cairo_xlib_screen_info_get (dpy, screen); + if (screen_info == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } surface = malloc (sizeof (cairo_xlib_surface_t)); - if (surface == NULL) - return NULL; + if (surface == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t*) &_cairo_surface_nil; + } _cairo_surface_init (&surface->base, &cairo_xlib_surface_backend); surface->dpy = dpy; + surface->screen_info = screen_info; surface->gc = NULL; surface->drawable = drawable; + surface->screen = screen; 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; + int j, k; /* This is ugly, but we have to walk over all visuals * for the display to find the depth. */ - for (i = 0; i < ScreenCount (dpy); i++) { - Screen *screen = ScreenOfDisplay (dpy, i); - for (j = 0; j < screen->ndepths; j++) { - Depth *depth = &screen->depths[j]; - for (k = 0; k < depth->nvisuals; k++) { - if (&depth->visuals[k] == visual) { - surface->depth = depth->depth; - goto found; - } + for (j = 0; j < screen->ndepths; j++) { + Depth *d = &screen->depths[j]; + for (k = 0; k < d->nvisuals; k++) { + if (&d->visuals[k] == visual) { + depth = d->depth; + goto found; } } } @@ -1080,25 +1642,63 @@ _cairo_xlib_surface_create_internal (Display *dpy, surface->render_minor = -1; } - surface->picture = None; - - if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) { - - if (!format) { - if (visual) { - format = XRenderFindVisualFormat (dpy, visual); - } else if (depth == 1) - format = XRenderFindStandardFormat (dpy, PictStandardA1); - } - - if (format) - surface->picture = XRenderCreatePicture (dpy, drawable, - format, 0, NULL); + surface->buggy_repeat = FALSE; + if (strcmp (ServerVendor (dpy), "The X.Org Foundation") == 0) { + if (VendorRelease (dpy) <= 60802000) + surface->buggy_repeat = TRUE; + } else if (strcmp (ServerVendor (dpy), "The XFree86 Project, Inc") == 0) { + if (VendorRelease (dpy) <= 40400000) + surface->buggy_repeat = TRUE; } + surface->dst_picture = None; + surface->src_picture = None; + + if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) { + if (!format) { + if (visual) + format = XRenderFindVisualFormat (dpy, visual); + else if (depth == 1) + format = XRenderFindStandardFormat (dpy, PictStandardA1); + } + } 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; } +static Screen * +_cairo_xlib_screen_from_visual (Display *dpy, Visual *visual) +{ + int s; + int d; + int v; + Screen *screen; + Depth *depth; + + for (s = 0; s < ScreenCount (dpy); s++) { + screen = ScreenOfDisplay (dpy, s); + if (visual == DefaultVisualOfScreen (screen)) + return screen; + for (d = 0; d < screen->ndepths; d++) { + depth = &screen->depths[d]; + for (v = 0; v < depth->nvisuals; v++) + if (visual == &depth->visuals[v]) + return screen; + } + } + return NULL; +} + /** * cairo_xlib_surface_create: * @dpy: an X Display @@ -1126,7 +1726,14 @@ cairo_xlib_surface_create (Display *dpy, int width, int height) { - return _cairo_xlib_surface_create_internal (dpy, drawable, + Screen *screen = _cairo_xlib_screen_from_visual (dpy, visual); + + if (screen == NULL) { + _cairo_error (CAIRO_STATUS_INVALID_VISUAL); + return (cairo_surface_t*) &_cairo_surface_nil; + } + + return _cairo_xlib_surface_create_internal (dpy, drawable, screen, visual, NULL, width, height, 0); } @@ -1134,6 +1741,7 @@ cairo_xlib_surface_create (Display *dpy, * cairo_xlib_surface_create_for_bitmap: * @dpy: an X Display * @bitmap: an X Drawable, (a depth-1 Pixmap) + * @screen: the X Screen associated with @bitmap * @width: the current width of @bitmap. * @height: the current height of @bitmap. * @@ -1145,10 +1753,11 @@ cairo_xlib_surface_create (Display *dpy, cairo_surface_t * cairo_xlib_surface_create_for_bitmap (Display *dpy, Pixmap bitmap, + Screen *screen, int width, int height) { - return _cairo_xlib_surface_create_internal (dpy, bitmap, + return _cairo_xlib_surface_create_internal (dpy, bitmap, screen, NULL, NULL, width, height, 1); } @@ -1156,6 +1765,7 @@ cairo_xlib_surface_create_for_bitmap (Display *dpy, * cairo_xlib_surface_create_with_xrender_format: * @dpy: an X Display * @drawable: an X Drawable, (a Pixmap or a Window) + * @screen: the X Screen associated with @drawable * @format: the picture format to use for drawing to @drawable. The depth * of @format must match the depth of the drawable. * @width: the current width of @drawable. @@ -1174,11 +1784,12 @@ cairo_xlib_surface_create_for_bitmap (Display *dpy, cairo_surface_t * cairo_xlib_surface_create_with_xrender_format (Display *dpy, Drawable drawable, + Screen *screen, XRenderPictFormat *format, int width, int height) { - return _cairo_xlib_surface_create_internal (dpy, drawable, + return _cairo_xlib_surface_create_internal (dpy, drawable, screen, NULL, format, width, height, 0); } @@ -1212,23 +1823,75 @@ cairo_xlib_surface_set_size (cairo_surface_t *surface, xlib_surface->width = width; xlib_surface->height = height; } +/** + * cairo_xlib_surface_set_drawable: + * @surface: a #cairo_surface_t for the XLib backend + * @drawable: the new drawable for the surface + * + * Informs cairo of a new X Drawable underlying the + * surface. The drawable must match the display, screen + * and format of the existing drawable or the application + * will get X protocol errors and will probably terminate. + * No checks are done by this function to ensure this + * compatibility. + **/ +void +cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface, + Drawable drawable, + int width, + int height) +{ + cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *)abstract_surface; + + /* XXX: How do we want to handle this error case? */ + if (! _cairo_surface_is_xlib (abstract_surface)) + return; + + /* XXX: and what about this case? */ + if (surface->owns_pixmap) + return; + + if (surface->drawable != drawable) { + if (surface->dst_picture) + XRenderFreePicture (surface->dpy, surface->dst_picture); + + if (surface->src_picture) + XRenderFreePicture (surface->dpy, surface->src_picture); + + surface->dst_picture = None; + surface->src_picture = None; + + surface->drawable = drawable; + } + surface->width = width; + surface->height = height; +} /* RENDER glyphset cache code */ typedef struct glyphset_cache { cairo_cache_t base; - struct glyphset_cache *next; + Display *display; - XRenderPictFormat *a8_pict_format; - GlyphSet glyphset; Glyph counter; + + XRenderPictFormat *a1_pict_format; + GlyphSet a1_glyphset; + + XRenderPictFormat *a8_pict_format; + GlyphSet a8_glyphset; + + XRenderPictFormat *argb32_pict_format; + GlyphSet argb32_glyphset; + + struct glyphset_cache *next; } glyphset_cache_t; typedef struct { cairo_glyph_cache_key_t key; + GlyphSet glyphset; Glyph glyph; - XGlyphInfo info; - int refcount; + cairo_glyph_size_t size; } glyphset_cache_entry_t; static Glyph @@ -1237,44 +1900,68 @@ _next_xlib_glyph (glyphset_cache_t *cache) return ++(cache->counter); } +static cairo_bool_t +_native_byte_order_lsb (void) +{ + int x = 1; + + return *((char *) &x) == 1; +} static cairo_status_t -_xlib_glyphset_cache_create_entry (void *cache, - void *key, +_xlib_glyphset_cache_create_entry (void *abstract_cache, + void *abstract_key, void **return_entry) { - glyphset_cache_t *g = (glyphset_cache_t *) cache; - cairo_glyph_cache_key_t *k = (cairo_glyph_cache_key_t *)key; - glyphset_cache_entry_t *v; + glyphset_cache_t *cache = abstract_cache; + cairo_glyph_cache_key_t *key = abstract_key; + glyphset_cache_entry_t *entry; + XGlyphInfo glyph_info; + unsigned char *data; cairo_status_t status; cairo_cache_t *im_cache; cairo_image_glyph_cache_entry_t *im; - v = malloc (sizeof (glyphset_cache_entry_t)); + entry = malloc (sizeof (glyphset_cache_entry_t)); _cairo_lock_global_image_glyph_cache (); im_cache = _cairo_get_global_image_glyph_cache (); - if (g == NULL || v == NULL || im_cache == NULL) { + if (cache == NULL || entry == NULL || im_cache == NULL) { _cairo_unlock_global_image_glyph_cache (); + if (entry) + free (entry); return CAIRO_STATUS_NO_MEMORY; } status = _cairo_cache_lookup (im_cache, key, (void **) (&im), NULL); if (status != CAIRO_STATUS_SUCCESS || im == NULL) { _cairo_unlock_global_image_glyph_cache (); + free (entry); return CAIRO_STATUS_NO_MEMORY; } - v->refcount = 1; - v->key = *k; - _cairo_unscaled_font_reference (v->key.unscaled); + entry->key = *key; + _cairo_unscaled_font_reference (entry->key.unscaled); - v->glyph = _next_xlib_glyph (g); + if (!im->image) { + entry->glyph = None; + entry->glyphset = None; + entry->key.base.memory = 0; + entry->size.x = entry->size.y = entry->size.width = entry->size.height = 0; + + goto out; + } + + entry->glyph = _next_xlib_glyph (cache); - v->info.width = im->image ? im->image->stride : im->size.width; - v->info.height = im->size.height; + data = im->image->data; + + entry->size = im->size; + + glyph_info.width = im->size.width; + glyph_info.height = im->size.height; /* * Most of the font rendering system thinks of glyph tiles as having @@ -1312,28 +1999,91 @@ _xlib_glyphset_cache_create_entry (void *cache, * sitting around for x and y. */ - v->info.x = -im->size.x; - v->info.y = -im->size.y; - v->info.xOff = 0; - v->info.yOff = 0; + glyph_info.x = -im->size.x; + glyph_info.y = -im->size.y; + glyph_info.xOff = 0; + glyph_info.yOff = 0; - XRenderAddGlyphs (g->display, g->glyphset, - &(v->glyph), &(v->info), 1, - im->image ? (char *) im->image->data : NULL, - im->image ? v->info.height * v->info.width : 0); + switch (im->image->format) { + case CAIRO_FORMAT_A1: + /* local bitmaps are always stored with bit == byte */ + if (_native_byte_order_lsb() != + (BitmapBitOrder (cache->display) == LSBFirst)) + { + int c = im->image->stride * im->size.height; + unsigned char *d; + unsigned char *new, *n; + + new = malloc (c); + if (!new) + return CAIRO_STATUS_NO_MEMORY; + n = new; + d = data; + while (c--) + { + char b = *d++; + b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55); + b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33); + b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f); + *n++ = b; + } + data = new; + } + entry->glyphset = cache->a1_glyphset; + break; + case CAIRO_FORMAT_A8: + entry->glyphset = cache->a8_glyphset; + break; + case CAIRO_FORMAT_ARGB32: + if (_native_byte_order_lsb() != + (ImageByteOrder (cache->display) == LSBFirst)) + { + int c = im->image->stride * im->size.height; + unsigned char *d; + unsigned char *new, *n; + + new = malloc (c); + if (!new) + return CAIRO_STATUS_NO_MEMORY; + n = new; + d = data; + while ((c -= 4) >= 0) + { + n[3] = d[0]; + n[2] = d[1]; + n[1] = d[2]; + n[0] = d[3]; + d += 4; + n += 4; + } + data = new; + } + entry->glyphset = cache->argb32_glyphset; + break; + case CAIRO_FORMAT_RGB24: + default: + ASSERT_NOT_REACHED; + break; + } + /* XXX assume X server wants pixman padding. Xft assumes this as well */ - v->key.base.memory = im->image ? im->image->width * im->image->stride : 0; - *return_entry = v; + XRenderAddGlyphs (cache->display, entry->glyphset, + &(entry->glyph), &(glyph_info), 1, + (char *) data, + im->image->stride * glyph_info.height); + + if (data != im->image->data) + free (data); + + entry->key.base.memory = im->image->height * im->image->stride; + + out: + *return_entry = entry; _cairo_unlock_global_image_glyph_cache (); + return CAIRO_STATUS_SUCCESS; } -static void -_glyphset_cache_entry_reference (glyphset_cache_entry_t *e) -{ - e->refcount++; -} - static void _xlib_glyphset_cache_destroy_cache (void *cache) { @@ -1341,20 +2091,17 @@ _xlib_glyphset_cache_destroy_cache (void *cache) } static void -_xlib_glyphset_cache_destroy_entry (void *cache, void *entry) +_xlib_glyphset_cache_destroy_entry (void *abstract_cache, + void *abstract_entry) { - glyphset_cache_t *g; - glyphset_cache_entry_t *v; + glyphset_cache_t *cache = abstract_cache; + glyphset_cache_entry_t *entry = abstract_entry; - g = (glyphset_cache_t *) cache; - v = (glyphset_cache_entry_t *) entry; - - if (--v->refcount > 0) - return; - - _cairo_unscaled_font_destroy (v->key.unscaled); - XRenderFreeGlyphs (g->display, g->glyphset, &(v->glyph), 1); - free (v); + _cairo_unscaled_font_destroy (entry->key.unscaled); + if (entry->glyph) + XRenderFreeGlyphs (cache->display, entry->glyphset, + &(entry->glyph), 1); + free (entry); } static const cairo_cache_backend_t _xlib_glyphset_cache_backend = { @@ -1365,6 +2112,7 @@ static const cairo_cache_backend_t _xlib_glyphset_cache_backend = { _xlib_glyphset_cache_destroy_cache }; +CAIRO_MUTEX_DECLARE(_xlib_glyphset_caches_mutex); static glyphset_cache_t * _xlib_glyphset_caches = NULL; @@ -1372,13 +2120,17 @@ _xlib_glyphset_caches = NULL; static void _lock_xlib_glyphset_caches (void) { - /* FIXME: implement locking */ + CAIRO_MUTEX_LOCK(_xlib_glyphset_caches_mutex); } static void -_unlock_xlib_glyphset_caches (void) +_unlock_xlib_glyphset_caches (glyphset_cache_t *cache) { - /* FIXME: implement locking */ + if (cache) { + _cairo_cache_shrink_to (&cache->base, + CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT); + } + CAIRO_MUTEX_UNLOCK(_xlib_glyphset_caches_mutex); } static glyphset_cache_t * @@ -1388,36 +2140,42 @@ _get_glyphset_cache (Display *d) * There should usually only be one, or a very small number, of * displays. So we just do a linear scan. */ + glyphset_cache_t *cache; - glyphset_cache_t *g; - - for (g = _xlib_glyphset_caches; g != NULL; g = g->next) { - if (g->display == d) - return g; + /* XXX: This is not thread-safe. Xft has example code to get + * per-display data via Xlib extension mechanisms. */ + for (cache = _xlib_glyphset_caches; cache != NULL; cache = cache->next) { + if (cache->display == d) + return cache; } - g = malloc (sizeof (glyphset_cache_t)); - if (g == NULL) + cache = malloc (sizeof (glyphset_cache_t)); + if (cache == NULL) goto ERR; - g->counter = 0; - g->display = d; - g->a8_pict_format = XRenderFindStandardFormat (d, PictStandardA8); - if (g->a8_pict_format == NULL) - goto ERR; - - if (_cairo_cache_init (&g->base, - &_xlib_glyphset_cache_backend, - CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT)) + if (_cairo_cache_init (&cache->base, + &_xlib_glyphset_cache_backend, 0)) goto FREE_GLYPHSET_CACHE; + + cache->display = d; + cache->counter = 0; + + cache->a1_pict_format = XRenderFindStandardFormat (d, PictStandardA1); + cache->a1_glyphset = XRenderCreateGlyphSet (d, cache->a1_pict_format); + + cache->a8_pict_format = XRenderFindStandardFormat (d, PictStandardA8); + cache->a8_glyphset = XRenderCreateGlyphSet (d, cache->a8_pict_format); + + cache->argb32_pict_format = XRenderFindStandardFormat (d, PictStandardARGB32); + cache->argb32_glyphset = XRenderCreateGlyphSet (d, cache->argb32_pict_format);; - g->glyphset = XRenderCreateGlyphSet (d, g->a8_pict_format); - g->next = _xlib_glyphset_caches; - _xlib_glyphset_caches = g; - return g; + cache->next = _xlib_glyphset_caches; + _xlib_glyphset_caches = cache; + + return cache; FREE_GLYPHSET_CACHE: - free (g); + free (cache); ERR: return NULL; @@ -1425,10 +2183,32 @@ _get_glyphset_cache (Display *d) #define N_STACK_BUF 1024 +static XRenderPictFormat * +_select_text_mask_format (glyphset_cache_t *cache, + cairo_bool_t have_a1_glyphs, + cairo_bool_t have_a8_glyphs, + cairo_bool_t have_argb32_glyphs) +{ + if (have_a8_glyphs) + return cache->a8_pict_format; + + if (have_a1_glyphs && have_argb32_glyphs) + return cache->a8_pict_format; + + if (have_a1_glyphs) + return cache->a1_pict_format; + + if (have_argb32_glyphs) + return cache->argb32_pict_format; + + /* when there are no glyphs to draw, just pick something */ + return cache->a8_pict_format; +} + static cairo_status_t _cairo_xlib_surface_show_glyphs32 (cairo_scaled_font_t *scaled_font, cairo_operator_t operator, - glyphset_cache_t *g, + glyphset_cache_t *cache, cairo_glyph_cache_key_t *key, cairo_xlib_surface_t *src, cairo_xlib_surface_t *self, @@ -1444,10 +2224,13 @@ _cairo_xlib_surface_show_glyphs32 (cairo_scaled_font_t *scaled_font, unsigned int *chars = NULL; unsigned int stack_chars [N_STACK_BUF]; - int i; + int i, count; int thisX, thisY; int lastX = 0, lastY = 0; + cairo_bool_t have_a1, have_a8, have_argb32; + XRenderPictFormat *mask_format; + /* Acquire arrays of suitable sizes. */ if (num_glyphs < N_STACK_BUF) { elts = stack_elts; @@ -1464,27 +2247,50 @@ _cairo_xlib_surface_show_glyphs32 (cairo_scaled_font_t *scaled_font, } + have_a1 = FALSE; + have_a8 = FALSE; + have_argb32 = FALSE; + count = 0; + for (i = 0; i < num_glyphs; ++i) { - chars[i] = entries[i]->glyph; - elts[i].chars = &(chars[i]); - elts[i].nchars = 1; - elts[i].glyphset = g->glyphset; + GlyphSet glyphset; + + if (!entries[i]->glyph) + continue; + + glyphset = entries[i]->glyphset; + + if (glyphset == cache->a1_glyphset) + have_a1 = TRUE; + else if (glyphset == cache->a8_glyphset) + have_a8 = TRUE; + else if (glyphset == cache->argb32_glyphset) + have_argb32 = TRUE; + + chars[count] = entries[i]->glyph; + elts[count].chars = &(chars[count]); + elts[count].nchars = 1; + elts[count].glyphset = glyphset; thisX = (int) floor (glyphs[i].x + 0.5); thisY = (int) floor (glyphs[i].y + 0.5); - elts[i].xOff = thisX - lastX; - elts[i].yOff = thisY - lastY; + elts[count].xOff = thisX - lastX; + elts[count].yOff = thisY - lastY; lastX = thisX; lastY = thisY; + count++; } + mask_format = _select_text_mask_format (cache, + have_a1, have_a8, have_argb32); + XRenderCompositeText32 (self->dpy, _render_operator (operator), - src->picture, - self->picture, - g->a8_pict_format, + src->src_picture, + self->dst_picture, + mask_format, source_x, source_y, 0, 0, - elts, num_glyphs); + elts, count); if (num_glyphs >= N_STACK_BUF) { free (chars); @@ -1505,7 +2311,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo_scaled_font_t *scaled_font, static cairo_status_t _cairo_xlib_surface_show_glyphs16 (cairo_scaled_font_t *scaled_font, cairo_operator_t operator, - glyphset_cache_t *g, + glyphset_cache_t *cache, cairo_glyph_cache_key_t *key, cairo_xlib_surface_t *src, cairo_xlib_surface_t *self, @@ -1521,10 +2327,13 @@ _cairo_xlib_surface_show_glyphs16 (cairo_scaled_font_t *scaled_font, unsigned short *chars = NULL; unsigned short stack_chars [N_STACK_BUF]; - int i; + int i, count; int thisX, thisY; int lastX = 0, lastY = 0; + cairo_bool_t have_a1, have_a8, have_argb32; + XRenderPictFormat *mask_format; + /* Acquire arrays of suitable sizes. */ if (num_glyphs < N_STACK_BUF) { elts = stack_elts; @@ -1541,27 +2350,50 @@ _cairo_xlib_surface_show_glyphs16 (cairo_scaled_font_t *scaled_font, } + have_a1 = FALSE; + have_a8 = FALSE; + have_argb32 = FALSE; + count = 0; + for (i = 0; i < num_glyphs; ++i) { - chars[i] = entries[i]->glyph; - elts[i].chars = &(chars[i]); - elts[i].nchars = 1; - elts[i].glyphset = g->glyphset; + GlyphSet glyphset; + + if (!entries[i]->glyph) + continue; + + glyphset = entries[i]->glyphset; + + if (glyphset == cache->a1_glyphset) + have_a1 = TRUE; + else if (glyphset == cache->a8_glyphset) + have_a8 = TRUE; + else if (glyphset == cache->argb32_glyphset) + have_argb32 = TRUE; + + chars[count] = entries[i]->glyph; + elts[count].chars = &(chars[count]); + elts[count].nchars = 1; + elts[count].glyphset = glyphset; thisX = (int) floor (glyphs[i].x + 0.5); thisY = (int) floor (glyphs[i].y + 0.5); - elts[i].xOff = thisX - lastX; - elts[i].yOff = thisY - lastY; + elts[count].xOff = thisX - lastX; + elts[count].yOff = thisY - lastY; lastX = thisX; lastY = thisY; + count++; } + mask_format = _select_text_mask_format (cache, + have_a1, have_a8, have_argb32); + XRenderCompositeText16 (self->dpy, _render_operator (operator), - src->picture, - self->picture, - g->a8_pict_format, + src->src_picture, + self->dst_picture, + mask_format, source_x, source_y, 0, 0, - elts, num_glyphs); + elts, count); if (num_glyphs >= N_STACK_BUF) { free (chars); @@ -1581,7 +2413,7 @@ _cairo_xlib_surface_show_glyphs16 (cairo_scaled_font_t *scaled_font, static cairo_status_t _cairo_xlib_surface_show_glyphs8 (cairo_scaled_font_t *scaled_font, cairo_operator_t operator, - glyphset_cache_t *g, + glyphset_cache_t *cache, cairo_glyph_cache_key_t *key, cairo_xlib_surface_t *src, cairo_xlib_surface_t *self, @@ -1597,10 +2429,16 @@ _cairo_xlib_surface_show_glyphs8 (cairo_scaled_font_t *scaled_font, char *chars = NULL; char stack_chars [N_STACK_BUF]; - int i; + int i, count; int thisX, thisY; int lastX = 0, lastY = 0; + cairo_bool_t have_a1, have_a8, have_argb32; + XRenderPictFormat *mask_format; + + if (num_glyphs == 0) + return CAIRO_STATUS_SUCCESS; + /* Acquire arrays of suitable sizes. */ if (num_glyphs < N_STACK_BUF) { elts = stack_elts; @@ -1617,27 +2455,50 @@ _cairo_xlib_surface_show_glyphs8 (cairo_scaled_font_t *scaled_font, } + have_a1 = FALSE; + have_a8 = FALSE; + have_argb32 = FALSE; + count = 0; + for (i = 0; i < num_glyphs; ++i) { - chars[i] = entries[i]->glyph; - elts[i].chars = &(chars[i]); - elts[i].nchars = 1; - elts[i].glyphset = g->glyphset; + GlyphSet glyphset; + + if (!entries[i]->glyph) + continue; + + glyphset = entries[i]->glyphset; + + if (glyphset == cache->a1_glyphset) + have_a1 = TRUE; + else if (glyphset == cache->a8_glyphset) + have_a8 = TRUE; + else if (glyphset == cache->argb32_glyphset) + have_argb32 = TRUE; + + chars[count] = entries[i]->glyph; + elts[count].chars = &(chars[count]); + elts[count].nchars = 1; + elts[count].glyphset = glyphset; thisX = (int) floor (glyphs[i].x + 0.5); thisY = (int) floor (glyphs[i].y + 0.5); - elts[i].xOff = thisX - lastX; - elts[i].yOff = thisY - lastY; + elts[count].xOff = thisX - lastX; + elts[count].yOff = thisY - lastY; lastX = thisX; lastY = thisY; + count++; } + mask_format = _select_text_mask_format (cache, + have_a1, have_a8, have_argb32); + XRenderCompositeText8 (self->dpy, _render_operator (operator), - src->picture, - self->picture, - g->a8_pict_format, + src->src_picture, + self->dst_picture, + mask_format, source_x, source_y, 0, 0, - elts, num_glyphs); + elts, count); if (num_glyphs >= N_STACK_BUF) { free (chars); @@ -1654,7 +2515,63 @@ _cairo_xlib_surface_show_glyphs8 (cairo_scaled_font_t *scaled_font, return CAIRO_STATUS_NO_MEMORY; } +/* Handles clearing the regions that are outside of the temporary + * mask created by XRenderCompositeText[N] but should be affected + * by an unbounded operator like CAIRO_OPERATOR_SOURCE. + */ +static cairo_status_t +_show_glyphs_fixup_unbounded (cairo_xlib_surface_t *self, + cairo_surface_attributes_t *src_attr, + cairo_xlib_surface_t *src, + const cairo_glyph_t *glyphs, + glyphset_cache_entry_t **entries, + int num_glyphs, + int src_x, + int src_y, + int dst_x, + int dst_y, + int width, + int height) +{ + int x1 = INT_MAX; + int x2 = INT_MIN; + int y1 = INT_MAX; + int y2 = INT_MIN; + int i; + /* Compute the size of the glyph mask as the bounding box + * of all the glyphs. + */ + for (i = 0; i < num_glyphs; ++i) { + int thisX, thisY; + + if (entries[i] == NULL || !entries[i]->glyph) + continue; + + thisX = (int) floor (glyphs[i].x + 0.5); + thisY = (int) floor (glyphs[i].y + 0.5); + + if (thisX + entries[i]->size.x < x1) + x1 = thisX + entries[i]->size.x; + if (thisX + entries[i]->size.x + entries[i]->size.width > x2) + x2 = thisX + entries[i]->size.x + entries[i]->size.width; + if (thisY + entries[i]->size.y < y1) + y1 = thisY + entries[i]->size.y; + if (thisY + entries[i]->size.y + entries[i]->size.height > y2) + y2 = thisY + entries[i]->size.y + entries[i]->size.height; + } + + if (x1 >= x2 || y1 >= y2) + x1 = x2 = y1 = y2 = 0; + + return _cairo_surface_composite_shape_fixup_unbounded (&self->base, + src_attr, src->width, src->height, + x2 - x1, y2 - y1, + src_x, src_y, + dst_x - x1, dst_y - y1, + dst_x, dst_y, width, height); +} + static cairo_int_status_t _cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font, cairo_operator_t operator, @@ -1674,15 +2591,20 @@ _cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font, unsigned int elt_size; cairo_xlib_surface_t *self = abstract_surface; cairo_xlib_surface_t *src; - glyphset_cache_t *g; + glyphset_cache_t *cache; 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_operation (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 +2612,12 @@ _cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font, if (status) return status; + operation = _recategorize_composite_operation (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; @@ -1705,29 +2633,22 @@ _cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font, } _lock_xlib_glyphset_caches (); - g = _get_glyphset_cache (self->dpy); - if (g == NULL) + cache = _get_glyphset_cache (self->dpy); + if (cache == NULL) goto UNLOCK; /* Work out the index size to use. */ elt_size = 8; - _cairo_scaled_font_get_glyph_cache_key (scaled_font, &key); + status = _cairo_scaled_font_get_glyph_cache_key (scaled_font, &key); + if (status) + goto UNLOCK; for (i = 0; i < num_glyphs; ++i) { key.index = glyphs[i].index; - status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i]), NULL); + status = _cairo_cache_lookup (&cache->base, &key, (void **) (&entries[i]), NULL); if (status != CAIRO_STATUS_SUCCESS || entries[i] == NULL) goto UNLOCK; - /* Referencing the glyph entries we use prevents them from - * being freed if lookup of later entries causes them to - * be ejected from the cache. It would be more efficient - * (though more complex) to prevent them from being ejected - * from the cache at all, so they could get reused later - * in the same string. - */ - _glyphset_cache_entry_reference (entries[i]); - if (elt_size == 8 && entries[i]->glyph > 0xff) elt_size = 16; if (elt_size == 16 && entries[i]->glyph > 0xffff) { @@ -1738,33 +2659,65 @@ _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, + { + status = _cairo_xlib_surface_show_glyphs8 (scaled_font, operator, cache, &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, + { + status = _cairo_xlib_surface_show_glyphs16 (scaled_font, operator, cache, &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, + { + status = _cairo_xlib_surface_show_glyphs32 (scaled_font, operator, cache, &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]); + if (status == CAIRO_STATUS_SUCCESS && + !_cairo_operator_bounded (operator)) + status = _show_glyphs_fixup_unbounded (self, + &attributes, src, + glyphs, entries, num_glyphs, + source_x, source_y, + dest_x, dest_y, width, height); UNLOCK: - _unlock_xlib_glyphset_caches (); + _unlock_xlib_glyphset_caches (cache); if (num_glyphs >= N_STACK_BUF) free (entries); FAIL: - _cairo_pattern_release_surface (&self->base, &src->base, &attributes); + _cairo_pattern_release_surface (pattern, &src->base, &attributes); return status; } + +static void +_destroy_glyphset_cache_recurse (glyphset_cache_t *cache) +{ + if (cache == NULL) + return; + + _destroy_glyphset_cache_recurse (cache->next); + _cairo_cache_destroy (&cache->base); + free (cache); +} + +void +_cairo_xlib_surface_reset_static_data (void) +{ + _lock_xlib_glyphset_caches (); + _destroy_glyphset_cache_recurse (_xlib_glyphset_caches); + _xlib_glyphset_caches = NULL; + _unlock_xlib_glyphset_caches (NULL); +} diff --git a/gfx/cairo/cairo/src/cairo-xlib-test.h b/gfx/cairo/cairo/src/cairo-xlib-test.h index 0ee570fb2ecb..44b986c7f3e9 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-test.h +++ b/gfx/cairo/cairo/src/cairo-xlib-test.h @@ -39,7 +39,7 @@ #include -#ifdef CAIRO_HAS_XLIB_SURFACE +#if CAIRO_HAS_XLIB_SURFACE #include diff --git a/gfx/cairo/cairo/src/cairo-xlib-xrender.h b/gfx/cairo/cairo/src/cairo-xlib-xrender.h index d3ebe3f976fb..71b2397728eb 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-xrender.h +++ b/gfx/cairo/cairo/src/cairo-xlib-xrender.h @@ -39,7 +39,7 @@ #include -#ifdef CAIRO_HAS_XLIB_SURFACE +#if CAIRO_HAS_XLIB_SURFACE #include @@ -48,6 +48,7 @@ CAIRO_BEGIN_DECLS cairo_surface_t * cairo_xlib_surface_create_with_xrender_format (Display *dpy, Drawable drawable, + Screen *screen, XRenderPictFormat *format, int width, int height); diff --git a/gfx/cairo/cairo/src/cairo-xlib.h b/gfx/cairo/cairo/src/cairo-xlib.h index 0bcd45022139..5cdf1378b5fb 100644 --- a/gfx/cairo/cairo/src/cairo-xlib.h +++ b/gfx/cairo/cairo/src/cairo-xlib.h @@ -39,7 +39,7 @@ #include -#ifdef CAIRO_HAS_XLIB_SURFACE +#if CAIRO_HAS_XLIB_SURFACE #include @@ -55,6 +55,7 @@ cairo_xlib_surface_create (Display *dpy, cairo_surface_t * cairo_xlib_surface_create_for_bitmap (Display *dpy, Pixmap bitmap, + Screen *screen, int width, int height); @@ -63,6 +64,12 @@ cairo_xlib_surface_set_size (cairo_surface_t *surface, int width, int height); +void +cairo_xlib_surface_set_drawable (cairo_surface_t *surface, + Drawable drawable, + int width, + int height); + CAIRO_END_DECLS #else /* CAIRO_HAS_XLIB_SURFACE */ diff --git a/gfx/cairo/cairo/src/cairo.c b/gfx/cairo/cairo/src/cairo.c index e92a15755ef8..8d759eadaf22 100644 --- a/gfx/cairo/cairo/src/cairo.c +++ b/gfx/cairo/cairo/src/cairo.c @@ -43,37 +43,116 @@ #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 -#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_FILE_NOT_FOUND + +/** + * _cairo_error: + * @status: a status value indicating an error, (eg. not + * CAIRO_STATUS_SUCCESS) + * + * Checks that status is an error status, but does nothing else. + * + * All assignments of an error status to any user-visible object + * within the cairo application should result in a call to + * _cairo_error(). + * + * 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. + **/ +void +_cairo_error (cairo_status_t status) +{ + assert (status > CAIRO_STATUS_SUCCESS && + status <= CAIRO_STATUS_LAST_STATUS); } -#define CAIRO_CHECK_SANITY(cr) assert(cairo_sane_state ((cr))) -#endif -/* +/** + * _cairo_set_error: + * @cr: a cairo context + * @status: a status value indicating an error, (eg. not + * CAIRO_STATUS_SUCCESS) + * + * Sets cr->status to @status and calls _cairo_error; + * + * All assignments of an error status to cr->status should happen + * through _cairo_set_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. + **/ +static void +_cairo_set_error (cairo_t *cr, cairo_status_t status) +{ + cr->status = status; + + _cairo_error (status); +} + +/** + * cairo_version: + * + * Returns the version of the cairo library encoded in a single + * integer as per CAIRO_VERSION_ENCODE. The encoding ensures that + * later versions compare greater than earlier versions. + * + * A run-time comparison to check that cairo's version is greater than + * or equal to version X.Y.Z could be performed as follows: + * + * + * if (cairo_version() >= CAIRO_VERSION_ENCODE(X,Y,Z)) {...} + * + * + * See also cairo_version_string() as well as the compile-time + * equivalents %CAIRO_VERSION and %CAIRO_VERSION_STRING. + * + * Return value: the encoded version. + **/ +int +cairo_version (void) +{ + return CAIRO_VERSION; +} + +/** + * cairo_version_string: + * + * Returns the version of the cairo library as a human-readable string + * of the form "X.Y.Z". + * + * See also cairo_version() as well as the compile-time equivalents + * %CAIRO_VERSION_STRING and %CAIRO_VERSION. + * + * Return value: a string containing the version. + **/ +const char* +cairo_version_string (void) +{ + return CAIRO_VERSION_STRING; +} + +/** * cairo_create: * @target: target surface for the context * @@ -81,7 +160,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__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 +179,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,18 +192,24 @@ cairo_create (cairo_surface_t *target) cr = malloc (sizeof (cairo_t)); if (cr == NULL) - return NULL; + return (cairo_t *) &cairo_nil; + + cr->ref_count = 1; cr->status = CAIRO_STATUS_SUCCESS; - cr->ref_count = 1; _cairo_path_fixed_init (&cr->path); + if (target == NULL) { + cr->gstate = NULL; + _cairo_set_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_set_error (cr, CAIRO_STATUS_NO_MEMORY); - CAIRO_CHECK_SANITY (cr); return cr; } @@ -130,16 +220,18 @@ cairo_create (cairo_surface_t *target) * Increases the reference count on @cr by one. This prevents * @cr from being destroyed until a matching call to cairo_destroy() * is made. + * + * Return value: the referenced #cairo_t. **/ -void +cairo_t * cairo_reference (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) - return; - + if (cr->ref_count == (unsigned int)-1) + return cr; + cr->ref_count++; - CAIRO_CHECK_SANITY (cr); + + return cr; } /** @@ -153,7 +245,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; @@ -191,21 +285,20 @@ cairo_save (cairo_t *cr) { cairo_gstate_t *top; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_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_set_error (cr, CAIRO_STATUS_NO_MEMORY); return; } top->next = cr->gstate; cr->gstate = top; - CAIRO_CHECK_SANITY (cr); } slim_hidden_def(cairo_save); @@ -222,9 +315,10 @@ cairo_restore (cairo_t *cr) { cairo_gstate_t *top; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_error (cr, cr->status); return; + } top = cr->gstate; cr->gstate = top->next; @@ -232,12 +326,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_set_error (cr, CAIRO_STATUS_INVALID_RESTORE); } slim_hidden_def(cairo_restore); @@ -285,12 +374,14 @@ 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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_operator (cr->gstate, op); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -311,21 +402,16 @@ cairo_set_operator (cairo_t *cr, cairo_operator_t op) void cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue) { - cairo_color_t color; + cairo_pattern_t *pattern; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_error (cr, cr->status); return; + } - _cairo_restrict_value (&red, 0.0, 1.0); - _cairo_restrict_value (&green, 0.0, 1.0); - _cairo_restrict_value (&blue, 0.0, 1.0); - - _cairo_color_init_rgb (&color, red, green, blue); - - cr->status = _cairo_gstate_set_source_solid (cr->gstate, &color); - - CAIRO_CHECK_SANITY (cr); + pattern = cairo_pattern_create_rgb (red, green, blue); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); } /** @@ -349,24 +435,41 @@ cairo_set_source_rgba (cairo_t *cr, double red, double green, double blue, double alpha) { - cairo_color_t color; + cairo_pattern_t *pattern; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_error (cr, cr->status); return; + } - _cairo_restrict_value (&red, 0.0, 1.0); - _cairo_restrict_value (&green, 0.0, 1.0); - _cairo_restrict_value (&blue, 0.0, 1.0); - _cairo_restrict_value (&alpha, 0.0, 1.0); - - _cairo_color_init_rgba (&color, red, green, blue, alpha); - - cr->status = _cairo_gstate_set_source_solid (cr->gstate, &color); - - CAIRO_CHECK_SANITY (cr); + pattern = cairo_pattern_create_rgba (red, green, blue, alpha); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); } +/** + * cairo_set_source_surface: + * @cr: a cairo context + * @surface: a surface to be used to set the source pattern + * @x: User-space X coordinate for surface origin + * @y: User-space Y coordinate for surface origin + * + * This is a convenience function for creating a pattern from @surface + * and setting it as the source in @cr with cairo_set_source(). + * + * The @x and @y parameters give the user-space coordinate at which + * the surface origin should appear. (The surface origin is its + * upper-left corner before any transformation has been applied.) The + * @x and @y patterns are negated and then set as translation values + * in the pattern matrix. + * + * Other than the initial translation pattern matrix, as described + * above, all other pattern attributes, (such as its extend mode), are + * set to the default values as in cairo_pattern_create_for_surface. + * The resulting pattern can be queried with cairo_get_source() so + * that these attributes can be modified if desired, (eg. to create a + * repeating pattern with cairo_pattern_set_extend()). + **/ void cairo_set_source_surface (cairo_t *cr, cairo_surface_t *surface, @@ -376,23 +479,18 @@ cairo_set_source_surface (cairo_t *cr, cairo_pattern_t *pattern; cairo_matrix_t matrix; - CAIRO_CHECK_SANITY (cr); - if (cr->status) - return; - - pattern = cairo_pattern_create_for_surface (surface); - if (!pattern) { - cr->status = CAIRO_STATUS_NO_MEMORY; + if (cr->status) { + _cairo_set_error (cr, cr->status); return; } + pattern = cairo_pattern_create_for_surface (surface); + 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); } /** @@ -405,6 +503,11 @@ cairo_set_source_surface (cairo_t *cr, * will then be used for any subsequent drawing operation until a new * source pattern is set. * + * Note: The pattern's transformation matrix will be locked to the + * user space in effect at the time of cairo_set_source(). This means + * that further modifications of the CTM will not affect the source + * pattern. See cairo_pattern_set_matrix(). + * * XXX: I'd also like to direct the reader's attention to some * (not-yet-written) section on cairo's imaging model. How would I do * that if such a section existed? (cworth). @@ -412,12 +515,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_set_error (cr, cr->status); return; + } + + if (source == NULL) { + _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER); + return; + } + + if (source->status) { + _cairo_set_error (cr, source->status); + return; + } cr->status = _cairo_gstate_set_source (cr->gstate, source); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -433,11 +548,8 @@ 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; - */ + return (cairo_pattern_t*) &cairo_solid_pattern_nil.base; return _cairo_gstate_get_source (cr->gstate); } @@ -458,14 +570,42 @@ 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_set_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_set_error (cr, cr->status); +} + +/** + * cairo_set_antialias: + * @cr: a #cairo_t + * @antialias: the new antialiasing mode + * + * Set the antialiasing mode of the rasterizer used for drawing shapes. + * This value is a hint, and a particular backend may or may not support + * a particular value. At the current time, no backend supports + * %CAIRO_ANTIALIAS_SUBPIXEL when drawing shapes. + * + * Note that this option does not affect text rendering, instead see + * cairo_font_options_set_antialias(). + **/ +void +cairo_set_antialias (cairo_t *cr, cairo_antialias_t antialias) +{ + if (cr->status) { + _cairo_set_error (cr, cr->status); + return; + } + + cr->status = _cairo_gstate_set_antialias (cr->gstate, antialias); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -482,12 +622,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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_fill_rule (cr->gstate, fill_rule); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -507,14 +649,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_set_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_set_error (cr, cr->status); } /** @@ -534,12 +678,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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_line_cap (cr->gstate, line_cap); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -559,34 +705,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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_line_join (cr->gstate, line_join); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_dash (cr->gstate, dashes, ndash, offset); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_miter_limit (cr->gstate, limit); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } @@ -596,7 +748,7 @@ cairo_set_miter_limit (cairo_t *cr, double limit) * @tx: amount to translate in the X direction * @ty: amount to translate in the Y direction * - * Modifies the current transformation matrix (CTM) by tanslating the + * Modifies the current transformation matrix (CTM) by translating the * user-space origin by (@tx, @ty). This offset is interpreted as a * user-space coordinate according to the CTM in place before the new * call to cairo_translate. In other words, the translation of the @@ -605,12 +757,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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_translate (cr->gstate, tx, ty); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -627,12 +781,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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_scale (cr->gstate, sx, sy); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } @@ -651,12 +807,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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_rotate (cr->gstate, angle); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -672,12 +830,14 @@ void cairo_transform (cairo_t *cr, const cairo_matrix_t *matrix) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_transform (cr->gstate, matrix); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -692,12 +852,14 @@ void cairo_set_matrix (cairo_t *cr, const cairo_matrix_t *matrix) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_matrix (cr->gstate, matrix); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -712,12 +874,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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_identity_matrix (cr->gstate); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -733,12 +897,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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_user_to_device (cr->gstate, x, y); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -755,12 +921,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_set_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_set_error (cr, cr->status); } /** @@ -776,12 +944,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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_device_to_user (cr->gstate, x, y); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -798,24 +968,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_set_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_set_error (cr, cr->status); } void cairo_new_path (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_error (cr, cr->status); return; + } _cairo_path_fixed_fini (&cr->path); - - CAIRO_CHECK_SANITY (cr); } slim_hidden_def(cairo_new_path); @@ -824,17 +995,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_set_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_set_error (cr, cr->status); } slim_hidden_def(cairo_move_to); @@ -843,17 +1015,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_set_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_set_error (cr, cr->status); } void @@ -866,9 +1039,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_set_error (cr, cr->status); return; + } _cairo_gstate_user_to_backend (cr->gstate, &x1, &y1); _cairo_gstate_user_to_backend (cr->gstate, &x2, &y2); @@ -887,8 +1061,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_set_error (cr, cr->status); } /** @@ -930,9 +1104,10 @@ cairo_arc (cairo_t *cr, double radius, double angle1, double angle2) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_error (cr, cr->status); return; + } /* Do nothing, successfully, if radius is <= 0 */ if (radius <= 0.0) @@ -947,8 +1122,6 @@ cairo_arc (cairo_t *cr, _cairo_arc_path (cr, xc, yc, radius, angle1, angle2); - - CAIRO_CHECK_SANITY (cr); } /** @@ -971,9 +1144,10 @@ cairo_arc_negative (cairo_t *cr, double radius, double angle1, double angle2) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_error (cr, cr->status); return; + } /* Do nothing, successfully, if radius is <= 0 */ if (radius <= 0.0) @@ -988,8 +1162,6 @@ cairo_arc_negative (cairo_t *cr, _cairo_arc_path_negative (cr, xc, yc, radius, angle1, angle2); - - CAIRO_CHECK_SANITY (cr); } /* XXX: NYI @@ -1014,17 +1186,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_set_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_set_error (cr, cr->status); } void @@ -1032,17 +1205,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_set_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_set_error (cr, cr->status); } slim_hidden_def(cairo_rel_line_to); @@ -1056,9 +1230,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_set_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); @@ -1077,8 +1252,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_set_error (cr, cr->status); } void @@ -1086,16 +1261,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_set_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 @@ -1106,19 +1281,22 @@ cairo_stroke_to_path (cairo_t *cr) return; cr->status = _cairo_gstate_stroke_path (cr->gstate); + if (cr->status) + _cairo_set_error (cr, cr->status); } */ void cairo_close_path (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_error (cr, cr->status); return; + } cr->status = _cairo_path_fixed_close_path (&cr->path); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } slim_hidden_def(cairo_close_path); @@ -1132,13 +1310,14 @@ slim_hidden_def(cairo_close_path); void cairo_paint (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_paint (cr->gstate); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -1158,22 +1337,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_set_error (cr, cr->status); return; - - if (alpha == 1.0) { - cr->status = _cairo_gstate_paint (cr->gstate); - } else { - _cairo_color_init_rgba (&color, 1., 1., 1., alpha); - _cairo_pattern_init_solid (&pattern.solid, &color); - - cr->status = _cairo_gstate_mask (cr->gstate, &pattern.base); - - _cairo_pattern_fini (&pattern.base); } - CAIRO_CHECK_SANITY (cr); + 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_set_error (cr, cr->status); + + _cairo_pattern_fini (&pattern.base); } /** @@ -1190,13 +1371,24 @@ void cairo_mask (cairo_t *cr, cairo_pattern_t *pattern) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_error (cr, cr->status); return; + } + + if (pattern == NULL) { + _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER); + return; + } + + if (pattern->status) { + _cairo_set_error (cr, pattern->status); + return; + } cr->status = _cairo_gstate_mask (cr->gstate, pattern); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -1220,16 +1412,13 @@ cairo_mask_surface (cairo_t *cr, cairo_pattern_t *pattern; cairo_matrix_t matrix; - CAIRO_CHECK_SANITY (cr); - if (cr->status) - return; - - pattern = cairo_pattern_create_for_surface (surface); - if (!pattern) { - cr->status = CAIRO_STATUS_NO_MEMORY; + if (cr->status) { + _cairo_set_error (cr, cr->status); return; } + pattern = cairo_pattern_create_for_surface (surface); + cairo_matrix_init_translate (&matrix, - surface_x, - surface_y); cairo_pattern_set_matrix (pattern, &matrix); @@ -1273,13 +1462,14 @@ cairo_stroke (cairo_t *cr) void cairo_stroke_preserve (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_stroke (cr->gstate, &cr->path); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } slim_hidden_def(cairo_stroke_preserve); @@ -1288,8 +1478,9 @@ slim_hidden_def(cairo_stroke_preserve); * @cr: a cairo context * * A drawing operator that fills the current path according to the - * current fill rule. After cairo_fill, the current path will be - * cleared from the cairo context. See cairo_set_fill_rule() and + * current fill rule, (each sub-path is implicitly closed before being + * filled). After cairo_fill, the current path will be cleared from + * the cairo context. See cairo_set_fill_rule() and * cairo_fill_preserve(). **/ void @@ -1305,44 +1496,50 @@ cairo_fill (cairo_t *cr) * @cr: a cairo context * * A drawing operator that fills the current path according to the - * current fill rule. Unlike cairo_fill(), cairo_fill_preserve - * preserves the path within the cairo context. + * current fill rule, (each sub-path is implicitly closed before being + * filled). Unlike cairo_fill(), cairo_fill_preserve preserves the + * path within the cairo context. * * See cairo_set_fill_rule() and cairo_fill(). **/ void cairo_fill_preserve (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_fill (cr->gstate, &cr->path); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_copy_page (cr->gstate); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } void cairo_show_page (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_show_page (cr->gstate); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } cairo_bool_t @@ -1350,39 +1547,39 @@ cairo_in_stroke (cairo_t *cr, double x, double y) { int inside; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_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_set_error (cr, cr->status); return 0; + } return inside; } -int +cairo_bool_t cairo_in_fill (cairo_t *cr, double x, double y) { int inside; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_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_set_error (cr, cr->status); return 0; + } return inside; } @@ -1391,28 +1588,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_set_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_set_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_set_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_set_error (cr, cr->status); } /** @@ -1432,7 +1633,7 @@ cairo_fill_extents (cairo_t *cr, * * Calling cairo_clip() can only make the clip region smaller, never * larger. But the current clip is part of the graphics state, so a - * tempoarary restriction of the clip region can be achieved by + * temporary restriction of the clip region can be achieved by * calling cairo_clip() within a cairo_save()/cairo_restore() * pair. The only other means of increasing the size of the clip * region is cairo_reset_clip(). @@ -1462,7 +1663,7 @@ cairo_clip (cairo_t *cr) * * Calling cairo_clip() can only make the clip region smaller, never * larger. But the current clip is part of the graphics state, so a - * tempoarary restriction of the clip region can be achieved by + * temporary restriction of the clip region can be achieved by * calling cairo_clip() within a cairo_save()/cairo_restore() * pair. The only other means of increasing the size of the clip * region is cairo_reset_clip(). @@ -1470,12 +1671,14 @@ cairo_clip (cairo_t *cr) void cairo_clip_preserve (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_clip (cr->gstate, &cr->path); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } slim_hidden_def(cairo_clip_preserve); @@ -1498,12 +1701,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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_reset_clip (cr->gstate); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -1519,7 +1724,7 @@ cairo_reset_clip (cairo_t *cr) * for operations such as listing all available fonts on the system, * and it is expected that most applications will need to use a more * comprehensive font handling and text layout library in addition to - * Cairo. + * cairo. **/ void cairo_select_font_face (cairo_t *cr, @@ -1527,12 +1732,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_set_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_set_error (cr, cr->status); } /** @@ -1544,19 +1751,24 @@ 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) - return NULL; + if (cr->status) { + _cairo_set_error (cr, cr->status); + return (cairo_font_face_t*) &_cairo_font_face_nil; + } cr->status = _cairo_gstate_get_font_face (cr->gstate, &font_face); - CAIRO_CHECK_SANITY (cr); + if (cr->status) { + _cairo_set_error (cr, cr->status); + return (cairo_font_face_t*) &_cairo_font_face_nil; + } + return font_face; } @@ -1572,12 +1784,14 @@ void cairo_font_extents (cairo_t *cr, cairo_font_extents_t *extents) { - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_get_font_extents (cr->gstate, extents); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -1593,12 +1807,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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_font_face (cr->gstate, font_face); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -1615,12 +1831,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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_font_size (cr->gstate, size); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -1640,12 +1858,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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_set_font_matrix (cr->gstate, matrix); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } /** @@ -1659,10 +1879,52 @@ 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); } +/** + * cairo_set_font_options: + * @cr: a #cairo_t + * @options: font options to use + * + * Sets a set of custom font rendering options for the #cairo_t. + * Rendering options are derived by merging these options with the + * options derived from underlying surface; if the value in @options + * has a default value (like %CAIRO_ANTIALIAS_DEFAULT), then the value + * from the surface is used. + **/ +void +cairo_set_font_options (cairo_t *cr, + const cairo_font_options_t *options) +{ + if (cr->status) { + _cairo_set_error (cr, cr->status); + return; + } + + cr->status = _cairo_gstate_set_font_options (cr->gstate, options); + if (cr->status) + _cairo_set_error (cr, cr->status); +} + +/** + * cairo_get_font_options: + * @cr: a #cairo_t + * @options: a #cairo_font_options_t object into which to store + * the retrieved options. All existing values are overwritten + * + * Retrieves font rendering options set via #cairo_set_font_options. + * Note that the returned options do not include any options derived + * from the underlying surface; they are literally the options + * passed to cairo_set_font_options(). + **/ +void +cairo_get_font_options (cairo_t *cr, + cairo_font_options_t *options) +{ + _cairo_gstate_get_font_options (cr->gstate, options); +} + /** * cairo_text_extents: * @cr: a #cairo_t @@ -1692,9 +1954,10 @@ cairo_text_extents (cairo_t *cr, int num_glyphs; double x, y; - CAIRO_CHECK_SANITY (cr); - if (cr->status) + if (cr->status) { + _cairo_set_error (cr, cr->status); return; + } if (utf8 == NULL) { extents->x_bearing = 0.0; @@ -1711,19 +1974,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_set_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_set_error (cr, cr->status); } /** @@ -1750,13 +2014,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_set_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_set_error (cr, cr->status); } void @@ -1766,9 +2032,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_set_error (cr, cr->status); return; + } if (utf8 == NULL) return; @@ -1778,30 +2045,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_set_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_set_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_set_error (cr, cr->status); return; + } cr->status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, num_glyphs); - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_error (cr, cr->status); } void @@ -1811,44 +2082,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_set_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_set_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_set_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_set_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_set_error (cr, cr->status); } /** @@ -1862,7 +2137,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); } @@ -1877,10 +2151,23 @@ cairo_get_operator (cairo_t *cr) double cairo_get_tolerance (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); return _cairo_gstate_get_tolerance (cr->gstate); } +/** + * cairo_get_antialias: + * @cr: a cairo context + * + * Gets the current shape antialiasing mode, as set by cairo_set_shape_antialias(). + * + * Return value: the current shape antialiasing mode. + **/ +cairo_antialias_t +cairo_get_antialias (cairo_t *cr) +{ + return _cairo_gstate_get_antialias (cr->gstate); +} + /** * cairo_get_current_point: * @cr: a cairo context @@ -1909,8 +2196,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; @@ -1925,8 +2210,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); @@ -1941,7 +2224,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); } @@ -1956,7 +2238,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); } @@ -1971,7 +2252,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); } @@ -1986,7 +2266,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); } @@ -2001,7 +2280,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); } @@ -2015,7 +2293,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); } @@ -2026,16 +2303,19 @@ cairo_get_matrix (cairo_t *cr, cairo_matrix_t *matrix) * Gets the target surface for the cairo context as passed to * cairo_create(). * - * Return value: the target surface, (or NULL if @cr is in an error - * state). This object is owned by cairo. To keep a reference to it, - * you must call cairo_pattern_reference(). + * Return value: the target surface. This object is owned by cairo. To + * keep a reference to it, you must call cairo_surface_reference(). + * + * This function will always return a valid pointer, but the result + * can be a "nil" surface if @cr is already in an error state, + * (ie. cairo_status(cr) != CAIRO_STATUS_SUCCESS). A nil surface is + * indicated by cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS. **/ cairo_surface_t * cairo_get_target (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); if (cr->status) - return NULL; + return (cairo_surface_t*) &_cairo_surface_nil; return _cairo_gstate_get_target (cr->gstate); } @@ -2051,13 +2331,23 @@ 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. + * + * 2) If @cr is already in an error state. + * + * In either case, path->status will be set to CAIRO_STATUS_NO_MEMORY, + * (regardless of what the error status in @cr might have been). **/ cairo_path_t * cairo_copy_path (cairo_t *cr) { - CAIRO_CHECK_SANITY (cr); if (cr->status) - return &_cairo_path_nil; + return (cairo_path_t*) &_cairo_path_nil; return _cairo_path_data_create (&cr->path, cr->gstate); } @@ -2080,15 +2370,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_t*) &_cairo_path_nil; + else + return _cairo_path_data_create_flat (&cr->path, cr->gstate); } /** @@ -2096,43 +2396,55 @@ 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) - return; - - if (path == NULL || path->data == NULL) { - cr->status = CAIRO_STATUS_NULL_POINTER; + if (cr->status) { + _cairo_set_error (cr, cr->status); return; } - if (path == &_cairo_path_nil) { - cr->status = CAIRO_STATUS_NO_MEMORY; + if (path == NULL) { + _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER); + return; + } + + if (path->status) { + if (path->status <= CAIRO_STATUS_LAST_STATUS) + _cairo_set_error (cr, path->status); + else + _cairo_set_error (cr, CAIRO_STATUS_INVALID_STATUS); + return; + } + + if (path->data == NULL) { + _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER); return; } cr->status = _cairo_path_data_append_to_context (path, cr); - - CAIRO_CHECK_SANITY (cr); + if (cr->status) + _cairo_set_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: @@ -2145,8 +2457,8 @@ cairo_status_string (cairo_t *cr) return "no current point defined"; case CAIRO_STATUS_INVALID_MATRIX: return "invalid matrix (not invertible)"; - case CAIRO_STATUS_NO_TARGET_SURFACE: - return "no target surface has been set"; + case CAIRO_STATUS_INVALID_STATUS: + return "invalid value for an input cairo_status_t"; case CAIRO_STATUS_NULL_POINTER: return "NULL pointer"; case CAIRO_STATUS_INVALID_STRING: @@ -2161,8 +2473,16 @@ 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"; + case CAIRO_STATUS_INVALID_CONTENT: + return "invalid value for an input cairo_content_t"; + case CAIRO_STATUS_INVALID_FORMAT: + return "invalid value for an input cairo_format_t"; + case CAIRO_STATUS_INVALID_VISUAL: + return "invalid value for an input Visual*"; + case CAIRO_STATUS_FILE_NOT_FOUND: + return "file not found"; } return ""; diff --git a/gfx/cairo/cairo/src/cairo.h b/gfx/cairo/cairo/src/cairo.h index 88db529ecf88..06a6d6a085cc 100644 --- a/gfx/cairo/cairo/src/cairo.h +++ b/gfx/cairo/cairo/src/cairo.h @@ -38,18 +38,26 @@ #ifndef CAIRO_H #define CAIRO_H -#ifdef __cplusplus -# define CAIRO_BEGIN_DECLS extern "C" { -# define CAIRO_END_DECLS } -#else -# define CAIRO_BEGIN_DECLS -# define CAIRO_END_DECLS -#endif - #include CAIRO_BEGIN_DECLS +#define CAIRO_VERSION_ENCODE(major, minor, micro) ( \ + ((major) * 10000) \ + + ((minor) * 100) \ + + ((micro) * 1)) + +#define CAIRO_VERSION CAIRO_VERSION_ENCODE( \ + CAIRO_VERSION_MAJOR, \ + CAIRO_VERSION_MINOR, \ + CAIRO_VERSION_MICRO) + +int +cairo_version (void); + +const char* +cairo_version_string (void); + /** * cairo_bool_t: * @@ -90,9 +98,20 @@ typedef struct _cairo_surface cairo_surface_t; /** * cairo_matrix_t: + * @xx: xx component of the affine transformation + * @yx: yx component of the affine transformation + * @xy: xy component of the affine transformation + * @yy: yy component of the affine transformation + * @x0: X translation component of the affine transformation + * @y0: Y translation component of the affine transformation * * A #cairo_matrix_t holds an affine transformation, such as a scale, - * rotation, or shear, or a combination of those. + * rotation, or shear, or a combination of those. The transformation is given + * by: + * + * x_new = xx * x + xy * y + x0; + * y_new = yx * x + yy * y + y0; + * **/ typedef struct _cairo_matrix { double xx; double yx; @@ -103,7 +122,8 @@ typedef struct _cairo_matrix { typedef struct _cairo_pattern cairo_pattern_t; /** - * cairo_destroy_func_t + * cairo_destroy_func_t: + * @data: The data element being destroyed. * * #cairo_destroy_func_t the type of function which is called when a * data element is destroyed. It is passed the pointer to the data @@ -112,7 +132,8 @@ typedef struct _cairo_pattern cairo_pattern_t; typedef void (*cairo_destroy_func_t) (void *data); /** - * cairo_user_data_key_t + * cairo_user_data_key_t: + * @unused: not used; ignore. * * #cairo_user_data_key_t is used for attaching user data to cairo * data structures. The actual contents of the struct is never used, @@ -127,37 +148,38 @@ typedef struct _cairo_user_data_key { /** * cairo_status_t * @CAIRO_STATUS_SUCCESS: no error has occurred - * @CAIRO_STATUS_NO_MEMORY: - * @CAIRO_STATUS_INVALID_RESTORE: - * @CAIRO_STATUS_INVALID_POP_GROUP: - * @CAIRO_STATUS_INVALID_MATRIX: - * @CAIRO_STATUS_NO_TARGET_SURFACE: - * @CAIRO_STATUS_NULL_POINTER: - * @CAIRO_STATUS_INVALID_STRING: - * @CAIRO_STATUS_INVALID_PATH_DATA: - * @CAIRO_STATUS_READ_ERROR: - * @CAIRO_STATUS_WRITE_ERROR: - * @CAIRO_STATUS_SURFACE_FINISHED: - * @CAIRO_STATUS_SURFACE_TYPE_MISMATCH: - * @CAIRO_STATUS_BAD_NESTING: the same surface was used as the - * target surface for two different cairo contexts at once, - * and more drawing was done on the first context before the - * surface was unset as the target for the second context. - * See the documentation for cairo_create(). + * @CAIRO_STATUS_NO_MEMORY: out of memory + * @CAIRO_STATUS_INVALID_RESTORE: cairo_restore without matching cairo_save + * @CAIRO_STATUS_INVALID_POP_GROUP: no saved group to pop + * @CAIRO_STATUS_NO_CURRENT_POINT: no current point defined + * @CAIRO_STATUS_INVALID_MATRIX: invalid matrix (not invertible) + * @CAIRO_STATUS_INVALID_STATUS: invalid value for an input cairo_status_t + * @CAIRO_STATUS_NULL_POINTER: NULL pointer + * @CAIRO_STATUS_INVALID_STRING: input string not valid UTF-8 + * @CAIRO_STATUS_INVALID_PATH_DATA: input path data not valid + * @CAIRO_STATUS_READ_ERROR: error while reading from input stream + * @CAIRO_STATUS_WRITE_ERROR: error while writing to output stream + * @CAIRO_STATUS_SURFACE_FINISHED: target surface has been finished + * @CAIRO_STATUS_SURFACE_TYPE_MISMATCH: the surface type is not appropriate for the operation + * @CAIRO_STATUS_PATTERN_TYPE_MISMATCH: the pattern type is not appropriate for the operation + * @CAIRO_STATUS_INVALID_CONTENT: invalid value for an input cairo_content_t + * @CAIRO_STATUS_INVALID_FORMAT: invalid value for an input cairo_format_t + * @CAIRO_STATUS_INVALID_VISUAL: invalid value for an input Visual* + * @CAIRO_STATUS_FILE_NOT_FOUND: file not found * * #cairo_status_t is used to indicate errors that can occur when * using Cairo. In some cases it is returned directly by functions. * but when using #cairo_t, the last error, if any, is stored in * the context and can be retrieved with cairo_status(). **/ -typedef enum cairo_status { +typedef enum _cairo_status { CAIRO_STATUS_SUCCESS = 0, CAIRO_STATUS_NO_MEMORY, CAIRO_STATUS_INVALID_RESTORE, CAIRO_STATUS_INVALID_POP_GROUP, CAIRO_STATUS_NO_CURRENT_POINT, CAIRO_STATUS_INVALID_MATRIX, - CAIRO_STATUS_NO_TARGET_SURFACE, + CAIRO_STATUS_INVALID_STATUS, CAIRO_STATUS_NULL_POINTER, CAIRO_STATUS_INVALID_STRING, CAIRO_STATUS_INVALID_PATH_DATA, @@ -165,11 +187,18 @@ 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_INVALID_CONTENT, + CAIRO_STATUS_INVALID_FORMAT, + CAIRO_STATUS_INVALID_VISUAL, + CAIRO_STATUS_FILE_NOT_FOUND } cairo_status_t; /** - * cairo_write_func_t + * cairo_write_func_t: + * @closure: the output closure + * @data: the buffer containing the data to write + * @length: the amount of data to write * * #cairo_write_func_t is the type of function which is called when a * backend needs to write data to an output stream. It is passed the @@ -178,21 +207,28 @@ typedef enum cairo_status { * data in bytes. The write function should return * CAIRO_STATUS_SUCCESS if all the data was successfully written, * CAIRO_STATUS_WRITE_ERROR otherwise. + * + * Returns: the status code of the write operation */ typedef cairo_status_t (*cairo_write_func_t) (void *closure, const unsigned char *data, unsigned int length); /** - * cairo_read_func_t + * cairo_read_func_t: + * @closure: the input closure + * @data: the buffer into which to read the data + * @length: the amount of data to read * * #cairo_read_func_t is the type of function which is called when a * backend needs to read data from an intput stream. It is passed the * closure which was specified by the user at the time the read * function was registered, the buffer to read the data into and the * length of the data in bytes. The read function should return - * CAIRO_STATUS_SUCCESS if all the data was successfully written, + * CAIRO_STATUS_SUCCESS if all the data was successfully read, * CAIRO_STATUS_READ_ERROR otherwise. + * + * Returns: the status code of the read operation */ typedef cairo_status_t (*cairo_read_func_t) (void *closure, unsigned char *data, @@ -202,7 +238,7 @@ typedef cairo_status_t (*cairo_read_func_t) (void *closure, cairo_t * cairo_create (cairo_surface_t *target); -void +cairo_t * cairo_reference (cairo_t *cr); void @@ -224,7 +260,7 @@ cairo_pop_group (cairo_t *cr); /* Modify state */ -typedef enum cairo_operator { +typedef enum _cairo_operator { CAIRO_OPERATOR_CLEAR, CAIRO_OPERATOR_SOURCE, @@ -267,6 +303,29 @@ cairo_set_source_surface (cairo_t *cr, void cairo_set_tolerance (cairo_t *cr, double tolerance); +/** + * cairo_antialias_t: + * @CAIRO_ANTIALIAS_DEFAULT: Use the default antialiasing for + * the subsystem and target device + * @CAIRO_ANTIALIAS_NONE: Use a bilevel alpha mask + * @CAIRO_ANTIALIAS_GRAY: Perform single-color antialiasing (using + * shades of gray for black text on a white background, for example). + * @CAIRO_ANTIALIAS_SUBPIXEL: Perform antialiasing by taking + * advantage of the order of subpixel elements on devices + * such as LCD panels + * + * Specifies the type of antialiasing to do when rendering text or shapes. + **/ +typedef enum _cairo_antialias { + CAIRO_ANTIALIAS_DEFAULT, + CAIRO_ANTIALIAS_NONE, + CAIRO_ANTIALIAS_GRAY, + CAIRO_ANTIALIAS_SUBPIXEL +} cairo_antialias_t; + +void +cairo_set_antialias (cairo_t *cr, cairo_antialias_t antialias); + /** * cairo_fill_rule_t * @CAIRO_FILL_RULE_WINDING: If the path crosses the ray from @@ -288,7 +347,7 @@ cairo_set_tolerance (cairo_t *cr, double tolerance); * (Note that filling is not actually implemented in this way. This * is just a description of the rule that is applied.) **/ -typedef enum cairo_fill_rule { +typedef enum _cairo_fill_rule { CAIRO_FILL_RULE_WINDING, CAIRO_FILL_RULE_EVEN_ODD } cairo_fill_rule_t; @@ -308,7 +367,7 @@ cairo_set_line_width (cairo_t *cr, double width); * * enumeration for style of line-endings **/ -typedef enum cairo_line_cap { +typedef enum _cairo_line_cap { CAIRO_LINE_CAP_BUTT, CAIRO_LINE_CAP_ROUND, CAIRO_LINE_CAP_SQUARE @@ -317,7 +376,7 @@ typedef enum cairo_line_cap { void cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap); -typedef enum cairo_line_join { +typedef enum _cairo_line_join { CAIRO_LINE_JOIN_MITER, CAIRO_LINE_JOIN_ROUND, CAIRO_LINE_JOIN_BEVEL @@ -628,17 +687,138 @@ typedef struct { double max_y_advance; } cairo_font_extents_t; -typedef enum cairo_font_slant { +typedef enum _cairo_font_slant { CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_SLANT_ITALIC, CAIRO_FONT_SLANT_OBLIQUE } cairo_font_slant_t; -typedef enum cairo_font_weight { +typedef enum _cairo_font_weight { CAIRO_FONT_WEIGHT_NORMAL, CAIRO_FONT_WEIGHT_BOLD } cairo_font_weight_t; - + +/** + * cairo_subpixel_order_t: + * @CAIRO_SUBPIXEL_ORDER_DEFAULT: Use the default subpixel order for + * for the target device + * @CAIRO_SUBPIXEL_ORDER_RGB: Subpixel elements are arranged horizontally + * with red at the left + * @CAIRO_SUBPIXEL_ORDER_BGR: Subpixel elements are arranged horizontally + * with blue at the left + * @CAIRO_SUBPIXEL_ORDER_VRGB: Subpixel elements are arranged vertically + * with red at the top + * @CAIRO_SUBPIXEL_ORDER_VBGR: Subpixel elements are arranged vertically + * with blue at the top + * + * The subpixel order specifies the order of color elements within + * each pixel on the display device when rendering with an + * antialiasing mode of %CAIRO_ANTIALIAS_SUBPIXEL. + **/ +typedef enum _cairo_subpixel_order { + CAIRO_SUBPIXEL_ORDER_DEFAULT, + CAIRO_SUBPIXEL_ORDER_RGB, + CAIRO_SUBPIXEL_ORDER_BGR, + CAIRO_SUBPIXEL_ORDER_VRGB, + CAIRO_SUBPIXEL_ORDER_VBGR +} cairo_subpixel_order_t; + +/** + * cairo_hint_style_t: + * @CAIRO_HINT_STYLE_DEFAULT: Use the default hint style for + * for font backend and target device + * @CAIRO_HINT_STYLE_NONE: Do not hint outlines + * @CAIRO_HINT_STYLE_SLIGHT: Hint outlines slightly to improve + * contrast while retaining good fidelity to the original + * shapes. + * @CAIRO_HINT_STYLE_MEDIUM: Hint outlines with medium strength + * giving a compromise between fidelity to the original shapes + * and contrast + * @CAIRO_HINT_STYLE_FULL: Hint outlines to maximize contrast + * + * Specifies the type of hinting to do on font outlines. Hinting + * is the process of fitting outlines to the pixel grid in order + * to improve the appearance of the result. Since hinting outlines + * involves distorting them, it also reduces the faithfulness + * to the original outline shapes. Not all of the outline hinting + * styles are supported by all font backends. + */ +typedef enum _cairo_hint_style { + CAIRO_HINT_STYLE_DEFAULT, + CAIRO_HINT_STYLE_NONE, + CAIRO_HINT_STYLE_SLIGHT, + CAIRO_HINT_STYLE_MEDIUM, + CAIRO_HINT_STYLE_FULL +} cairo_hint_style_t; + +/** + * cairo_hint_metrics_t: + * @CAIRO_HINT_METRICS_DEFAULT: Hint metrics in the default + * manner for the font backend and target device + * @CAIRO_HINT_METRICS_OFF: Do not hint font metrics + * @CAIRO_HINT_METRICS_ON: Hint font metrics + * + * Specifies whether to hint font metrics; hinting font metrics + * means quantizing them so that they are integer values in + * device space. Doing this improves the consistency of + * letter and line spacing, however it also means that text + * will be laid out differently at different zoom factors. + */ +typedef enum _cairo_hint_metrics { + CAIRO_HINT_METRICS_DEFAULT, + CAIRO_HINT_METRICS_OFF, + CAIRO_HINT_METRICS_ON +} cairo_hint_metrics_t; + +typedef struct _cairo_font_options cairo_font_options_t; + +cairo_font_options_t * +cairo_font_options_create (void); + +cairo_font_options_t * +cairo_font_options_copy (const cairo_font_options_t *original); + +void +cairo_font_options_destroy (cairo_font_options_t *options); + +cairo_status_t +cairo_font_options_status (cairo_font_options_t *options); + +void +cairo_font_options_merge (cairo_font_options_t *options, + const cairo_font_options_t *other); +cairo_bool_t +cairo_font_options_equal (const cairo_font_options_t *options, + const cairo_font_options_t *other); + +unsigned long +cairo_font_options_hash (const cairo_font_options_t *options); + +void +cairo_font_options_set_antialias (cairo_font_options_t *options, + cairo_antialias_t antialias); +cairo_antialias_t +cairo_font_options_get_antialias (const cairo_font_options_t *options); + +void +cairo_font_options_set_subpixel_order (cairo_font_options_t *options, + cairo_subpixel_order_t subpixel_order); +cairo_subpixel_order_t +cairo_font_options_get_subpixel_order (const cairo_font_options_t *options); + +void +cairo_font_options_set_hint_style (cairo_font_options_t *options, + cairo_hint_style_t hint_style); +cairo_hint_style_t +cairo_font_options_get_hint_style (const cairo_font_options_t *options); + +void +cairo_font_options_set_hint_metrics (cairo_font_options_t *options, + cairo_hint_metrics_t hint_metrics); +cairo_hint_metrics_t +cairo_font_options_get_hint_metrics (const cairo_font_options_t *options); + + /* This interface is for dealing with text as text, not caring about the font object inside the the cairo_t. */ @@ -659,6 +839,14 @@ void cairo_get_font_matrix (cairo_t *cr, cairo_matrix_t *matrix); +void +cairo_set_font_options (cairo_t *cr, + const cairo_font_options_t *options); + +void +cairo_get_font_options (cairo_t *cr, + cairo_font_options_t *options); + void cairo_show_text (cairo_t *cr, const char *utf8); @@ -694,12 +882,15 @@ cairo_glyph_path (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs); /* Generic identifier for a font style */ -void +cairo_font_face_t * cairo_font_face_reference (cairo_font_face_t *font_face); void cairo_font_face_destroy (cairo_font_face_t *font_face); +cairo_status_t +cairo_font_face_status (cairo_font_face_t *font_face); + void * cairo_font_face_get_user_data (cairo_font_face_t *font_face, const cairo_user_data_key_t *key); @@ -713,17 +904,21 @@ cairo_font_face_set_user_data (cairo_font_face_t *font_face, /* Portable interface to general font features. */ cairo_scaled_font_t * -cairo_scaled_font_create (cairo_font_face_t *font_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm); +cairo_scaled_font_create (cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options); -void +cairo_scaled_font_t * cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font); void cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font); cairo_status_t +cairo_scaled_font_status (cairo_scaled_font_t *scaled_font); + +void cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font, cairo_font_extents_t *extents); @@ -744,6 +939,9 @@ cairo_get_source (cairo_t *cr); double cairo_get_tolerance (cairo_t *cr); +cairo_antialias_t +cairo_get_antialias (cairo_t *cr); + void cairo_get_current_point (cairo_t *cr, double *x, double *y); @@ -767,8 +965,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 +1026,16 @@ cairo_get_target (cairo_t *cr); * cairo_path_destroy (path); * */ +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 { @@ -847,6 +1045,9 @@ typedef union { /** * cairo_path_t: + * @status: the current error status + * @data: the elements in the path + * @num_data: the number of elements in the data array * * A data structure for holding a path. This data structure serves as * the return value for cairo_copy_path_data() and @@ -862,6 +1063,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,57 +1087,55 @@ 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 */ /** - * cairo_format_t - * @CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with - * alpha in the upper 8 bits, then red, then green, then blue. - * The 32-bit quantities are stored native-endian. Pre-multiplied - * alpha is used. (That is, 50% transparent red is 0x80800000, - * not 0x80ff0000.) - * @CAIRO_FORMAT_RGB24: each pixel is a 32-bit quantity, with - * the upper 8 bits unused. Red, Green, and Blue are stored - * in the remaining 24 bits in that order. - * @CAIRO_FORMAT_A8: each pixel is a 8-bit quantity holding - * an alpha value. - * @CAIRO_FORMAT_A1: each pixel is a 1-bit quantity holding - * an alpha value. Pixels are packed together into 32-bit - * quantities. The ordering of the bits matches the - * endianess of the platform. On a big-endian machine, the - * first pixel is in the uppermost bit, on a little-endian - * machine the first pixel is in the least-significant bit. + * cairo_content_t + * @CAIRO_CONTENT_COLOR: The surface will hold color content only. + * @CAIRO_CONTENT_ALPHA: The surface will hold alpha content only. + * @CAIRO_CONTENT_COLOR_ALPHA: The surface will hold color and alpha content. * - * #cairo_format_t is used to identify the memory format of - * image data. + * @cairo_content_t is used to describe the content that a surface will + * contain, whether color information, alpha information (translucence + * vs. opacity), or both. + * + * Note: The large values here are designed to keep cairo_content_t + * values distinct from cairo_format_t values so that the + * implementation can detect the error if users confuse the two types. */ -typedef enum cairo_format { - CAIRO_FORMAT_ARGB32, - CAIRO_FORMAT_RGB24, - CAIRO_FORMAT_A8, - CAIRO_FORMAT_A1 -} cairo_format_t; +typedef enum _cairo_content { + CAIRO_CONTENT_COLOR = 0x1000, + CAIRO_CONTENT_ALPHA = 0x2000, + CAIRO_CONTENT_COLOR_ALPHA = 0x3000 +} cairo_content_t; + +#define CAIRO_CONTENT_VALID(content) ((content) && \ + (((content) & ~(CAIRO_CONTENT_COLOR | \ + CAIRO_CONTENT_ALPHA | \ + CAIRO_CONTENT_COLOR_ALPHA))\ + == 0)) -/* XXX: I want to remove this function, (replace with - cairo_begin_group and friends). */ cairo_surface_t * -cairo_surface_create_similar (cairo_surface_t *other, - cairo_format_t format, +cairo_surface_create_similar (cairo_surface_t *other, + cairo_content_t content, int width, int height); -void +cairo_surface_t * cairo_surface_reference (cairo_surface_t *surface); void cairo_surface_destroy (cairo_surface_t *surface); cairo_status_t +cairo_surface_status (cairo_surface_t *surface); + +void cairo_surface_finish (cairo_surface_t *surface); -#ifdef CAIRO_HAS_PNG_FUNCTIONS +#if CAIRO_HAS_PNG_FUNCTIONS cairo_status_t cairo_surface_write_to_png (cairo_surface_t *surface, @@ -958,6 +1158,23 @@ cairo_surface_set_user_data (cairo_surface_t *surface, void *user_data, cairo_destroy_func_t destroy); +void +cairo_surface_get_font_options (cairo_surface_t *surface, + cairo_font_options_t *options); + +void +cairo_surface_flush (cairo_surface_t *surface); + +void +cairo_surface_mark_dirty (cairo_surface_t *surface); + +void +cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, + int x, + int y, + int width, + int height); + void cairo_surface_set_device_offset (cairo_surface_t *surface, double x_offset, @@ -965,6 +1182,38 @@ cairo_surface_set_device_offset (cairo_surface_t *surface, /* Image-surface functions */ +/** + * cairo_format_t + * @CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with + * alpha in the upper 8 bits, then red, then green, then blue. + * The 32-bit quantities are stored native-endian. Pre-multiplied + * alpha is used. (That is, 50% transparent red is 0x80800000, + * not 0x80ff0000.) + * @CAIRO_FORMAT_RGB24: each pixel is a 32-bit quantity, with + * the upper 8 bits unused. Red, Green, and Blue are stored + * in the remaining 24 bits in that order. + * @CAIRO_FORMAT_A8: each pixel is a 8-bit quantity holding + * an alpha value. + * @CAIRO_FORMAT_A1: each pixel is a 1-bit quantity holding + * an alpha value. Pixels are packed together into 32-bit + * quantities. The ordering of the bits matches the + * endianess of the platform. On a big-endian machine, the + * first pixel is in the uppermost bit, on a little-endian + * machine the first pixel is in the least-significant bit. + * + * #cairo_format_t is used to identify the memory format of + * image data. + */ +typedef enum _cairo_format { + CAIRO_FORMAT_ARGB32, + CAIRO_FORMAT_RGB24, + CAIRO_FORMAT_A8, + CAIRO_FORMAT_A1 +} cairo_format_t; + +#define CAIRO_FORMAT_VALID(format) ((format) >= CAIRO_FORMAT_ARGB32 && \ + (format) <= CAIRO_FORMAT_A1) + cairo_surface_t * cairo_image_surface_create (cairo_format_t format, int width, @@ -983,7 +1232,7 @@ cairo_image_surface_get_width (cairo_surface_t *surface); int cairo_image_surface_get_height (cairo_surface_t *surface); -#ifdef CAIRO_HAS_PNG_FUNCTIONS +#if CAIRO_HAS_PNG_FUNCTIONS cairo_surface_t * cairo_image_surface_create_from_png (const char *filename); @@ -995,6 +1244,14 @@ cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, #endif /* Pattern creation functions */ + +cairo_pattern_t * +cairo_pattern_create_rgb (double red, double green, double blue); + +cairo_pattern_t * +cairo_pattern_create_rgba (double red, double green, double blue, + double alpha); + cairo_pattern_t * cairo_pattern_create_for_surface (cairo_surface_t *surface); @@ -1006,44 +1263,47 @@ cairo_pattern_t * cairo_pattern_create_radial (double cx0, double cy0, double radius0, double cx1, double cy1, double radius1); -void +cairo_pattern_t * cairo_pattern_reference (cairo_pattern_t *pattern); 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); -typedef enum { +typedef enum _cairo_extend { CAIRO_EXTEND_NONE, CAIRO_EXTEND_REPEAT, 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 cairo_pattern_get_extend (cairo_pattern_t *pattern); -typedef enum { +typedef enum _cairo_filter { CAIRO_FILTER_FAST, CAIRO_FILTER_GOOD, CAIRO_FILTER_BEST, @@ -1052,7 +1312,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 +1399,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 +1447,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/gfx/cairo/cairo/src/cairoint.h b/gfx/cairo/cairo/src/cairoint.h index 215be0248089..11a6781c6b6a 100644 --- a/gfx/cairo/cairo/src/cairoint.h +++ b/gfx/cairo/cairo/src/cairoint.h @@ -36,7 +36,7 @@ */ /* - * These definitions are solely for use by the implementation of Cairo + * These definitions are solely for use by the implementation of cairo * and constitute no kind of standard. If you need any of these * functions, please drop me a note. Either the library needs new * functionality, or there's a way to do what you need using the @@ -46,27 +46,24 @@ #ifndef _CAIROINT_H_ #define _CAIROINT_H_ -#define _USE_MATH_DEFINES - #if HAVE_CONFIG_H #include "config.h" #endif -#include - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#include #include #include #include #include +#ifdef _MSC_VER +#define _USE_MATH_DEFINES +#endif +#include +#include #include #include "cairo.h" +#include "cairo-debug.h" #include #if __GNUC__ >= 3 && defined(__ELF__) @@ -89,6 +86,13 @@ # define slim_hidden_def(name) #endif +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) +#define CAIRO_PRINTF_FORMAT(fmt_index, va_index) \ + __attribute__((__format__(__printf__, fmt_index, va_index))) +#else +#define CAIRO_PRINTF_FORMAT(fmt_index, va_index) +#endif + /* slim_internal.h */ #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) #define cairo_private __attribute__((__visibility__("hidden"))) @@ -120,6 +124,22 @@ #define __attribute__(x) #endif +#if HAVE_PTHREAD_H +# include +# define CAIRO_MUTEX_DECLARE(name) static pthread_mutex_t name = PTHREAD_MUTEX_INITIALIZER +#define CAIRO_MUTEX_DECLARE_GLOBAL(name) pthread_mutex_t name = PTHREAD_MUTEX_INITIALIZER +# define CAIRO_MUTEX_LOCK(name) pthread_mutex_lock (&name) +# define CAIRO_MUTEX_UNLOCK(name) pthread_mutex_unlock (&name) +#endif + +#ifndef CAIRO_MUTEX_DECLARE +/*# warning "No mutex declarations, assuming single-threaded code" */ +# define CAIRO_MUTEX_DECLARE(name) +# define CAIRO_MUTEX_DECLARE_GLOBAL(name) +# define CAIRO_MUTEX_LOCK(name) +# define CAIRO_MUTEX_UNLOCK(name) +#endif + #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) @@ -151,6 +171,10 @@ 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)) + +#include "cairo-hash-private.h" + typedef struct _cairo_point { cairo_fixed_t x; cairo_fixed_t y; @@ -192,17 +216,19 @@ typedef struct _cairo_rectangle { offset */ typedef enum cairo_int_status { CAIRO_INT_STATUS_DEGENERATE = 1000, - CAIRO_INT_STATUS_UNSUPPORTED + CAIRO_INT_STATUS_UNSUPPORTED, + CAIRO_INT_STATUS_NOTHING_TO_DO } cairo_int_status_t; -#define CAIRO_OK(status) ((status) == CAIRO_STATUS_SUCCESS) - typedef enum cairo_direction { CAIRO_DIRECTION_FORWARD, CAIRO_DIRECTION_REVERSE } cairo_direction_t; typedef struct _cairo_path_fixed cairo_path_fixed_t; +typedef enum _cairo_clip_mode cairo_clip_mode_t; +typedef struct _cairo_clip_path cairo_clip_path_t; +typedef struct _cairo_clip cairo_clip_t; typedef struct _cairo_edge { cairo_line_t edge; @@ -252,6 +278,13 @@ typedef struct _cairo_pen { typedef struct _cairo_color cairo_color_t; typedef struct _cairo_image_surface cairo_image_surface_t; +cairo_private void +_cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_t *rectangle); + +cairo_private void +_cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src); + + /* cairo_array.c structures and functions */ typedef struct _cairo_array cairo_array_t; @@ -293,7 +326,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, @@ -360,7 +393,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; @@ -382,10 +414,11 @@ _cairo_cache_init (cairo_cache_t *cache, unsigned long max_memory); cairo_private void -_cairo_cache_reference (cairo_cache_t *cache); +_cairo_cache_destroy (cairo_cache_t *cache); cairo_private void -_cairo_cache_destroy (cairo_cache_t *cache); +_cairo_cache_shrink_to (cairo_cache_t *cache, + unsigned long max_memory); cairo_private cairo_status_t _cairo_cache_lookup (cairo_cache_t *cache, @@ -407,8 +440,6 @@ _cairo_hash_string (const char *c); #define CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT 0x100000 #define CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT 0x100000 -typedef struct _cairo_unscaled_font cairo_unscaled_font_t; - typedef struct _cairo_unscaled_font_backend cairo_unscaled_font_backend_t; typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t; typedef struct _cairo_font_face_backend cairo_font_face_backend_t; @@ -417,22 +448,36 @@ typedef struct _cairo_font_face_backend cairo_font_face_backend_t; * A cairo_unscaled_font_t is just an opaque handle we use in the * glyph cache. */ -struct _cairo_unscaled_font { - int refcount; +typedef struct _cairo_unscaled_font { + cairo_hash_entry_t hash_entry; + int ref_count; const cairo_unscaled_font_backend_t *backend; +} cairo_unscaled_font_t; + +struct _cairo_font_options { + cairo_antialias_t antialias; + cairo_subpixel_order_t subpixel_order; + cairo_hint_style_t hint_style; + cairo_hint_metrics_t hint_metrics; }; struct _cairo_scaled_font { - int refcount; + cairo_hash_entry_t hash_entry; + cairo_status_t status; + int ref_count; + cairo_font_face_t *font_face; /* may be NULL */ cairo_matrix_t font_matrix; /* font space => user space */ cairo_matrix_t ctm; /* user space => device space */ cairo_matrix_t scale; /* font space => device space */ - cairo_font_face_t *font_face; /* may be NULL */ + cairo_font_options_t options; + const cairo_scaled_font_backend_t *backend; }; struct _cairo_font_face { - int refcount; + cairo_hash_entry_t hash_entry; + cairo_status_t status; + int ref_count; cairo_user_data_array_t user_data; const cairo_font_face_backend_t *backend; }; @@ -471,6 +516,18 @@ _cairo_unlock_global_image_glyph_cache (void); cairo_private cairo_cache_t * _cairo_get_global_image_glyph_cache (void); +cairo_private void +_cairo_font_reset_static_data (void); + +cairo_private void +_cairo_ft_font_reset_static_data (void); + +cairo_private void +_cairo_xlib_surface_reset_static_data (void); + +cairo_private void +_cairo_xlib_screen_reset_static_data (void); + /* Some glyph cache functions you can reuse. */ cairo_private unsigned long @@ -489,80 +546,105 @@ struct _cairo_unscaled_font_backend { cairo_image_glyph_cache_entry_t *entry); }; +/* cairo_toy_font_face_t - simple family/slant/weight font faces used for + * the built-in font API + */ + +typedef struct _cairo_toy_font_face { + cairo_font_face_t base; + const char *family; + cairo_bool_t owns_family; + cairo_font_slant_t slant; + cairo_font_weight_t weight; +} cairo_toy_font_face_t; + struct _cairo_scaled_font_backend { - cairo_status_t (*create) (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - cairo_scaled_font_t **font); - - void (*destroy) (void *font); + cairo_status_t + (*create_toy) (cairo_toy_font_face_t *toy_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font); - cairo_status_t (*font_extents) (void *font, - cairo_font_extents_t *extents); + void + (*fini) (void *scaled_font); - cairo_status_t (*text_to_glyphs) (void *font, - const char *utf8, - cairo_glyph_t **glyphs, - int *num_glyphs); + cairo_status_t + (*font_extents) (void *scaled_font, + cairo_font_extents_t *extents); - cairo_status_t (*glyph_extents) (void *font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_text_extents_t *extents); + cairo_status_t + (*text_to_glyphs) (void *scaled_font, + const char *utf8, + cairo_glyph_t **glyphs, + int *num_glyphs); - cairo_status_t (*glyph_bbox) (void *font, - const cairo_glyph_t *glyphs, - int num_glyphs, - cairo_box_t *bbox); + cairo_status_t + (*glyph_extents) (void *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents); + + cairo_status_t + (*glyph_bbox) (void *scaled_font, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_box_t *bbox); + + cairo_status_t + (*show_glyphs) (void *scaled_font, + cairo_operator_t operator, + cairo_pattern_t *pattern, + cairo_surface_t *surface, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, + const cairo_glyph_t *glyphs, + int num_glyphs); - cairo_status_t (*show_glyphs) (void *font, - cairo_operator_t operator, - cairo_pattern_t *pattern, - cairo_surface_t *surface, - int source_x, - int source_y, - int dest_x, - int dest_y, - unsigned int width, - unsigned int height, - const cairo_glyph_t *glyphs, - int num_glyphs); - - cairo_status_t (*glyph_path) (void *font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_path_fixed_t *path); - void (*get_glyph_cache_key) (void *font, - cairo_glyph_cache_key_t *key); + cairo_status_t + (*glyph_path) (void *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_fixed_t *path); + + void + (*get_glyph_cache_key) (void *scaled_font, + cairo_glyph_cache_key_t *key); }; struct _cairo_font_face_backend { /* The destroy() function is allowed to resurrect the font face * by re-referencing. This is needed for the FreeType backend. */ - void (*destroy) (void *font_face); - cairo_status_t (*create_font) (void *font_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - cairo_scaled_font_t **scaled_font); + void + (*destroy) (void *font_face); + + cairo_status_t + (*scaled_font_create) (void *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font); }; /* concrete font backends */ -#ifdef CAIRO_HAS_FT_FONT +#if CAIRO_HAS_FT_FONT extern const cairo_private struct _cairo_scaled_font_backend cairo_ft_scaled_font_backend; #endif -#ifdef CAIRO_HAS_WIN32_FONT +#if CAIRO_HAS_WIN32_FONT extern const cairo_private struct _cairo_scaled_font_backend cairo_win32_scaled_font_backend; #endif -#ifdef CAIRO_HAS_ATSUI_FONT +#if CAIRO_HAS_ATSUI_FONT extern const cairo_private struct _cairo_scaled_font_backend cairo_atsui_scaled_font_backend; @@ -571,8 +653,7 @@ extern const cairo_private struct _cairo_scaled_font_backend cairo_atsui_scaled_ typedef struct _cairo_surface_backend { cairo_surface_t * (*create_similar) (void *surface, - cairo_format_t format, - int drawable, + cairo_content_t content, int width, int height); @@ -635,6 +716,7 @@ typedef struct _cairo_surface_backend { (*composite_trapezoids) (cairo_operator_t operator, cairo_pattern_t *pattern, void *dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, @@ -650,10 +732,44 @@ 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, + cairo_antialias_t antialias); + /* 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}. @@ -691,8 +807,24 @@ 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); + void + (*get_font_options) (void *surface, + cairo_font_options_t *options); + + cairo_status_t + (*flush) (void *surface); + + cairo_status_t + (*mark_dirty_rectangle) (void *surface, + int x, + int y, + int width, + int height); + } cairo_surface_backend_t; typedef struct _cairo_format_masks { @@ -703,26 +835,32 @@ typedef struct _cairo_format_masks { unsigned long blue_mask; } cairo_format_masks_t; -typedef struct _cairo_surface_save cairo_surface_save_t; - struct _cairo_surface { const cairo_surface_backend_t *backend; unsigned int ref_count; + cairo_status_t status; 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 { @@ -731,7 +869,9 @@ struct _cairo_image_surface { /* libic-specific fields */ cairo_format_t format; unsigned char *data; - int owns_data; + cairo_bool_t owns_data; + cairo_bool_t has_clip; + int width; int height; @@ -741,6 +881,8 @@ struct _cairo_image_surface { pixman_image_t *pixman_image; }; +extern const cairo_private cairo_surface_backend_t cairo_image_surface_backend; + /* XXX: Right now, the cairo_color structure puts unpremultiplied color in the doubles and premultiplied color in the shorts. Yes, this is crazy insane, (but at least we don't export this @@ -783,6 +925,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; @@ -793,6 +936,8 @@ typedef struct _cairo_solid_pattern { cairo_color_t color; } cairo_solid_pattern_t; +extern const cairo_private cairo_solid_pattern_t cairo_solid_pattern_nil; + typedef struct _cairo_surface_pattern { cairo_pattern_t base; @@ -844,7 +989,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; @@ -858,20 +1002,24 @@ typedef struct _cairo_traps { #define CAIRO_FONT_SLANT_DEFAULT CAIRO_FONT_SLANT_NORMAL #define CAIRO_FONT_WEIGHT_DEFAULT CAIRO_FONT_WEIGHT_NORMAL -#if defined(CAIRO_HAS_WIN32_FONT) +#define CAIRO_WIN32_FONT_FAMILY_DEFAULT "Arial" +#define CAIRO_ATSUI_FONT_FAMILY_DEFAULT "Monaco" +#define CAIRO_FT_FONT_FAMILY_DEFAULT "" -#define CAIRO_FONT_FAMILY_DEFAULT "Arial" -#define CAIRO_FONT_BACKEND_DEFAULT &cairo_win32_scaled_font_backend +#if CAIRO_HAS_WIN32_FONT -#elif defined(CAIRO_HAS_ATSUI_FONT) +#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_WIN32_FONT_FAMILY_DEFAULT +#define CAIRO_SCALED_FONT_BACKEND_DEFAULT &cairo_win32_scaled_font_backend -#define CAIRO_FONT_FAMILY_DEFAULT "Monaco" -#define CAIRO_FONT_BACKEND_DEFAULT &cairo_atsui_scaled_font_backend +#elif CAIRO_HAS_ATSUI_FONT -#elif defined(CAIRO_HAS_FT_FONT) +#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_ATSUI_FONT_FAMILY_DEFAULT +#define CAIRO_SCALED_FONT_BACKEND_DEFAULT &cairo_atsui_scaled_font_backend -#define CAIRO_FONT_FAMILY_DEFAULT "serif" -#define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_scaled_font_backend +#elif CAIRO_HAS_FT_FONT + +#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_FT_FONT_FAMILY_DEFAULT +#define CAIRO_SCALED_FONT_BACKEND_DEFAULT &cairo_ft_scaled_font_backend #endif @@ -884,13 +1032,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 { @@ -934,25 +1075,12 @@ _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); 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); @@ -965,10 +1093,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); @@ -1127,7 +1251,7 @@ cairo_private cairo_status_t _cairo_gstate_set_font_size (cairo_gstate_t *gstate, double size); -void +cairo_private void _cairo_gstate_get_font_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix); @@ -1135,6 +1259,14 @@ cairo_private cairo_status_t _cairo_gstate_set_font_matrix (cairo_gstate_t *gstate, const cairo_matrix_t *matrix); +cairo_private void +_cairo_gstate_get_font_options (cairo_gstate_t *gstate, + cairo_font_options_t *options); + +cairo_private cairo_status_t +_cairo_gstate_set_font_options (cairo_gstate_t *gstate, + const cairo_font_options_t *options); + cairo_private cairo_status_t _cairo_gstate_get_font_face (cairo_gstate_t *gstate, cairo_font_face_t **font_face); @@ -1172,6 +1304,8 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, int num_glyphs, cairo_path_fixed_t *path); +cairo_private cairo_bool_t +_cairo_operator_bounded (cairo_operator_t operator); /* cairo_color.c */ cairo_private const cairo_color_t * @@ -1213,31 +1347,42 @@ _cairo_color_get_rgba_premultiplied (cairo_color_t *color, /* cairo-font.c */ +cairo_private void +_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font, + cairo_status_t status); + +extern const cairo_private cairo_font_face_t _cairo_font_face_nil; + cairo_private void _cairo_font_face_init (cairo_font_face_t *font_face, const cairo_font_face_backend_t *backend); cairo_private cairo_font_face_t * -_cairo_simple_font_face_create (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight); - -cairo_private void -_cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - const cairo_scaled_font_backend_t *backend); +_cairo_toy_font_face_create (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight); cairo_private void _cairo_unscaled_font_init (cairo_unscaled_font_t *font, const cairo_unscaled_font_backend_t *backend); -cairo_private void +cairo_private cairo_unscaled_font_t * _cairo_unscaled_font_reference (cairo_unscaled_font_t *font); cairo_private void _cairo_unscaled_font_destroy (cairo_unscaled_font_t *font); +cairo_private void +_cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, + cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + const cairo_scaled_font_backend_t *backend); + +void +_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font); + cairo_private cairo_status_t _cairo_scaled_font_font_extents (cairo_scaled_font_t *scaled_font, cairo_font_extents_t *extents); @@ -1280,10 +1425,15 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, int num_glyphs, cairo_path_fixed_t *path); -cairo_private void +cairo_private cairo_status_t _cairo_scaled_font_get_glyph_cache_key (cairo_scaled_font_t *scaled_font, cairo_glyph_cache_key_t *key); +/* cairo-font-options.c */ + +cairo_private void +_cairo_font_options_init_default (cairo_font_options_t *options); + /* cairo_hull.c */ cairo_private cairo_status_t _cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices); @@ -1299,33 +1449,33 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path, cairo_private void _cairo_path_fixed_fini (cairo_path_fixed_t *path); -cairo_status_t +cairo_private cairo_status_t _cairo_path_fixed_move_to (cairo_path_fixed_t *path, cairo_fixed_t x, cairo_fixed_t y); -cairo_status_t +cairo_private cairo_status_t _cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path, cairo_fixed_t dx, cairo_fixed_t dy); -cairo_status_t +cairo_private cairo_status_t _cairo_path_fixed_line_to (cairo_path_fixed_t *path, cairo_fixed_t x, cairo_fixed_t y); -cairo_status_t +cairo_private cairo_status_t _cairo_path_fixed_rel_line_to (cairo_path_fixed_t *path, cairo_fixed_t dx, cairo_fixed_t dy); -cairo_status_t +cairo_private cairo_status_t _cairo_path_fixed_curve_to (cairo_path_fixed_t *path, cairo_fixed_t x0, cairo_fixed_t y0, cairo_fixed_t x1, cairo_fixed_t y1, cairo_fixed_t x2, cairo_fixed_t y2); -cairo_status_t +cairo_private cairo_status_t _cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path, cairo_fixed_t dx0, cairo_fixed_t dy0, cairo_fixed_t dx1, cairo_fixed_t dy1, @@ -1334,7 +1484,7 @@ _cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path, cairo_private cairo_status_t _cairo_path_fixed_close_path (cairo_path_fixed_t *path); -cairo_status_t +cairo_private cairo_status_t _cairo_path_fixed_get_current_point (cairo_path_fixed_t *path, cairo_fixed_t *x, cairo_fixed_t *y); @@ -1373,7 +1523,8 @@ _cairo_path_fixed_bounds (cairo_path_fixed_t *path, /* cairo_path_fill.c */ cairo_private cairo_status_t _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path, - cairo_gstate_t *gstate, + cairo_fill_rule_t fill_rule, + double tolerance, cairo_traps_t *traps); /* cairo_path_stroke.c */ @@ -1382,17 +1533,21 @@ _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 */ + +extern const cairo_private cairo_surface_t _cairo_surface_nil; +extern const cairo_private cairo_surface_t _cairo_surface_nil_read_error; +extern const cairo_private cairo_surface_t _cairo_surface_nil_file_not_found; + cairo_private cairo_surface_t * -_cairo_surface_create_similar_scratch (cairo_surface_t *other, - cairo_format_t format, - int drawable, +_cairo_surface_create_similar_scratch (cairo_surface_t *other, + cairo_content_t content, int width, int height); cairo_private cairo_surface_t * _cairo_surface_create_similar_solid (cairo_surface_t *other, - cairo_format_t format, + cairo_content_t content, int width, int height, const cairo_color_t *color); @@ -1401,23 +1556,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_status_t -_cairo_surface_fill_rectangle (cairo_surface_t *surface, - cairo_operator_t operator, - const cairo_color_t *color, - int x, - int y, - int width, - int height); +cairo_private cairo_clip_mode_t +_cairo_surface_get_clip_mode (cairo_surface_t *surface); cairo_private cairo_status_t _cairo_surface_composite (cairo_operator_t operator, @@ -1433,6 +1573,21 @@ _cairo_surface_composite (cairo_operator_t operator, unsigned int width, unsigned int height); +cairo_private cairo_status_t +_cairo_surface_fill_rectangle (cairo_surface_t *surface, + cairo_operator_t operator, + const cairo_color_t *color, + int x, + int y, + int width, + int height); + +cairo_private cairo_status_t +_cairo_surface_fill_region (cairo_surface_t *surface, + cairo_operator_t operator, + const cairo_color_t *color, + pixman_region16_t *region); + cairo_private cairo_status_t _cairo_surface_fill_rectangles (cairo_surface_t *surface, cairo_operator_t operator, @@ -1441,15 +1596,18 @@ _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, cairo_pattern_t *pattern, cairo_surface_t *dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, @@ -1459,6 +1617,14 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator, cairo_trapezoid_t *traps, int ntraps); +cairo_private cairo_status_t +_cairo_surface_clip_and_composite_trapezoids (cairo_pattern_t *src, + cairo_operator_t operator, + cairo_surface_t *dst, + cairo_traps_t *traps, + cairo_clip_t *clip, + cairo_antialias_t antialias); + cairo_private cairo_status_t _cairo_surface_copy_page (cairo_surface_t *surface); @@ -1494,13 +1660,33 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, cairo_surface_t *src, cairo_surface_t **clone_out); -cairo_private cairo_status_t -_cairo_surface_set_clip_region (cairo_surface_t *surface, - pixman_region16_t *region); +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_get_clip_extents (cairo_surface_t *surface, - cairo_rectangle_t *rectangle); +_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); + +cairo_private cairo_int_status_t +_cairo_surface_intersect_clip_path (cairo_surface_t *surface, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias); + +cairo_private cairo_status_t +_cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip); + +cairo_private cairo_status_t +_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, @@ -1516,9 +1702,48 @@ _cairo_surface_show_glyphs (cairo_scaled_font_t *scaled_font, const cairo_glyph_t *glyphs, int num_glyphs); +cairo_private cairo_status_t +_cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst, + cairo_surface_attributes_t *src_attr, + int src_width, + int src_height, + cairo_surface_attributes_t *mask_attr, + int mask_width, + int mask_height, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height); + +cairo_private cairo_status_t +_cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst, + cairo_surface_attributes_t *src_attr, + int src_width, + int src_height, + int mask_width, + int mask_height, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height); + /* cairo_image_surface.c */ -cairo_private cairo_image_surface_t * +cairo_private cairo_format_t +_cairo_format_from_content (cairo_content_t content); + +cairo_private cairo_content_t +_cairo_content_from_format (cairo_format_t format); + +cairo_private cairo_surface_t * _cairo_image_surface_create_with_masks (unsigned char *data, cairo_format_masks_t *format, int width, @@ -1528,23 +1753,11 @@ _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); -cairo_private int +cairo_private cairo_bool_t _cairo_surface_is_image (cairo_surface_t *surface); /* cairo_pen.c */ @@ -1642,9 +1855,6 @@ cairo_private cairo_status_t _cairo_matrix_compute_scale_factors (const cairo_matrix_t *matrix, double *sx, double *sy, int x_major); -cairo_private cairo_status_t -_cairo_matrix_compute_expansion_factors (const cairo_matrix_t *matrix, double *min, double *max); - cairo_private cairo_bool_t _cairo_matrix_is_integer_translation(const cairo_matrix_t *matrix, int *itx, int *ity); @@ -1660,6 +1870,9 @@ _cairo_traps_init_box (cairo_traps_t *traps, cairo_private void _cairo_traps_fini (cairo_traps_t *traps); +cairo_private void +_cairo_traps_translate (cairo_traps_t *traps, int x, int y); + cairo_private cairo_status_t _cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3]); @@ -1696,8 +1909,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, @@ -1740,7 +1954,7 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern, cairo_surface_attributes_t *attributes); cairo_private void -_cairo_pattern_release_surface (cairo_surface_t *dst, +_cairo_pattern_release_surface (cairo_pattern_t *pattern, cairo_surface_t *surface, cairo_surface_attributes_t *attributes); @@ -1759,6 +1973,21 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src, cairo_surface_attributes_t *src_attributes, cairo_surface_attributes_t *mask_attributes); +cairo_private cairo_status_t +_cairo_gstate_set_antialias (cairo_gstate_t *gstate, + cairo_antialias_t antialias); + +cairo_private cairo_antialias_t +_cairo_gstate_get_antialias (cairo_gstate_t *gstate); + +/* cairo-region.c */ + +cairo_private pixman_region16_t * +_cairo_region_create_from_rectangle (cairo_rectangle_t *rect); + +cairo_private void +_cairo_region_extents_rectangle (pixman_region16_t *region, + cairo_rectangle_t *rect); /* cairo_unicode.c */ @@ -1789,13 +2018,18 @@ cairo_private cairo_status_t _cairo_output_stream_write (cairo_output_stream_t *stream, const void *data, size_t length); +cairo_private void +_cairo_output_stream_write_hex_string (cairo_output_stream_t *stream, + const char *data, + size_t length); + cairo_private cairo_status_t _cairo_output_stream_vprintf (cairo_output_stream_t *stream, const char *fmt, va_list ap); cairo_private cairo_status_t _cairo_output_stream_printf (cairo_output_stream_t *stream, - const char *fmt, ...); + const char *fmt, ...) CAIRO_PRINTF_FORMAT(2, 3); cairo_private long _cairo_output_stream_get_position (cairo_output_stream_t *status); @@ -1803,9 +2037,12 @@ _cairo_output_stream_get_position (cairo_output_stream_t *status); cairo_private cairo_status_t _cairo_output_stream_get_status (cairo_output_stream_t *stream); -cairo_output_stream_t * +cairo_private cairo_output_stream_t * _cairo_output_stream_create_for_file (const char *filename); +cairo_private void +_cairo_error (cairo_status_t status); + /* Avoid unnecessary PLT entries. */ slim_hidden_proto(cairo_get_current_point) diff --git a/gfx/cairo/dash-dos.diff b/gfx/cairo/dash-dos.diff deleted file mode 100644 index 18099d9e1504..000000000000 --- a/gfx/cairo/dash-dos.diff +++ /dev/null @@ -1,252 +0,0 @@ -diff -ru ../../../../../cairo-cvs/dist/cairo-0.5.0/src/cairo-gstate-private.h cairo/src/cairo-gstate-private.h ---- ../../../../../cairo-cvs/dist/cairo-0.5.0/src/cairo-gstate-private.h 2005-05-06 21:55:23.000000000 -0700 -+++ cairo/src/cairo-gstate-private.h 2005-06-01 22:19:22.000000000 -0700 -@@ -52,6 +52,8 @@ - double *dash; - int num_dashes; - double dash_offset; -+ double max_dash_length; -+ double fraction_dash_lit; - - char *font_family; /* NULL means CAIRO_FONT_FAMILY_DEFAULT; */ - cairo_font_slant_t font_slant; -Only in cairo/src: cairo-gstate-private.h~ -diff -ru ../../../../../cairo-cvs/dist/cairo-0.5.0/src/cairo-gstate.c cairo/src/cairo-gstate.c ---- ../../../../../cairo-cvs/dist/cairo-0.5.0/src/cairo-gstate.c 2005-05-12 10:59:01.000000000 -0700 -+++ cairo/src/cairo-gstate.c 2005-06-01 22:15:34.000000000 -0700 -@@ -101,6 +101,8 @@ - gstate->dash = NULL; - gstate->num_dashes = 0; - gstate->dash_offset = 0.0; -+ gstate->max_dash_length = 0.0; -+ gstate->fraction_dash_lit = 0.0; - - gstate->scaled_font = NULL; - gstate->font_face = NULL; -@@ -509,6 +511,9 @@ - cairo_status_t - _cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, double offset) - { -+ double length = 0.0, lit = 0.0; -+ int i; -+ - if (gstate->dash) { - free (gstate->dash); - gstate->dash = NULL; -@@ -521,6 +526,16 @@ - gstate->num_dashes = 0; - return CAIRO_STATUS_NO_MEMORY; - } -+ -+ gstate->max_dash_length = 0.0; -+ for (i = 0; i < num_dashes; i++) { -+ gstate->max_dash_length = MAX(dash[i], gstate->max_dash_length); -+ -+ if (!(i & 1)) -+ lit += dash[i]; -+ length += dash[i]; -+ } -+ gstate->fraction_dash_lit = lit/length; - } - - memcpy (gstate->dash, dash, gstate->num_dashes * sizeof (double)); -@@ -954,11 +969,30 @@ - return status; - } - -+static cairo_bool_t -+_dashes_invisible (cairo_gstate_t *gstate) -+{ -+ if (gstate->dash) { -+ double min, max; -+ -+ _cairo_matrix_compute_expansion_factors (&gstate->ctm, &min, &max); -+ -+ /* Quick and dirty applicaton of Nyquist sampling limit */ -+ -+ if (min * gstate->max_dash_length < 0.5f) -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ - cairo_status_t - _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) - { - cairo_status_t status; - cairo_traps_t traps; -+ double *dash = NULL; -+ double alpha = 0.0; - - if (gstate->surface->level != gstate->surface_level) - return CAIRO_STATUS_BAD_NESTING; -@@ -966,15 +1000,21 @@ - if (gstate->line_width <= 0.0) - return CAIRO_STATUS_SUCCESS; - -+ if (_dashes_invisible(gstate)) { -+ dash = gstate->dash; -+ gstate->dash = NULL; -+ -+ /* alpha = gstate->alpha; */ -+ /* gstate->alpha *= gstate->fraction_dash_lit; */ -+ } -+ - _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate); - - _cairo_traps_init (&traps); - - status = _cairo_path_fixed_stroke_to_traps (path, gstate, &traps); -- if (status) { -- _cairo_traps_fini (&traps); -- return status; -- } -+ if (status) -+ goto BAIL; - - _cairo_gstate_clip_and_composite_trapezoids (gstate, - gstate->source, -@@ -982,9 +1022,15 @@ - gstate->surface, - &traps); - -+BAIL: - _cairo_traps_fini (&traps); - -- return CAIRO_STATUS_SUCCESS; -+ if (dash) { -+ gstate->dash = dash; -+ /* gstate->alpha = alpha; */ -+ } -+ -+ return status; - } - - cairo_status_t -@@ -1514,7 +1560,13 @@ - cairo_status_t status; - cairo_traps_t traps; - cairo_box_t extents; -- -+ double *dash = NULL; -+ -+ if (_dashes_invisible(gstate)) { -+ dash = gstate->dash; -+ gstate->dash = NULL; -+ } -+ - _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate); - - _cairo_traps_init (&traps); -@@ -1535,6 +1587,9 @@ - - BAIL: - _cairo_traps_fini (&traps); -+ -+ if (dash) -+ gstate->dash = dash; - - return status; - } -Only in cairo/src: cairo-gstate.c~ -diff -ru ../../../../../cairo-cvs/dist/cairo-0.5.0/src/cairo-matrix.c cairo/src/cairo-matrix.c ---- ../../../../../cairo-cvs/dist/cairo-0.5.0/src/cairo-matrix.c 2005-05-09 08:50:27.000000000 -0700 -+++ cairo/src/cairo-matrix.c 2005-06-01 22:19:54.000000000 -0700 -@@ -559,6 +559,29 @@ - return CAIRO_STATUS_SUCCESS; - } - -+/* Compute the min/max expansion factors. See the comment in -+ * cairo-pen.c for the derivation */ -+cairo_status_t -+_cairo_matrix_compute_expansion_factors (const cairo_matrix_t *matrix, -+ double *min, double *max) -+{ -+ double a = matrix->xx, b = matrix->yx; -+ double c = matrix->xy, d = matrix->yy; -+ -+ double i = a*a + c*c; -+ double j = b*b + d*d; -+ -+ double f = 0.5 * (i + j); -+ double g = 0.5 * (i - j); -+ double h = a*b + c*d; -+ -+ *max = sqrt (f + sqrt (g*g+h*h)); -+ -+ *min = sqrt (f - sqrt (g*g+h*h)); -+ -+ return CAIRO_STATUS_SUCCESS; -+} -+ - cairo_bool_t - _cairo_matrix_is_integer_translation(const cairo_matrix_t *mat, - int *itx, int *ity) -diff -ru ../../../../../cairo-cvs/dist/cairo-0.5.0/src/cairo-pen.c cairo/src/cairo-pen.c ---- ../../../../../cairo-cvs/dist/cairo-0.5.0/src/cairo-pen.c 2005-05-06 21:55:23.000000000 -0700 -+++ cairo/src/cairo-pen.c 2005-06-01 22:18:51.000000000 -0700 -@@ -374,32 +374,15 @@ - double radius, - cairo_matrix_t *matrix) - { -- double a = matrix->xx, b = matrix->yx; -- double c = matrix->xy, d = matrix->yy; -+ double min, max, major_axis; -+ int num_vertices; - -- double i = a*a + c*c; -- double j = b*b + d*d; -- -- double f = 0.5 * (i + j); -- double g = 0.5 * (i - j); -- double h = a*b + c*d; -- -- /* -- * compute major and minor axes lengths for -- * a pen with the specified radius -- */ -- -- double major_axis = radius * sqrt (f + sqrt (g*g+h*h)); -- -- /* -- * we don't need the minor axis length, which is -- * double min = radius * sqrt (f - sqrt (g*g+h*h)); -- */ -+ _cairo_matrix_compute_expansion_factors (matrix, &min, &max); -+ major_axis = radius * max; - - /* - * compute number of vertices needed - */ -- int num_vertices; - - /* Where tolerance / M is > 1, we use 4 points */ - if (tolerance >= major_axis) { -Only in cairo/src: cairo-pen.c~ -diff -ru ../../../../../cairo-cvs/dist/cairo-0.5.0/src/cairo-wideint.h cairo/src/cairo-wideint.h ---- ../../../../../cairo-cvs/dist/cairo-0.5.0/src/cairo-wideint.h 2005-05-10 14:55:37.000000000 -0700 -+++ cairo/src/cairo-wideint.h 2005-06-01 22:07:43.000000000 -0700 -@@ -45,7 +45,7 @@ - #elif HAVE_SYS_INT_TYPES_H - # include - #else --#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.) -+# include "mozstdint.h" - #endif - - /* -diff -ru ../../../../../cairo-cvs/dist/cairo-0.5.0/src/cairoint.h cairo/src/cairoint.h ---- ../../../../../cairo-cvs/dist/cairo-0.5.0/src/cairoint.h 2005-05-17 06:17:45.000000000 -0700 -+++ cairo/src/cairoint.h 2005-06-01 22:19:46.000000000 -0700 -@@ -1638,6 +1638,9 @@ - _cairo_matrix_compute_scale_factors (const cairo_matrix_t *matrix, - double *sx, double *sy, int x_major); - -+cairo_private cairo_status_t -+_cairo_matrix_compute_expansion_factors (const cairo_matrix_t *matrix, double *min, double *max); -+ - cairo_private cairo_bool_t - _cairo_matrix_is_integer_translation(const cairo_matrix_t *matrix, - int *itx, int *ity); -Only in cairo/src: cairoint.h~ diff --git a/gfx/cairo/glitz/src/.cvsignore b/gfx/cairo/glitz/src/.cvsignore new file mode 100644 index 000000000000..6829f0d41185 --- /dev/null +++ b/gfx/cairo/glitz/src/.cvsignore @@ -0,0 +1,7 @@ +Makefile +Makefile.in +*.la +*.lo +*.loT +.libs +.deps diff --git a/gfx/cairo/glitz/src/agl/.cvsignore b/gfx/cairo/glitz/src/agl/.cvsignore new file mode 100644 index 000000000000..6829f0d41185 --- /dev/null +++ b/gfx/cairo/glitz/src/agl/.cvsignore @@ -0,0 +1,7 @@ +Makefile +Makefile.in +*.la +*.lo +*.loT +.libs +.deps diff --git a/gfx/cairo/glitz/src/egl/.cvsignore b/gfx/cairo/glitz/src/egl/.cvsignore new file mode 100644 index 000000000000..6829f0d41185 --- /dev/null +++ b/gfx/cairo/glitz/src/egl/.cvsignore @@ -0,0 +1,7 @@ +Makefile +Makefile.in +*.la +*.lo +*.loT +.libs +.deps diff --git a/gfx/cairo/glitz/src/glitz.man b/gfx/cairo/glitz/src/glitz.man new file mode 100644 index 000000000000..e7f7656df25b --- /dev/null +++ b/gfx/cairo/glitz/src/glitz.man @@ -0,0 +1,38 @@ +.\" +.\" +.de TQ +.br +.ns +.TP +\\$1 +.. +.TH GLITZ 3 "Version 1.0" + +.SH NAME +GLITZ \- OpenGL image compositing library + +.SH SYNOPSIS +.nf +.B #include +.fi +.SH DESCRIPTION + +Glitz is an OpenGL image compositing library. Glitz provides +Porter/Duff compositing of images and implicit mask generation for +geometric primitives including trapezoids, triangles, and rectangles. + +The semantics of glitz are designed to precisely match the +specification of the X Render extension. Glitz does not only implement +X Render features like component alpha and image transformations, but +also support for additional features like convolution filters and color +gradients, which are not currently part of the X Render specification. + +The performance and capabilities of glitz are much dependent on +graphics hardware. Glitz does not in any way handle software +fall-backs when graphics hardware is insufficient. However, glitz +will report if any requested operation cannot be carried out by +graphics hardware, hence making a higher level software layer +responsible for appropriate actions. + +.SH AUTHOR +David Reveman diff --git a/gfx/cairo/glitz/src/glx/.cvsignore b/gfx/cairo/glitz/src/glx/.cvsignore new file mode 100644 index 000000000000..6829f0d41185 --- /dev/null +++ b/gfx/cairo/glitz/src/glx/.cvsignore @@ -0,0 +1,7 @@ +Makefile +Makefile.in +*.la +*.lo +*.loT +.libs +.deps diff --git a/gfx/cairo/glitz/src/glx/glitz-glx.man b/gfx/cairo/glitz/src/glx/glitz-glx.man new file mode 100644 index 000000000000..4ad99aef1c9a --- /dev/null +++ b/gfx/cairo/glitz/src/glx/glitz-glx.man @@ -0,0 +1,26 @@ +.\" +.\" +.de TQ +.br +.ns +.TP +\\$1 +.. +.TH GLITZ-GLX 3 "Version 1.0" + +.SH NAME +GLITZ-GLX \- GLX interface to glitz + +.SH SYNOPSIS +.nf +.B #include +.fi +.SH DESCRIPTION + +GLX interface to glitz. + +.SH AUTHOR +David Reveman + +.SH "SEE ALSO" +.BR GLITZ (3) \ No newline at end of file diff --git a/gfx/cairo/glitz/src/wgl/.cvsignore b/gfx/cairo/glitz/src/wgl/.cvsignore new file mode 100644 index 000000000000..6829f0d41185 --- /dev/null +++ b/gfx/cairo/glitz/src/wgl/.cvsignore @@ -0,0 +1,7 @@ +Makefile +Makefile.in +*.la +*.lo +*.loT +.libs +.deps diff --git a/gfx/cairo/glitz/src/wgl/glitz-wgl.def b/gfx/cairo/glitz/src/wgl/glitz-wgl.def new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/gfx/cairo/libpixman/NEWS b/gfx/cairo/libpixman/NEWS index 62d00554644c..cb4125846694 100644 --- a/gfx/cairo/libpixman/NEWS +++ b/gfx/cairo/libpixman/NEWS @@ -1,3 +1,45 @@ +Snapshot 0.1.6 (2005-07-28 Carl Worth ) +========================================================== +Behavioral changes +------------------ +Clips are changed to only affect destination operands, not +sources. This gives the desired behavior for cairo. If the X server's +Render implementation wants to use pixman it will have to select +source clipping, (presumably through a new API call that we can add at +that point). + +Bug fixes +--------- +Fix leak of the clip region associated with an image in +pixman_image_destroy. + +Fix units for stride return to be FbStip-sized, (this bug was causing +non antialiased text in cairo to appear as garbage). + +Other changes +------------- +The implementation has been merged considerably with xserver/fb. Most +of the merge was just name changes, but there were likely some bug +fixes or performance improvements in there as well. + +Snapshot 0.1.5 (2005-05-18 Carl Worth ) +========================================================== +Bug fixes +--------- +Fix confusion of depth and bpp which was causing cairo to crash on +some X servers. + +Properly declare pixman_fixed16_16_t as int32_t which fixes +compilation failures on some platforms. + +Fix to find inttypes.h on AIX. + +Fix bug in compositing when the source image has no alpha channel. + +Some fixes to the clipping code. + +Fix memory leak when asked to draw a degenerate trapezoid list. + Snapshot 0.1.4 (2005-03-07 Carl Worth ) ========================================================== API Addition diff --git a/gfx/cairo/libpixman/src/Makefile.in b/gfx/cairo/libpixman/src/Makefile.in index 4138e830d8d9..3c49955c2922 100644 --- a/gfx/cairo/libpixman/src/Makefile.in +++ b/gfx/cairo/libpixman/src/Makefile.in @@ -47,20 +47,14 @@ MODULE = libpixman LIBRARY_NAME = mozlibpixman LIBXUL_LIBRARY = 1 -ifeq ($(OS_ARCH)_$(GNU_CC), WINNT_) -ifeq ($(MOZ_OPTIMIZE),1) -USE_STATIC_VC71_LIB = 1 -endif -endif - CSRCS = \ + fbcompose.c \ fbedge.c \ fbtrap.c \ ic.c \ icblt.c \ icbltone.c \ iccolor.c \ - iccompose.c \ icformat.c \ icimage.c \ icpixels.c \ @@ -74,7 +68,12 @@ CSRCS = \ renderedge.c \ $(NULL) -EXPORTS = pixman.h mozstdint.h +ifdef MOZ_X11 +#CSRCS += fbmmx.c +#DEFINES += -DUSE_MMX +endif + +EXPORTS = pixman.h pixman-remap.h mozstdint.h LOCAL_INCLUDES = -I$(srcdir) @@ -84,9 +83,7 @@ FORCE_USE_PIC = 1 include $(topsrcdir)/config/rules.mk -ifeq ($(USE_STATIC_VC71_LIB),1) -libs:: $(srcdir)/pixman-vc71.lib - cp $(srcdir)/pixman-vc71.lib $(LIBRARY) - $(INSTALL) $(IFLAGS1) $(LIBRARY) $(DIST)/lib +ifdef MOZ_X11 +#CFLAGS += -mmmx -msse -Winline --param inline-unit-growth=10000 --param large-function-growth=10000 endif diff --git a/gfx/cairo/libpixman/src/fbcompose.c b/gfx/cairo/libpixman/src/fbcompose.c new file mode 100644 index 000000000000..8b3799b84878 --- /dev/null +++ b/gfx/cairo/libpixman/src/fbcompose.c @@ -0,0 +1,3617 @@ +/* + * $XdotOrg: xc/programs/Xserver/fb/fbcompose.c,v 1.5 2005/01/13 20:49:21 sandmann Exp $ + * + * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. + * 2005 Lars Knoll & Zack Rusin, Trolltech + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include "pixman-xserver-compat.h" +#include "fbpict.h" + +#ifdef RENDER + +#include "pixregionint.h" + +// #define PIXMAN_CONVOLUTION +// #define PIXMAN_GRADIENTS +// #define PIXMAN_INDEXED_FORMATS + +static Bool +PictureTransformPoint3d (pixman_transform_t *transform, + PictVector *vector) +{ + PictVector result; + int i, j; + xFixed_32_32 partial; + xFixed_48_16 v; + + for (j = 0; j < 3; j++) + { + v = 0; + for (i = 0; i < 3; i++) + { + partial = ((xFixed_48_16) transform->matrix[j][i] * + (xFixed_48_16) vector->vector[i]); + v += partial >> 16; + } + if (v > MAX_FIXED_48_16 || v < MIN_FIXED_48_16) + return FALSE; + result.vector[j] = (xFixed) v; + } + if (!result.vector[2]) + return FALSE; + *vector = result; + return TRUE; +} + +#define mod(a,b) ((b) == 1 ? 0 : (a) >= 0 ? (a) % (b) : (b) - (-a) % (b)) + +#define SCANLINE_BUFFER_LENGTH 2048 + +typedef FASTCALL void (*fetchProc)(const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed); + +/* + * All of the fetch functions + */ + +static FASTCALL void +fbFetch_a8r8g8b8 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + memcpy(buffer, (const CARD32 *)bits + x, width*sizeof(CARD32)); +} + +static FASTCALL void +fbFetch_x8r8g8b8 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD32 *pixel = (const CARD32 *)bits + x; + const CARD32 *end = pixel + width; + while (pixel < end) { + *buffer++ = *pixel++ | 0xff000000; + } +} + +static FASTCALL void +fbFetch_a8b8g8r8 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD32 *pixel = (CARD32 *)bits + x; + const CARD32 *end = pixel + width; + while (pixel < end) { + *buffer++ = ((*pixel & 0xff00ff00) | + ((*pixel >> 16) & 0xff) | + ((*pixel & 0xff) << 16)); + ++pixel; + } +} + +static FASTCALL void +fbFetch_x8b8g8r8 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD32 *pixel = (CARD32 *)bits + x; + const CARD32 *end = pixel + width; + while (pixel < end) { + *buffer++ = 0xff000000 | + ((*pixel & 0x0000ff00) | + ((*pixel >> 16) & 0xff) | + ((*pixel & 0xff) << 16)); + ++pixel; + } +} + +static FASTCALL void +fbFetch_r8g8b8 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD8 *pixel = (const CARD8 *)bits + 3*x; + const CARD8 *end = pixel + 3*width; + while (pixel < end) { + CARD32 b = Fetch24(pixel) | 0xff000000; + pixel += 3; + *buffer++ = b; + } +} + +static FASTCALL void +fbFetch_b8g8r8 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD8 *pixel = (const CARD8 *)bits + 3*x; + const CARD8 *end = pixel + 3*width; + while (pixel < end) { + CARD32 b = 0xff000000; +#if IMAGE_BYTE_ORDER == MSBFirst + b |= (*pixel++); + b |= (*pixel++ << 8); + b |= (*pixel++ << 16); +#else + b |= (*pixel++ << 16); + b |= (*pixel++ << 8); + b |= (*pixel++); +#endif + } +} + +static FASTCALL void +fbFetch_r5g6b5 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD16 *pixel = (const CARD16 *)bits + x; + const CARD16 *end = pixel + width; + while (pixel < end) { + CARD32 p = *pixel++; + CARD32 r = (((p) << 3) & 0xf8) | + (((p) << 5) & 0xfc00) | + (((p) << 8) & 0xf80000); + r |= (r >> 5) & 0x70007; + r |= (r >> 6) & 0x300; + *buffer++ = 0xff000000 | r; + } +} + +static FASTCALL void +fbFetch_b5g6r5 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD16 *pixel = (const CARD16 *)bits + x; + const CARD16 *end = pixel + width; + while (pixel < end) { + CARD32 p = *pixel++; + CARD32 r,g,b; + + b = ((p & 0xf800) | ((p & 0xe000) >> 5)) >> 8; + g = ((p & 0x07e0) | ((p & 0x0600) >> 6)) << 5; + r = ((p & 0x001c) | ((p & 0x001f) << 5)) << 14; + *buffer++ = (0xff000000 | r | g | b); + } +} + +static FASTCALL void +fbFetch_a1r5g5b5 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD16 *pixel = (const CARD16 *)bits + x; + const CARD16 *end = pixel + width; + while (pixel < end) { + CARD32 p = *pixel++; + CARD32 r,g,b, a; + + a = (CARD32) ((CARD8) (0 - ((p & 0x8000) >> 15))) << 24; + r = ((p & 0x7c00) | ((p & 0x7000) >> 5)) << 9; + g = ((p & 0x03e0) | ((p & 0x0380) >> 5)) << 6; + b = ((p & 0x001c) | ((p & 0x001f) << 5)) >> 2; + *buffer++ = (a | r | g | b); + } +} + +static FASTCALL void +fbFetch_x1r5g5b5 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD16 *pixel = (const CARD16 *)bits + x; + const CARD16 *end = pixel + width; + while (pixel < end) { + CARD32 p = *pixel++; + CARD32 r,g,b; + + r = ((p & 0x7c00) | ((p & 0x7000) >> 5)) << 9; + g = ((p & 0x03e0) | ((p & 0x0380) >> 5)) << 6; + b = ((p & 0x001c) | ((p & 0x001f) << 5)) >> 2; + *buffer++ = (0xff000000 | r | g | b); + } +} + +static FASTCALL void +fbFetch_a1b5g5r5 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD16 *pixel = (const CARD16 *)bits + x; + const CARD16 *end = pixel + width; + while (pixel < end) { + CARD32 p = *pixel++; + CARD32 r,g,b, a; + + a = (CARD32) ((CARD8) (0 - ((p & 0x8000) >> 15))) << 24; + b = ((p & 0x7c00) | ((p & 0x7000) >> 5)) >> 7; + g = ((p & 0x03e0) | ((p & 0x0380) >> 5)) << 6; + r = ((p & 0x001c) | ((p & 0x001f) << 5)) << 14; + *buffer++ = (a | r | g | b); + } +} + +static FASTCALL void +fbFetch_x1b5g5r5 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD16 *pixel = (const CARD16 *)bits + x; + const CARD16 *end = pixel + width; + while (pixel < end) { + CARD32 p = *pixel++; + CARD32 r,g,b; + + b = ((p & 0x7c00) | ((p & 0x7000) >> 5)) >> 7; + g = ((p & 0x03e0) | ((p & 0x0380) >> 5)) << 6; + r = ((p & 0x001c) | ((p & 0x001f) << 5)) << 14; + *buffer++ = (0xff000000 | r | g | b); + } +} + +static FASTCALL void +fbFetch_a4r4g4b4 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD16 *pixel = (const CARD16 *)bits + x; + const CARD16 *end = pixel + width; + while (pixel < end) { + CARD32 p = *pixel++; + CARD32 r,g,b, a; + + a = ((p & 0xf000) | ((p & 0xf000) >> 4)) << 16; + r = ((p & 0x0f00) | ((p & 0x0f00) >> 4)) << 12; + g = ((p & 0x00f0) | ((p & 0x00f0) >> 4)) << 8; + b = ((p & 0x000f) | ((p & 0x000f) << 4)); + *buffer++ = (a | r | g | b); + } +} + +static FASTCALL void +fbFetch_x4r4g4b4 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD16 *pixel = (const CARD16 *)bits + x; + const CARD16 *end = pixel + width; + while (pixel < end) { + CARD32 p = *pixel++; + CARD32 r,g,b; + + r = ((p & 0x0f00) | ((p & 0x0f00) >> 4)) << 12; + g = ((p & 0x00f0) | ((p & 0x00f0) >> 4)) << 8; + b = ((p & 0x000f) | ((p & 0x000f) << 4)); + *buffer++ = (0xff000000 | r | g | b); + } +} + +static FASTCALL void +fbFetch_a4b4g4r4 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD16 *pixel = (const CARD16 *)bits + x; + const CARD16 *end = pixel + width; + while (pixel < end) { + CARD32 p = *pixel++; + CARD32 r,g,b, a; + + a = ((p & 0xf000) | ((p & 0xf000) >> 4)) << 16; + b = ((p & 0x0f00) | ((p & 0x0f00) >> 4)) << 12; + g = ((p & 0x00f0) | ((p & 0x00f0) >> 4)) << 8; + r = ((p & 0x000f) | ((p & 0x000f) << 4)); + *buffer++ = (a | r | g | b); + } +} + +static FASTCALL void +fbFetch_x4b4g4r4 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD16 *pixel = (const CARD16 *)bits + x; + const CARD16 *end = pixel + width; + while (pixel < end) { + CARD32 p = *pixel++; + CARD32 r,g,b; + + b = ((p & 0x0f00) | ((p & 0x0f00) >> 4)) << 12; + g = ((p & 0x00f0) | ((p & 0x00f0) >> 4)) << 8; + r = ((p & 0x000f) | ((p & 0x000f) << 4)); + *buffer++ = (0xff000000 | r | g | b); + } +} + +static FASTCALL void +fbFetch_a8 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD8 *pixel = (const CARD8 *)bits + x; + const CARD8 *end = pixel + width; + while (pixel < end) { + *buffer++ = (*pixel++) << 24; + } +} + +static FASTCALL void +fbFetch_r3g3b2 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD8 *pixel = (const CARD8 *)bits + x; + const CARD8 *end = pixel + width; + while (pixel < end) { + CARD32 p = *pixel++; + CARD32 r,g,b; + + r = ((p & 0xe0) | ((p & 0xe0) >> 3) | ((p & 0xc0) >> 6)) << 16; + g = ((p & 0x1c) | ((p & 0x18) >> 3) | ((p & 0x1c) << 3)) << 8; + b = (((p & 0x03) ) | + ((p & 0x03) << 2) | + ((p & 0x03) << 4) | + ((p & 0x03) << 6)); + *buffer++ = (0xff000000 | r | g | b); + } +} + +static FASTCALL void +fbFetch_b2g3r3 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD8 *pixel = (const CARD8 *)bits + x; + const CARD8 *end = pixel + width; + while (pixel < end) { + CARD32 p = *pixel++; + CARD32 r,g,b; + + b = (((p & 0xc0) ) | + ((p & 0xc0) >> 2) | + ((p & 0xc0) >> 4) | + ((p & 0xc0) >> 6)); + g = ((p & 0x38) | ((p & 0x38) >> 3) | ((p & 0x30) << 2)) << 8; + r = (((p & 0x07) ) | + ((p & 0x07) << 3) | + ((p & 0x06) << 6)) << 16; + *buffer++ = (0xff000000 | r | g | b); + } +} + +static FASTCALL void +fbFetch_a2r2g2b2 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD8 *pixel = (const CARD8 *)bits + x; + const CARD8 *end = pixel + width; + while (pixel < end) { + CARD32 p = *pixel++; + CARD32 a,r,g,b; + + a = ((p & 0xc0) * 0x55) << 18; + r = ((p & 0x30) * 0x55) << 12; + g = ((p & 0x0c) * 0x55) << 6; + b = ((p & 0x03) * 0x55); + *buffer++ = a|r|g|b; + } +} + +static FASTCALL void +fbFetch_a2b2g2r2 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD8 *pixel = (const CARD8 *)bits + x; + const CARD8 *end = pixel + width; + while (pixel < end) { + CARD32 p = *pixel++; + CARD32 a,r,g,b; + + a = ((p & 0xc0) * 0x55) << 18; + b = ((p & 0x30) * 0x55) >> 6; + g = ((p & 0x0c) * 0x55) << 6; + r = ((p & 0x03) * 0x55) << 16; + *buffer++ = a|r|g|b; + } +} + +static FASTCALL void +fbFetch_c8 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + const CARD8 *pixel = (const CARD8 *)bits + x; + const CARD8 *end = pixel + width; + while (pixel < end) { + CARD32 p = *pixel++; + *buffer++ = indexed->rgba[p]; + } +} + +#define Fetch8(l,o) (((CARD8 *) (l))[(o) >> 2]) +#if IMAGE_BYTE_ORDER == MSBFirst +#define Fetch4(l,o) ((o) & 2 ? Fetch8(l,o) & 0xf : Fetch8(l,o) >> 4) +#else +#define Fetch4(l,o) ((o) & 2 ? Fetch8(l,o) >> 4 : Fetch8(l,o) & 0xf) +#endif + +static FASTCALL void +fbFetch_a4 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 p = Fetch4(bits, i + x); + + p |= p << 4; + *buffer++ = p << 24; + } +} + +static FASTCALL void +fbFetch_r1g2b1 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 p = Fetch4(bits, i + x); + CARD32 r,g,b; + + r = ((p & 0x8) * 0xff) << 13; + g = ((p & 0x6) * 0x55) << 7; + b = ((p & 0x1) * 0xff); + *buffer++ = 0xff000000|r|g|b; + } +} + +static FASTCALL void +fbFetch_b1g2r1 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 p = Fetch4(bits, i + x); + CARD32 r,g,b; + + b = ((p & 0x8) * 0xff) >> 3; + g = ((p & 0x6) * 0x55) << 7; + r = ((p & 0x1) * 0xff) << 16; + *buffer++ = 0xff000000|r|g|b; + } +} + +static FASTCALL void +fbFetch_a1r1g1b1 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 p = Fetch4(bits, i + x); + CARD32 a,r,g,b; + + a = ((p & 0x8) * 0xff) << 21; + r = ((p & 0x4) * 0xff) << 14; + g = ((p & 0x2) * 0xff) << 7; + b = ((p & 0x1) * 0xff); + *buffer++ = a|r|g|b; + } +} + +static FASTCALL void +fbFetch_a1b1g1r1 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 p = Fetch4(bits, i + x); + CARD32 a,r,g,b; + + a = ((p & 0x8) * 0xff) << 21; + r = ((p & 0x4) * 0xff) >> 3; + g = ((p & 0x2) * 0xff) << 7; + b = ((p & 0x1) * 0xff) << 16; + *buffer++ = a|r|g|b; + } +} + +static FASTCALL void +fbFetch_c4 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 p = Fetch4(bits, i + x); + + *buffer++ = indexed->rgba[p]; + } +} + + +static FASTCALL void +fbFetch_a1 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 p = ((CARD32 *)bits)[(i + x) >> 5]; + CARD32 a; +#if BITMAP_BIT_ORDER == MSBFirst + a = p >> (0x1f - ((i+x) & 0x1f)); +#else + a = p >> ((i+x) & 0x1f); +#endif + a = a & 1; + a |= a << 1; + a |= a << 2; + a |= a << 4; + *buffer++ = a << 24; + } +} + +static FASTCALL void +fbFetch_g1 (const FbBits *bits, int x, int width, CARD32 *buffer, miIndexedPtr indexed) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 p = ((CARD32 *)bits)[(i+x) >> 5]; + CARD32 a; +#if BITMAP_BIT_ORDER == MSBFirst + a = p >> (0x1f - ((i+x) & 0x1f)); +#else + a = p >> ((i+x) & 0x1f); +#endif + a = a & 1; + *buffer++ = indexed->rgba[a]; + } +} + +static fetchProc fetchProcForPicture (PicturePtr pict) +{ + switch(pict->format_code) { + case PICT_a8r8g8b8: return fbFetch_a8r8g8b8; + case PICT_x8r8g8b8: return fbFetch_x8r8g8b8; + case PICT_a8b8g8r8: return fbFetch_a8b8g8r8; + case PICT_x8b8g8r8: return fbFetch_x8b8g8r8; + + /* 24bpp formats */ + case PICT_r8g8b8: return fbFetch_r8g8b8; + case PICT_b8g8r8: return fbFetch_b8g8r8; + + /* 16bpp formats */ + case PICT_r5g6b5: return fbFetch_r5g6b5; + case PICT_b5g6r5: return fbFetch_b5g6r5; + + case PICT_a1r5g5b5: return fbFetch_a1r5g5b5; + case PICT_x1r5g5b5: return fbFetch_x1r5g5b5; + case PICT_a1b5g5r5: return fbFetch_a1b5g5r5; + case PICT_x1b5g5r5: return fbFetch_x1b5g5r5; + case PICT_a4r4g4b4: return fbFetch_a4r4g4b4; + case PICT_x4r4g4b4: return fbFetch_x4r4g4b4; + case PICT_a4b4g4r4: return fbFetch_a4b4g4r4; + case PICT_x4b4g4r4: return fbFetch_x4b4g4r4; + + /* 8bpp formats */ + case PICT_a8: return fbFetch_a8; + case PICT_r3g3b2: return fbFetch_r3g3b2; + case PICT_b2g3r3: return fbFetch_b2g3r3; + case PICT_a2r2g2b2: return fbFetch_a2r2g2b2; + case PICT_a2b2g2r2: return fbFetch_a2b2g2r2; + case PICT_c8: return fbFetch_c8; + case PICT_g8: return fbFetch_c8; + + /* 4bpp formats */ + case PICT_a4: return fbFetch_a4; + case PICT_r1g2b1: return fbFetch_r1g2b1; + case PICT_b1g2r1: return fbFetch_b1g2r1; + case PICT_a1r1g1b1: return fbFetch_a1r1g1b1; + case PICT_a1b1g1r1: return fbFetch_a1b1g1r1; + case PICT_c4: return fbFetch_c4; + case PICT_g4: return fbFetch_c4; + + /* 1bpp formats */ + case PICT_a1: return fbFetch_a1; + case PICT_g1: return fbFetch_g1; + default: + return 0; + } +} + +/* + * Pixel wise fetching + */ + +typedef FASTCALL CARD32 (*fetchPixelProc)(const FbBits *bits, int offset, miIndexedPtr indexed); + +static FASTCALL CARD32 +fbFetchPixel_a8r8g8b8 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + return ((CARD32 *)bits)[offset]; +} + +static FASTCALL CARD32 +fbFetchPixel_x8r8g8b8 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + return ((CARD32 *)bits)[offset] | 0xff000000; +} + +static FASTCALL CARD32 +fbFetchPixel_a8b8g8r8 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD32 *)bits)[offset]; + + return ((pixel & 0xff000000) | + ((pixel >> 16) & 0xff) | + (pixel & 0x0000ff00) | + ((pixel & 0xff) << 16)); +} + +static FASTCALL CARD32 +fbFetchPixel_x8b8g8r8 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD32 *)bits)[offset]; + + return ((0xff000000) | + ((pixel >> 16) & 0xff) | + (pixel & 0x0000ff00) | + ((pixel & 0xff) << 16)); +} + +static FASTCALL CARD32 +fbFetchPixel_r8g8b8 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD8 *pixel = ((CARD8 *) bits) + (offset*3); +#if IMAGE_BYTE_ORDER == MSBFirst + return (0xff000000 | + (pixel[0] << 16) | + (pixel[1] << 8) | + (pixel[2])); +#else + return (0xff000000 | + (pixel[2] << 16) | + (pixel[1] << 8) | + (pixel[0])); +#endif +} + +static FASTCALL CARD32 +fbFetchPixel_b8g8r8 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD8 *pixel = ((CARD8 *) bits) + (offset*3); +#if IMAGE_BYTE_ORDER == MSBFirst + return (0xff000000 | + (pixel[2] << 16) | + (pixel[1] << 8) | + (pixel[0])); +#else + return (0xff000000 | + (pixel[0] << 16) | + (pixel[1] << 8) | + (pixel[2])); +#endif +} + +static FASTCALL CARD32 +fbFetchPixel_r5g6b5 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD16 *) bits)[offset]; + CARD32 r,g,b; + + r = ((pixel & 0xf800) | ((pixel & 0xe000) >> 5)) << 8; + g = ((pixel & 0x07e0) | ((pixel & 0x0600) >> 6)) << 5; + b = ((pixel & 0x001c) | ((pixel & 0x001f) << 5)) >> 2; + return (0xff000000 | r | g | b); +} + +static FASTCALL CARD32 +fbFetchPixel_b5g6r5 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD16 *) bits)[offset]; + CARD32 r,g,b; + + b = ((pixel & 0xf800) | ((pixel & 0xe000) >> 5)) >> 8; + g = ((pixel & 0x07e0) | ((pixel & 0x0600) >> 6)) << 5; + r = ((pixel & 0x001c) | ((pixel & 0x001f) << 5)) << 14; + return (0xff000000 | r | g | b); +} + +static FASTCALL CARD32 +fbFetchPixel_a1r5g5b5 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD16 *) bits)[offset]; + CARD32 a,r,g,b; + + a = (CARD32) ((CARD8) (0 - ((pixel & 0x8000) >> 15))) << 24; + r = ((pixel & 0x7c00) | ((pixel & 0x7000) >> 5)) << 9; + g = ((pixel & 0x03e0) | ((pixel & 0x0380) >> 5)) << 6; + b = ((pixel & 0x001c) | ((pixel & 0x001f) << 5)) >> 2; + return (a | r | g | b); +} + +static FASTCALL CARD32 +fbFetchPixel_x1r5g5b5 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD16 *) bits)[offset]; + CARD32 r,g,b; + + r = ((pixel & 0x7c00) | ((pixel & 0x7000) >> 5)) << 9; + g = ((pixel & 0x03e0) | ((pixel & 0x0380) >> 5)) << 6; + b = ((pixel & 0x001c) | ((pixel & 0x001f) << 5)) >> 2; + return (0xff000000 | r | g | b); +} + +static FASTCALL CARD32 +fbFetchPixel_a1b5g5r5 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD16 *) bits)[offset]; + CARD32 a,r,g,b; + + a = (CARD32) ((CARD8) (0 - ((pixel & 0x8000) >> 15))) << 24; + b = ((pixel & 0x7c00) | ((pixel & 0x7000) >> 5)) >> 7; + g = ((pixel & 0x03e0) | ((pixel & 0x0380) >> 5)) << 6; + r = ((pixel & 0x001c) | ((pixel & 0x001f) << 5)) << 14; + return (a | r | g | b); +} + +static FASTCALL CARD32 +fbFetchPixel_x1b5g5r5 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD16 *) bits)[offset]; + CARD32 r,g,b; + + b = ((pixel & 0x7c00) | ((pixel & 0x7000) >> 5)) >> 7; + g = ((pixel & 0x03e0) | ((pixel & 0x0380) >> 5)) << 6; + r = ((pixel & 0x001c) | ((pixel & 0x001f) << 5)) << 14; + return (0xff000000 | r | g | b); +} + +static FASTCALL CARD32 +fbFetchPixel_a4r4g4b4 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD16 *) bits)[offset]; + CARD32 a,r,g,b; + + a = ((pixel & 0xf000) | ((pixel & 0xf000) >> 4)) << 16; + r = ((pixel & 0x0f00) | ((pixel & 0x0f00) >> 4)) << 12; + g = ((pixel & 0x00f0) | ((pixel & 0x00f0) >> 4)) << 8; + b = ((pixel & 0x000f) | ((pixel & 0x000f) << 4)); + return (a | r | g | b); +} + +static FASTCALL CARD32 +fbFetchPixel_x4r4g4b4 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD16 *) bits)[offset]; + CARD32 r,g,b; + + r = ((pixel & 0x0f00) | ((pixel & 0x0f00) >> 4)) << 12; + g = ((pixel & 0x00f0) | ((pixel & 0x00f0) >> 4)) << 8; + b = ((pixel & 0x000f) | ((pixel & 0x000f) << 4)); + return (0xff000000 | r | g | b); +} + +static FASTCALL CARD32 +fbFetchPixel_a4b4g4r4 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD16 *) bits)[offset]; + CARD32 a,r,g,b; + + a = ((pixel & 0xf000) | ((pixel & 0xf000) >> 4)) << 16; + b = ((pixel & 0x0f00) | ((pixel & 0x0f00) >> 4)) << 12; + g = ((pixel & 0x00f0) | ((pixel & 0x00f0) >> 4)) << 8; + r = ((pixel & 0x000f) | ((pixel & 0x000f) << 4)); + return (a | r | g | b); +} + +static FASTCALL CARD32 +fbFetchPixel_x4b4g4r4 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD16 *) bits)[offset]; + CARD32 r,g,b; + + b = ((pixel & 0x0f00) | ((pixel & 0x0f00) >> 4)) << 12; + g = ((pixel & 0x00f0) | ((pixel & 0x00f0) >> 4)) << 8; + r = ((pixel & 0x000f) | ((pixel & 0x000f) << 4)); + return (0xff000000 | r | g | b); +} + +static FASTCALL CARD32 +fbFetchPixel_a8 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD8 *) bits)[offset]; + + return pixel << 24; +} + +static FASTCALL CARD32 +fbFetchPixel_r3g3b2 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD8 *) bits)[offset]; + CARD32 r,g,b; + + r = ((pixel & 0xe0) | ((pixel & 0xe0) >> 3) | ((pixel & 0xc0) >> 6)) << 16; + g = ((pixel & 0x1c) | ((pixel & 0x18) >> 3) | ((pixel & 0x1c) << 3)) << 8; + b = (((pixel & 0x03) ) | + ((pixel & 0x03) << 2) | + ((pixel & 0x03) << 4) | + ((pixel & 0x03) << 6)); + return (0xff000000 | r | g | b); +} + +static FASTCALL CARD32 +fbFetchPixel_b2g3r3 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD8 *) bits)[offset]; + CARD32 r,g,b; + + b = (((pixel & 0xc0) ) | + ((pixel & 0xc0) >> 2) | + ((pixel & 0xc0) >> 4) | + ((pixel & 0xc0) >> 6)); + g = ((pixel & 0x38) | ((pixel & 0x38) >> 3) | ((pixel & 0x30) << 2)) << 8; + r = (((pixel & 0x07) ) | + ((pixel & 0x07) << 3) | + ((pixel & 0x06) << 6)) << 16; + return (0xff000000 | r | g | b); +} + +static FASTCALL CARD32 +fbFetchPixel_a2r2g2b2 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD8 *) bits)[offset]; + CARD32 a,r,g,b; + + a = ((pixel & 0xc0) * 0x55) << 18; + r = ((pixel & 0x30) * 0x55) << 12; + g = ((pixel & 0x0c) * 0x55) << 6; + b = ((pixel & 0x03) * 0x55); + return a|r|g|b; +} + +static FASTCALL CARD32 +fbFetchPixel_a2b2g2r2 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD8 *) bits)[offset]; + CARD32 a,r,g,b; + + a = ((pixel & 0xc0) * 0x55) << 18; + b = ((pixel & 0x30) * 0x55) >> 6; + g = ((pixel & 0x0c) * 0x55) << 6; + r = ((pixel & 0x03) * 0x55) << 16; + return a|r|g|b; +} + +static FASTCALL CARD32 +fbFetchPixel_c8 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD8 *) bits)[offset]; + return indexed->rgba[pixel]; +} + +#define Fetch8(l,o) (((CARD8 *) (l))[(o) >> 2]) +#if IMAGE_BYTE_ORDER == MSBFirst +#define Fetch4(l,o) ((o) & 2 ? Fetch8(l,o) & 0xf : Fetch8(l,o) >> 4) +#else +#define Fetch4(l,o) ((o) & 2 ? Fetch8(l,o) >> 4 : Fetch8(l,o) & 0xf) +#endif + +static FASTCALL CARD32 +fbFetchPixel_a4 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = Fetch4(bits, offset); + + pixel |= pixel << 4; + return pixel << 24; +} + +static FASTCALL CARD32 +fbFetchPixel_r1g2b1 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = Fetch4(bits, offset); + CARD32 r,g,b; + + r = ((pixel & 0x8) * 0xff) << 13; + g = ((pixel & 0x6) * 0x55) << 7; + b = ((pixel & 0x1) * 0xff); + return 0xff000000|r|g|b; +} + +static FASTCALL CARD32 +fbFetchPixel_b1g2r1 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = Fetch4(bits, offset); + CARD32 r,g,b; + + b = ((pixel & 0x8) * 0xff) >> 3; + g = ((pixel & 0x6) * 0x55) << 7; + r = ((pixel & 0x1) * 0xff) << 16; + return 0xff000000|r|g|b; +} + +static FASTCALL CARD32 +fbFetchPixel_a1r1g1b1 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = Fetch4(bits, offset); + CARD32 a,r,g,b; + + a = ((pixel & 0x8) * 0xff) << 21; + r = ((pixel & 0x4) * 0xff) << 14; + g = ((pixel & 0x2) * 0xff) << 7; + b = ((pixel & 0x1) * 0xff); + return a|r|g|b; +} + +static FASTCALL CARD32 +fbFetchPixel_a1b1g1r1 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = Fetch4(bits, offset); + CARD32 a,r,g,b; + + a = ((pixel & 0x8) * 0xff) << 21; + r = ((pixel & 0x4) * 0xff) >> 3; + g = ((pixel & 0x2) * 0xff) << 7; + b = ((pixel & 0x1) * 0xff) << 16; + return a|r|g|b; +} + +static FASTCALL CARD32 +fbFetchPixel_c4 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = Fetch4(bits, offset); + + return indexed->rgba[pixel]; +} + + +static FASTCALL CARD32 +fbFetchPixel_a1 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD32 *)bits)[offset >> 5]; + CARD32 a; +#if BITMAP_BIT_ORDER == MSBFirst + a = pixel >> (0x1f - (offset & 0x1f)); +#else + a = pixel >> (offset & 0x1f); +#endif + a = a & 1; + a |= a << 1; + a |= a << 2; + a |= a << 4; + return a << 24; +} + +static FASTCALL CARD32 +fbFetchPixel_g1 (const FbBits *bits, int offset, miIndexedPtr indexed) +{ + CARD32 pixel = ((CARD32 *)bits)[offset >> 5]; + CARD32 a; +#if BITMAP_BIT_ORDER == MSBFirst + a = pixel >> (0x1f - (offset & 0x1f)); +#else + a = pixel >> (offset & 0x1f); +#endif + a = a & 1; + return indexed->rgba[a]; +} + +static fetchPixelProc fetchPixelProcForPicture (PicturePtr pict) +{ + switch(pict->format_code) { + case PICT_a8r8g8b8: return fbFetchPixel_a8r8g8b8; + case PICT_x8r8g8b8: return fbFetchPixel_x8r8g8b8; + case PICT_a8b8g8r8: return fbFetchPixel_a8b8g8r8; + case PICT_x8b8g8r8: return fbFetchPixel_x8b8g8r8; + + /* 24bpp formats */ + case PICT_r8g8b8: return fbFetchPixel_r8g8b8; + case PICT_b8g8r8: return fbFetchPixel_b8g8r8; + + /* 16bpp formats */ + case PICT_r5g6b5: return fbFetchPixel_r5g6b5; + case PICT_b5g6r5: return fbFetchPixel_b5g6r5; + + case PICT_a1r5g5b5: return fbFetchPixel_a1r5g5b5; + case PICT_x1r5g5b5: return fbFetchPixel_x1r5g5b5; + case PICT_a1b5g5r5: return fbFetchPixel_a1b5g5r5; + case PICT_x1b5g5r5: return fbFetchPixel_x1b5g5r5; + case PICT_a4r4g4b4: return fbFetchPixel_a4r4g4b4; + case PICT_x4r4g4b4: return fbFetchPixel_x4r4g4b4; + case PICT_a4b4g4r4: return fbFetchPixel_a4b4g4r4; + case PICT_x4b4g4r4: return fbFetchPixel_x4b4g4r4; + + /* 8bpp formats */ + case PICT_a8: return fbFetchPixel_a8; + case PICT_r3g3b2: return fbFetchPixel_r3g3b2; + case PICT_b2g3r3: return fbFetchPixel_b2g3r3; + case PICT_a2r2g2b2: return fbFetchPixel_a2r2g2b2; + case PICT_a2b2g2r2: return fbFetchPixel_a2b2g2r2; + case PICT_c8: return fbFetchPixel_c8; + case PICT_g8: return fbFetchPixel_c8; + + /* 4bpp formats */ + case PICT_a4: return fbFetchPixel_a4; + case PICT_r1g2b1: return fbFetchPixel_r1g2b1; + case PICT_b1g2r1: return fbFetchPixel_b1g2r1; + case PICT_a1r1g1b1: return fbFetchPixel_a1r1g1b1; + case PICT_a1b1g1r1: return fbFetchPixel_a1b1g1r1; + case PICT_c4: return fbFetchPixel_c4; + case PICT_g4: return fbFetchPixel_c4; + + /* 1bpp formats */ + case PICT_a1: return fbFetchPixel_a1; + case PICT_g1: return fbFetchPixel_g1; + default: + return 0; + } +} + + + +/* + * All the store functions + */ + +typedef FASTCALL void (*storeProc) (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed); + +#define Splita(v) CARD32 a = ((v) >> 24), r = ((v) >> 16) & 0xff, g = ((v) >> 8) & 0xff, b = (v) & 0xff +#define Split(v) CARD32 r = ((v) >> 16) & 0xff, g = ((v) >> 8) & 0xff, b = (v) & 0xff + +static FASTCALL void +fbStore_a8r8g8b8 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + memcpy(((CARD32 *)bits) + x, values, width*sizeof(CARD32)); +} + +static FASTCALL void +fbStore_x8r8g8b8 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD32 *pixel = (CARD32 *)bits + x; + for (i = 0; i < width; ++i) + *pixel++ = values[i] & 0xffffff; +} + +static FASTCALL void +fbStore_a8b8g8r8 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD32 *pixel = (CARD32 *)bits + x; + for (i = 0; i < width; ++i) + *pixel++ = (values[i] & 0xff00ff00) | ((values[i] >> 16) && 0xff) | ((values[i] & 0xff) << 16); +} + +static FASTCALL void +fbStore_x8b8g8r8 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD32 *pixel = (CARD32 *)bits + x; + for (i = 0; i < width; ++i) + *pixel++ = (values[i] & 0x0000ff00) | ((values[i] >> 16) && 0xff) | ((values[i] & 0xff) << 16); +} + +static FASTCALL void +fbStore_r8g8b8 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD8 *pixel = ((CARD8 *) bits) + x; + for (i = 0; i < width; ++i) { + Store24(pixel, values[i]); + pixel += 3; + } +} + +static FASTCALL void +fbStore_b8g8r8 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD8 *pixel = ((CARD8 *) bits) + x; + for (i = 0; i < width; ++i) { +#if IMAGE_BYTE_ORDER == MSBFirst + *pixel++ = Blue(values[i]); + *pixel++ = Green(values[i]); + *pixel++ = Red(values[i]); +#else + *pixel++ = Red(values[i]); + *pixel++ = Green(values[i]); + *pixel++ = Blue(values[i]); +#endif + } +} + +static FASTCALL void +fbStore_r5g6b5 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD16 *pixel = ((CARD16 *) bits) + x; + for (i = 0; i < width; ++i) { + CARD32 s = values[i]; + *pixel++ = ((s >> 3) & 0x001f) | + ((s >> 5) & 0x07e0) | + ((s >> 8) & 0xf800); + } +} + +static FASTCALL void +fbStore_b5g6r5 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD16 *pixel = ((CARD16 *) bits) + x; + for (i = 0; i < width; ++i) { + Split(values[i]); + *pixel++ = (((b << 8) & 0xf800) | + ((g << 3) & 0x07e0) | + ((r >> 3) )); + } +} + +static FASTCALL void +fbStore_a1r5g5b5 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD16 *pixel = ((CARD16 *) bits) + x; + for (i = 0; i < width; ++i) { + Splita(values[i]); + *pixel++ = (((a << 8) & 0x8000) | + ((r << 7) & 0x7c00) | + ((g << 2) & 0x03e0) | + ((b >> 3) )); + } +} + +static FASTCALL void +fbStore_x1r5g5b5 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD16 *pixel = ((CARD16 *) bits) + x; + for (i = 0; i < width; ++i) { + Split(values[i]); + *pixel++ = (((r << 7) & 0x7c00) | + ((g << 2) & 0x03e0) | + ((b >> 3) )); + } +} + +static FASTCALL void +fbStore_a1b5g5r5 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD16 *pixel = ((CARD16 *) bits) + x; + for (i = 0; i < width; ++i) { + Splita(values[i]); + *pixel++ = (((a << 8) & 0x8000) | + ((b << 7) & 0x7c00) | + ((g << 2) & 0x03e0) | + ((r >> 3) )); + } +} + +static FASTCALL void +fbStore_x1b5g5r5 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD16 *pixel = ((CARD16 *) bits) + x; + for (i = 0; i < width; ++i) { + Split(values[i]); + *pixel++ = (((b << 7) & 0x7c00) | + ((g << 2) & 0x03e0) | + ((r >> 3) )); + } +} + +static FASTCALL void +fbStore_a4r4g4b4 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD16 *pixel = ((CARD16 *) bits) + x; + for (i = 0; i < width; ++i) { + Splita(values[i]); + *pixel++ = (((a << 8) & 0xf000) | + ((r << 4) & 0x0f00) | + ((g ) & 0x00f0) | + ((b >> 4) )); + } +} + +static FASTCALL void +fbStore_x4r4g4b4 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD16 *pixel = ((CARD16 *) bits) + x; + for (i = 0; i < width; ++i) { + Split(values[i]); + *pixel++ = (((r << 4) & 0x0f00) | + ((g ) & 0x00f0) | + ((b >> 4) )); + } +} + +static FASTCALL void +fbStore_a4b4g4r4 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD16 *pixel = ((CARD16 *) bits) + x; + for (i = 0; i < width; ++i) { + Splita(values[i]); + *pixel++ = (((a << 8) & 0xf000) | + ((b << 4) & 0x0f00) | + ((g ) & 0x00f0) | + ((r >> 4) )); + } +} + +static FASTCALL void +fbStore_x4b4g4r4 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD16 *pixel = ((CARD16 *) bits) + x; + for (i = 0; i < width; ++i) { + Split(values[i]); + *pixel++ = (((b << 4) & 0x0f00) | + ((g ) & 0x00f0) | + ((r >> 4) )); + } +} + +static FASTCALL void +fbStore_a8 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD8 *pixel = ((CARD8 *) bits) + x; + for (i = 0; i < width; ++i) { + *pixel++ = values[i] >> 24; + } +} + +static FASTCALL void +fbStore_r3g3b2 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD8 *pixel = ((CARD8 *) bits) + x; + for (i = 0; i < width; ++i) { + Split(values[i]); + *pixel++ = (((r ) & 0xe0) | + ((g >> 3) & 0x1c) | + ((b >> 6) )); + } +} + +static FASTCALL void +fbStore_b2g3r3 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD8 *pixel = ((CARD8 *) bits) + x; + for (i = 0; i < width; ++i) { + Split(values[i]); + *pixel++ = (((b ) & 0xe0) | + ((g >> 3) & 0x1c) | + ((r >> 6) )); + } +} + +static FASTCALL void +fbStore_a2r2g2b2 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD8 *pixel = ((CARD8 *) bits) + x; + for (i = 0; i < width; ++i) { + Splita(values[i]); + *pixel++ = (((a ) & 0xc0) | + ((r >> 2) & 0x30) | + ((g >> 4) & 0x0c) | + ((b >> 6) )); + } +} + +static FASTCALL void +fbStore_c8 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + CARD8 *pixel = ((CARD8 *) bits) + x; + for (i = 0; i < width; ++i) { + *pixel++ = miIndexToEnt24(indexed,values[i]); + } +} + +#define Store8(l,o,v) (((CARD8 *) l)[(o) >> 3] = (v)) +#if IMAGE_BYTE_ORDER == MSBFirst +#define Store4(l,o,v) Store8(l,o,((o) & 4 ? \ + (Fetch8(l,o) & 0xf0) | (v) : \ + (Fetch8(l,o) & 0x0f) | ((v) << 4))) +#else +#define Store4(l,o,v) Store8(l,o,((o) & 4 ? \ + (Fetch8(l,o) & 0x0f) | ((v) << 4) : \ + (Fetch8(l,o) & 0xf0) | (v))) +#endif + +static FASTCALL void +fbStore_a4 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + for (i = 0; i < width; ++i) { + Store4(bits, i + x, values[i]>>28); + } +} + +static FASTCALL void +fbStore_r1g2b1 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 pixel; + + Split(values[i]); + pixel = (((r >> 4) & 0x8) | + ((g >> 5) & 0x6) | + ((b >> 7) )); + Store4(bits, i + x, pixel); + } +} + +static FASTCALL void +fbStore_b1g2r1 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 pixel; + + Split(values[i]); + pixel = (((b >> 4) & 0x8) | + ((g >> 5) & 0x6) | + ((r >> 7) )); + Store4(bits, i + x, pixel); + } +} + +static FASTCALL void +fbStore_a1r1g1b1 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 pixel; + Splita(values[i]); + pixel = (((a >> 4) & 0x8) | + ((r >> 5) & 0x4) | + ((g >> 6) & 0x2) | + ((b >> 7) )); + Store4(bits, i + x, pixel); + } +} + +static FASTCALL void +fbStore_a1b1g1r1 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 pixel; + Splita(values[i]); + pixel = (((a >> 4) & 0x8) | + ((b >> 5) & 0x4) | + ((g >> 6) & 0x2) | + ((r >> 7) )); + Store4(bits, i + x, pixel); + } +} + +static FASTCALL void +fbStore_c4 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 pixel; + + pixel = miIndexToEnt24(indexed, values[i]); + Store4(bits, i + x, pixel); + } +} + +static FASTCALL void +fbStore_a1 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 *pixel = ((CARD32 *) bits) + ((i+x) >> 5); + CARD32 mask = FbStipMask((i+x) & 0x1f, 1); + + CARD32 v = values[i] & 0x80000000 ? mask : 0; + *pixel = (*pixel & ~mask) | v; + } +} + +static FASTCALL void +fbStore_g1 (FbBits *bits, const CARD32 *values, int x, int width, miIndexedPtr indexed) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 *pixel = ((CARD32 *) bits) + ((i+x) >> 5); + CARD32 mask = FbStipMask((i+x) & 0x1f, 1); + + CARD32 v = miIndexToEntY24(indexed,values[i]) ? mask : 0; + *pixel = (*pixel & ~mask) | v; + } +} + + +static storeProc storeProcForPicture (PicturePtr pict) +{ + switch(pict->format_code) { + case PICT_a8r8g8b8: return fbStore_a8r8g8b8; + case PICT_x8r8g8b8: return fbStore_x8r8g8b8; + case PICT_a8b8g8r8: return fbStore_a8b8g8r8; + case PICT_x8b8g8r8: return fbStore_x8b8g8r8; + + /* 24bpp formats */ + case PICT_r8g8b8: return fbStore_r8g8b8; + case PICT_b8g8r8: return fbStore_b8g8r8; + + /* 16bpp formats */ + case PICT_r5g6b5: return fbStore_r5g6b5; + case PICT_b5g6r5: return fbStore_b5g6r5; + + case PICT_a1r5g5b5: return fbStore_a1r5g5b5; + case PICT_x1r5g5b5: return fbStore_x1r5g5b5; + case PICT_a1b5g5r5: return fbStore_a1b5g5r5; + case PICT_x1b5g5r5: return fbStore_x1b5g5r5; + case PICT_a4r4g4b4: return fbStore_a4r4g4b4; + case PICT_x4r4g4b4: return fbStore_x4r4g4b4; + case PICT_a4b4g4r4: return fbStore_a4b4g4r4; + case PICT_x4b4g4r4: return fbStore_x4b4g4r4; + + /* 8bpp formats */ + case PICT_a8: return fbStore_a8; + case PICT_r3g3b2: return fbStore_r3g3b2; + case PICT_b2g3r3: return fbStore_b2g3r3; + case PICT_a2r2g2b2: return fbStore_a2r2g2b2; + case PICT_c8: return fbStore_c8; + case PICT_g8: return fbStore_c8; + + /* 4bpp formats */ + case PICT_a4: return fbStore_a4; + case PICT_r1g2b1: return fbStore_r1g2b1; + case PICT_b1g2r1: return fbStore_b1g2r1; + case PICT_a1r1g1b1: return fbStore_a1r1g1b1; + case PICT_a1b1g1r1: return fbStore_a1b1g1r1; + case PICT_c4: return fbStore_c4; + case PICT_g4: return fbStore_c4; + + /* 1bpp formats */ + case PICT_a1: return fbStore_a1; + case PICT_g1: return fbStore_g1; + default: + return 0; + } +} + + +/* + * Combine src and mask + */ +static FASTCALL void +fbCombineMaskU (CARD32 *src, const CARD32 *mask, int width) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 a = mask[i] >> 24; + CARD32 s = src[i]; + FbByteMul(s, a); + src[i] = s; + } +} + +/* + * All of the composing functions + */ + +static FASTCALL void +fbCombineClear (CARD32 *dest, const CARD32 *src, int width) +{ + memset(dest, 0, width*sizeof(CARD32)); +} + +static FASTCALL void +fbCombineSrcU (CARD32 *dest, const CARD32 *src, int width) +{ + memcpy(dest, src, width*sizeof(CARD32)); +} + + +static FASTCALL void +fbCombineOverU (CARD32 *dest, const CARD32 *src, int width) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD32 d = dest[i]; + CARD32 ia = Alpha(~s); + + FbByteMulAdd(d, ia, s); + dest[i] = d; + } +} + +static FASTCALL void +fbCombineOverReverseU (CARD32 *dest, const CARD32 *src, int width) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD32 d = dest[i]; + CARD32 ia = Alpha(~dest[i]); + FbByteMulAdd(s, ia, d); + dest[i] = s; + } +} + +static FASTCALL void +fbCombineInU (CARD32 *dest, const CARD32 *src, int width) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD32 a = Alpha(dest[i]); + FbByteMul(s, a); + dest[i] = s; + } +} + +static FASTCALL void +fbCombineInReverseU (CARD32 *dest, const CARD32 *src, int width) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 d = dest[i]; + CARD32 a = Alpha(src[i]); + FbByteMul(d, a); + dest[i] = d; + } +} + +static FASTCALL void +fbCombineOutU (CARD32 *dest, const CARD32 *src, int width) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD32 a = Alpha(~dest[i]); + FbByteMul(s, a); + dest[i] = s; + } +} + +static FASTCALL void +fbCombineOutReverseU (CARD32 *dest, const CARD32 *src, int width) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 d = dest[i]; + CARD32 a = Alpha(~src[i]); + FbByteMul(d, a); + dest[i] = d; + } +} + +static FASTCALL void +fbCombineAtopU (CARD32 *dest, const CARD32 *src, int width) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD32 d = dest[i]; + CARD32 dest_a = Alpha(d); + CARD32 src_ia = Alpha(~s); + + FbByteAddMul(s, dest_a, d, src_ia); + dest[i] = s; + } +} + +static FASTCALL void +fbCombineAtopReverseU (CARD32 *dest, const CARD32 *src, int width) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD32 d = dest[i]; + CARD32 src_a = Alpha(s); + CARD32 dest_ia = Alpha(~d); + + FbByteAddMul(s, dest_ia, d, src_a); + dest[i] = s; + } +} + +static FASTCALL void +fbCombineXorU (CARD32 *dest, const CARD32 *src, int width) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD32 d = dest[i]; + CARD32 src_ia = Alpha(~s); + CARD32 dest_ia = Alpha(~d); + + FbByteAddMul(s, dest_ia, d, src_ia); + dest[i] = s; + } +} + +static FASTCALL void +fbCombineAddU (CARD32 *dest, const CARD32 *src, int width) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD32 d = dest[i]; + FbByteAdd(d, s); + dest[i] = d; + } +} + +static FASTCALL void +fbCombineSaturateU (CARD32 *dest, const CARD32 *src, int width) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD32 d = dest[i]; + CARD16 sa, da; + + sa = s >> 24; + da = ~d >> 24; + if (sa > da) + { + sa = FbIntDiv(da, sa); + FbByteMul(s, sa); + } + FbByteAdd(d, s); + dest[i] = d; + } +} + +/* + * All of the disjoint composing functions + + The four entries in the first column indicate what source contributions + come from each of the four areas of the picture -- areas covered by neither + A nor B, areas covered only by A, areas covered only by B and finally + areas covered by both A and B. + + Disjoint Conjoint + Fa Fb Fa Fb +(0,0,0,0) 0 0 0 0 +(0,A,0,A) 1 0 1 0 +(0,0,B,B) 0 1 0 1 +(0,A,B,A) 1 min((1-a)/b,1) 1 max(1-a/b,0) +(0,A,B,B) min((1-b)/a,1) 1 max(1-b/a,0) 1 +(0,0,0,A) max(1-(1-b)/a,0) 0 min(1,b/a) 0 +(0,0,0,B) 0 max(1-(1-a)/b,0) 0 min(a/b,1) +(0,A,0,0) min(1,(1-b)/a) 0 max(1-b/a,0) 0 +(0,0,B,0) 0 min(1,(1-a)/b) 0 max(1-a/b,0) +(0,0,B,A) max(1-(1-b)/a,0) min(1,(1-a)/b) min(1,b/a) max(1-a/b,0) +(0,A,0,B) min(1,(1-b)/a) max(1-(1-a)/b,0) max(1-b/a,0) min(1,a/b) +(0,A,B,0) min(1,(1-b)/a) min(1,(1-a)/b) max(1-b/a,0) max(1-a/b,0) + + */ + +#define CombineAOut 1 +#define CombineAIn 2 +#define CombineBOut 4 +#define CombineBIn 8 + +#define CombineClear 0 +#define CombineA (CombineAOut|CombineAIn) +#define CombineB (CombineBOut|CombineBIn) +#define CombineAOver (CombineAOut|CombineBOut|CombineAIn) +#define CombineBOver (CombineAOut|CombineBOut|CombineBIn) +#define CombineAAtop (CombineBOut|CombineAIn) +#define CombineBAtop (CombineAOut|CombineBIn) +#define CombineXor (CombineAOut|CombineBOut) + +/* portion covered by a but not b */ +static INLINE CARD8 +fbCombineDisjointOutPart (CARD8 a, CARD8 b) +{ + /* min (1, (1-b) / a) */ + + b = ~b; /* 1 - b */ + if (b >= a) /* 1 - b >= a -> (1-b)/a >= 1 */ + return 0xff; /* 1 */ + return FbIntDiv(b,a); /* (1-b) / a */ +} + +/* portion covered by both a and b */ +static INLINE CARD8 +fbCombineDisjointInPart (CARD8 a, CARD8 b) +{ + /* max (1-(1-b)/a,0) */ + /* = - min ((1-b)/a - 1, 0) */ + /* = 1 - min (1, (1-b)/a) */ + + b = ~b; /* 1 - b */ + if (b >= a) /* 1 - b >= a -> (1-b)/a >= 1 */ + return 0; /* 1 - 1 */ + return ~FbIntDiv(b,a); /* 1 - (1-b) / a */ +} + +static FASTCALL void +fbCombineDisjointGeneralU (CARD32 *dest, const CARD32 *src, int width, CARD8 combine) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD32 d = dest[i]; + CARD32 m,n,o,p; + CARD16 Fa, Fb, t, u, v; + CARD8 sa = s >> 24; + CARD8 da = d >> 24; + + switch (combine & CombineA) { + default: + Fa = 0; + break; + case CombineAOut: + Fa = fbCombineDisjointOutPart (sa, da); + break; + case CombineAIn: + Fa = fbCombineDisjointInPart (sa, da); + break; + case CombineA: + Fa = 0xff; + break; + } + + switch (combine & CombineB) { + default: + Fb = 0; + break; + case CombineBOut: + Fb = fbCombineDisjointOutPart (da, sa); + break; + case CombineBIn: + Fb = fbCombineDisjointInPart (da, sa); + break; + case CombineB: + Fb = 0xff; + break; + } + m = FbGen (s,d,0,Fa,Fb,t, u, v); + n = FbGen (s,d,8,Fa,Fb,t, u, v); + o = FbGen (s,d,16,Fa,Fb,t, u, v); + p = FbGen (s,d,24,Fa,Fb,t, u, v); + s = m|n|o|p; + dest[i] = s; + } +} + +static FASTCALL void +fbCombineDisjointOverU (CARD32 *dest, const CARD32 *src, int width) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD16 a = s >> 24; + + if (a != 0x00) + { + if (a != 0xff) + { + CARD32 d = dest[i]; + a = fbCombineDisjointOutPart (d >> 24, a); + FbByteMulAdd(d, a, s); + s = d; + } + dest[i] = s; + } + } +} + +static FASTCALL void +fbCombineDisjointInU (CARD32 *dest, const CARD32 *src, int width) +{ + fbCombineDisjointGeneralU (dest, src, width, CombineAIn); +} + +static FASTCALL void +fbCombineDisjointInReverseU (CARD32 *dest, const CARD32 *src, int width) +{ + fbCombineDisjointGeneralU (dest, src, width, CombineBIn); +} + +static FASTCALL void +fbCombineDisjointOutU (CARD32 *dest, const CARD32 *src, int width) +{ + fbCombineDisjointGeneralU (dest, src, width, CombineAOut); +} + +static FASTCALL void +fbCombineDisjointOutReverseU (CARD32 *dest, const CARD32 *src, int width) +{ + fbCombineDisjointGeneralU (dest, src, width, CombineBOut); +} + +static FASTCALL void +fbCombineDisjointAtopU (CARD32 *dest, const CARD32 *src, int width) +{ + fbCombineDisjointGeneralU (dest, src, width, CombineAAtop); +} + +static FASTCALL void +fbCombineDisjointAtopReverseU (CARD32 *dest, const CARD32 *src, int width) +{ + fbCombineDisjointGeneralU (dest, src, width, CombineBAtop); +} + +static FASTCALL void +fbCombineDisjointXorU (CARD32 *dest, const CARD32 *src, int width) +{ + fbCombineDisjointGeneralU (dest, src, width, CombineXor); +} + +/* portion covered by a but not b */ +static INLINE CARD8 +fbCombineConjointOutPart (CARD8 a, CARD8 b) +{ + /* max (1-b/a,0) */ + /* = 1-min(b/a,1) */ + + /* min (1, (1-b) / a) */ + + if (b >= a) /* b >= a -> b/a >= 1 */ + return 0x00; /* 0 */ + return ~FbIntDiv(b,a); /* 1 - b/a */ +} + +/* portion covered by both a and b */ +static INLINE CARD8 +fbCombineConjointInPart (CARD8 a, CARD8 b) +{ + /* min (1,b/a) */ + + if (b >= a) /* b >= a -> b/a >= 1 */ + return 0xff; /* 1 */ + return FbIntDiv(b,a); /* b/a */ +} + +static FASTCALL void +fbCombineConjointGeneralU (CARD32 *dest, const CARD32 *src, int width, CARD8 combine) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD32 d = dest[i]; + CARD32 m,n,o,p; + CARD16 Fa, Fb, t, u, v; + CARD8 sa = s >> 24; + CARD8 da = d >> 24; + + switch (combine & CombineA) { + default: + Fa = 0; + break; + case CombineAOut: + Fa = fbCombineConjointOutPart (sa, da); + break; + case CombineAIn: + Fa = fbCombineConjointInPart (sa, da); + break; + case CombineA: + Fa = 0xff; + break; + } + + switch (combine & CombineB) { + default: + Fb = 0; + break; + case CombineBOut: + Fb = fbCombineConjointOutPart (da, sa); + break; + case CombineBIn: + Fb = fbCombineConjointInPart (da, sa); + break; + case CombineB: + Fb = 0xff; + break; + } + m = FbGen (s,d,0,Fa,Fb,t, u, v); + n = FbGen (s,d,8,Fa,Fb,t, u, v); + o = FbGen (s,d,16,Fa,Fb,t, u, v); + p = FbGen (s,d,24,Fa,Fb,t, u, v); + s = m|n|o|p; + dest[i] = s; + } +} + +static FASTCALL void +fbCombineConjointOverU (CARD32 *dest, const CARD32 *src, int width) +{ + fbCombineConjointGeneralU (dest, src, width, CombineAOver); +} + + +static FASTCALL void +fbCombineConjointOverReverseU (CARD32 *dest, const CARD32 *src, int width) +{ + fbCombineConjointGeneralU (dest, src, width, CombineBOver); +} + + +static FASTCALL void +fbCombineConjointInU (CARD32 *dest, const CARD32 *src, int width) +{ + fbCombineConjointGeneralU (dest, src, width, CombineAIn); +} + + +static FASTCALL void +fbCombineConjointInReverseU (CARD32 *dest, const CARD32 *src, int width) +{ + fbCombineConjointGeneralU (dest, src, width, CombineBIn); +} + +static FASTCALL void +fbCombineConjointOutU (CARD32 *dest, const CARD32 *src, int width) +{ + fbCombineConjointGeneralU (dest, src, width, CombineAOut); +} + +static FASTCALL void +fbCombineConjointOutReverseU (CARD32 *dest, const CARD32 *src, int width) +{ + fbCombineConjointGeneralU (dest, src, width, CombineBOut); +} + +static FASTCALL void +fbCombineConjointAtopU (CARD32 *dest, const CARD32 *src, int width) +{ + fbCombineConjointGeneralU (dest, src, width, CombineAAtop); +} + +static FASTCALL void +fbCombineConjointAtopReverseU (CARD32 *dest, const CARD32 *src, int width) +{ + fbCombineConjointGeneralU (dest, src, width, CombineBAtop); +} + +static FASTCALL void +fbCombineConjointXorU (CARD32 *dest, const CARD32 *src, int width) +{ + fbCombineConjointGeneralU (dest, src, width, CombineXor); +} + +static CombineFuncU fbCombineFuncU[] = { + fbCombineClear, + fbCombineSrcU, + 0, /* CombineDst */ + fbCombineOverU, + fbCombineOverReverseU, + fbCombineInU, + fbCombineInReverseU, + fbCombineOutU, + fbCombineOutReverseU, + fbCombineAtopU, + fbCombineAtopReverseU, + fbCombineXorU, + fbCombineAddU, + fbCombineSaturateU, + 0, + 0, + fbCombineClear, + fbCombineSrcU, + 0, /* CombineDst */ + fbCombineDisjointOverU, + fbCombineSaturateU, /* DisjointOverReverse */ + fbCombineDisjointInU, + fbCombineDisjointInReverseU, + fbCombineDisjointOutU, + fbCombineDisjointOutReverseU, + fbCombineDisjointAtopU, + fbCombineDisjointAtopReverseU, + fbCombineDisjointXorU, + 0, + 0, + 0, + 0, + fbCombineClear, + fbCombineSrcU, + 0, /* CombineDst */ + fbCombineConjointOverU, + fbCombineConjointOverReverseU, + fbCombineConjointInU, + fbCombineConjointInReverseU, + fbCombineConjointOutU, + fbCombineConjointOutReverseU, + fbCombineConjointAtopU, + fbCombineConjointAtopReverseU, + fbCombineConjointXorU, +}; + +static FASTCALL void +fbCombineMaskC (CARD32 *src, CARD32 *mask, int width) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 a = mask[i]; + + CARD32 x; + CARD16 xa; + + if (!a) + { + src[i] = 0; + continue; + } + + x = src[i]; + if (a == 0xffffffff) + { + x = x >> 24; + x |= x << 8; + x |= x << 16; + mask[i] = x; + continue; + } + + xa = x >> 24; + FbByteMulC(x, a); + src[i] = x; + FbByteMul(a, xa); + mask[i] = a; + } +} + +static FASTCALL void +fbCombineMaskValueC (CARD32 *src, const CARD32 *mask, int width) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 a = mask[i]; + CARD32 x; + + if (!a) + { + src[i] = 0; + continue; + } + + if (a == 0xffffffff) + continue; + + x = src[i]; + FbByteMulC(x, a); + src[i] = x; + } +} + + +static FASTCALL void +fbCombineMaskAlphaC (const CARD32 *src, CARD32 *mask, int width) +{ + int i; + for (i = 0; i < width; ++i) { + CARD32 a = mask[i]; + CARD32 x; + + if (!a) + continue; + + x = src[i] >> 24; + if (x == 0xff) + continue; + if (a == 0xffffffff) + { + x = x >> 24; + x |= x << 8; + x |= x << 16; + mask[i] = x; + continue; + } + + FbByteMul(a, x); + mask[i] = a; + } +} + +static FASTCALL void +fbCombineClearC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + memset(dest, 0, width*sizeof(CARD32)); +} + +static FASTCALL void +fbCombineSrcC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineMaskValueC(src, mask, width); + memcpy(dest, src, width*sizeof(CARD32)); +} + +static FASTCALL void +fbCombineOverC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + int i; + fbCombineMaskC(src, mask, width); + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD32 a = ~mask[i]; + + if (a != 0xffffffff) + { + if (a) + { + CARD32 d = dest[i]; + FbByteMulAddC(d, a, s); + s = d; + } + dest[i] = s; + } + } +} + +static FASTCALL void +fbCombineOverReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + int i; + fbCombineMaskValueC(src, mask, width); + for (i = 0; i < width; ++i) { + CARD32 d = dest[i]; + CARD32 a = ~d >> 24; + + if (a) + { + CARD32 s = src[i]; + if (a != 0xff) + { + FbByteMulAdd(s, a, d); + } + dest[i] = s; + } + } +} + +static FASTCALL void +fbCombineInC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + int i; + fbCombineMaskValueC(src, mask, width); + for (i = 0; i < width; ++i) { + CARD32 d = dest[i]; + CARD16 a = d >> 24; + CARD32 s = 0; + if (a) + { + s = src[i]; + if (a != 0xff) + { + FbByteMul(s, a); + } + } + dest[i] = s; + } +} + +static FASTCALL void +fbCombineInReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + int i; + fbCombineMaskAlphaC(src, mask, width); + for (i = 0; i < width; ++i) { + CARD32 a = mask[i]; + + if (a != 0xffffffff) + { + CARD32 d = 0; + if (a) + { + d = dest[i]; + FbByteMulC(d, a); + } + dest[i] = d; + } + } +} + +static FASTCALL void +fbCombineOutC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + int i; + fbCombineMaskValueC(src, mask, width); + for (i = 0; i < width; ++i) { + CARD32 d = dest[i]; + CARD16 a = ~d >> 24; + CARD32 s = 0; + if (a) + { + s = src[i]; + if (a != 0xff) + { + FbByteMul(s, a); + } + } + dest[i] = s; + } +} + +static FASTCALL void +fbCombineOutReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + int i; + fbCombineMaskAlphaC(src, mask, width); + for (i = 0; i < width; ++i) { + CARD32 a = ~mask[i]; + + if (a != 0xffffffff) + { + CARD32 d = 0; + if (a) + { + d = dest[i]; + FbByteMulC(d, a); + } + dest[i] = d; + } + } +} + +static FASTCALL void +fbCombineAtopC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + int i; + fbCombineMaskC(src, mask, width); + for (i = 0; i < width; ++i) { + CARD32 d = dest[i]; + CARD32 s = src[i]; + CARD32 ad = ~mask[i]; + CARD16 as = d >> 24; + FbByteAddMulC(d, ad, s, as); + dest[i] = d; + } +} + +static FASTCALL void +fbCombineAtopReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + int i; + fbCombineMaskC(src, mask, width); + for (i = 0; i < width; ++i) { + + CARD32 d = dest[i]; + CARD32 s = src[i]; + CARD32 ad = mask[i]; + CARD16 as = ~d >> 24; + FbByteAddMulC(d, ad, s, as); + dest[i] = d; + } +} + +static FASTCALL void +fbCombineXorC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + int i; + fbCombineMaskC(src, mask, width); + for (i = 0; i < width; ++i) { + CARD32 d = dest[i]; + CARD32 s = src[i]; + CARD32 ad = ~mask[i]; + CARD16 as = ~d >> 24; + FbByteAddMulC(d, ad, s, as); + dest[i] = d; + } +} + +static FASTCALL void +fbCombineAddC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + int i; + fbCombineMaskValueC(src, mask, width); + for (i = 0; i < width; ++i) { + CARD32 s = src[i]; + CARD32 d = dest[i]; + FbByteAdd(d, s); + dest[i] = d; + } +} + +static FASTCALL void +fbCombineSaturateC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + int i; + fbCombineMaskC(src, mask, width); + for (i = 0; i < width; ++i) { + CARD32 s, d; + CARD16 sa, sr, sg, sb, da; + CARD16 t, u, v; + CARD32 m,n,o,p; + + d = dest[i]; + s = src[i]; + sa = (mask[i] >> 24); + sr = (mask[i] >> 16) & 0xff; + sg = (mask[i] >> 8) & 0xff; + sb = (mask[i] ) & 0xff; + da = ~d >> 24; + + if (sb <= da) + m = FbAdd(s,d,0,t); + else + m = FbGen (s, d, 0, (da << 8) / sb, 0xff, t, u, v); + + if (sg <= da) + n = FbAdd(s,d,8,t); + else + n = FbGen (s, d, 8, (da << 8) / sg, 0xff, t, u, v); + + if (sr <= da) + o = FbAdd(s,d,16,t); + else + o = FbGen (s, d, 16, (da << 8) / sr, 0xff, t, u, v); + + if (sa <= da) + p = FbAdd(s,d,24,t); + else + p = FbGen (s, d, 24, (da << 8) / sa, 0xff, t, u, v); + + dest[i] = m|n|o|p; + } +} + +static FASTCALL void +fbCombineDisjointGeneralC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width, CARD8 combine) +{ + int i; + fbCombineMaskC(src, mask, width); + for (i = 0; i < width; ++i) { + CARD32 s, d; + CARD32 m,n,o,p; + CARD32 Fa, Fb; + CARD16 t, u, v; + CARD32 sa; + CARD8 da; + + s = src[i]; + sa = mask[i]; + d = dest[i]; + da = d >> 24; + + switch (combine & CombineA) { + default: + Fa = 0; + break; + case CombineAOut: + m = fbCombineDisjointOutPart ((CARD8) (sa >> 0), da); + n = fbCombineDisjointOutPart ((CARD8) (sa >> 8), da) << 8; + o = fbCombineDisjointOutPart ((CARD8) (sa >> 16), da) << 16; + p = fbCombineDisjointOutPart ((CARD8) (sa >> 24), da) << 24; + Fa = m|n|o|p; + break; + case CombineAIn: + m = fbCombineDisjointInPart ((CARD8) (sa >> 0), da); + n = fbCombineDisjointInPart ((CARD8) (sa >> 8), da) << 8; + o = fbCombineDisjointInPart ((CARD8) (sa >> 16), da) << 16; + p = fbCombineDisjointInPart ((CARD8) (sa >> 24), da) << 24; + Fa = m|n|o|p; + break; + case CombineA: + Fa = 0xffffffff; + break; + } + + switch (combine & CombineB) { + default: + Fb = 0; + break; + case CombineBOut: + m = fbCombineDisjointOutPart (da, (CARD8) (sa >> 0)); + n = fbCombineDisjointOutPart (da, (CARD8) (sa >> 8)) << 8; + o = fbCombineDisjointOutPart (da, (CARD8) (sa >> 16)) << 16; + p = fbCombineDisjointOutPart (da, (CARD8) (sa >> 24)) << 24; + Fb = m|n|o|p; + break; + case CombineBIn: + m = fbCombineDisjointInPart (da, (CARD8) (sa >> 0)); + n = fbCombineDisjointInPart (da, (CARD8) (sa >> 8)) << 8; + o = fbCombineDisjointInPart (da, (CARD8) (sa >> 16)) << 16; + p = fbCombineDisjointInPart (da, (CARD8) (sa >> 24)) << 24; + Fb = m|n|o|p; + break; + case CombineB: + Fb = 0xffffffff; + break; + } + m = FbGen (s,d,0,FbGet8(Fa,0),FbGet8(Fb,0),t, u, v); + n = FbGen (s,d,8,FbGet8(Fa,8),FbGet8(Fb,8),t, u, v); + o = FbGen (s,d,16,FbGet8(Fa,16),FbGet8(Fb,16),t, u, v); + p = FbGen (s,d,24,FbGet8(Fa,24),FbGet8(Fb,24),t, u, v); + s = m|n|o|p; + dest[i] = s; + } +} + +static FASTCALL void +fbCombineDisjointOverC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineDisjointGeneralC (dest, src, mask, width, CombineAOver); +} + +static FASTCALL void +fbCombineDisjointInC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineDisjointGeneralC (dest, src, mask, width, CombineAIn); +} + +static FASTCALL void +fbCombineDisjointInReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineDisjointGeneralC (dest, src, mask, width, CombineBIn); +} + +static FASTCALL void +fbCombineDisjointOutC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineDisjointGeneralC (dest, src, mask, width, CombineAOut); +} + +static FASTCALL void +fbCombineDisjointOutReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineDisjointGeneralC (dest, src, mask, width, CombineBOut); +} + +static FASTCALL void +fbCombineDisjointAtopC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineDisjointGeneralC (dest, src, mask, width, CombineAAtop); +} + +static FASTCALL void +fbCombineDisjointAtopReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineDisjointGeneralC (dest, src, mask, width, CombineBAtop); +} + +static FASTCALL void +fbCombineDisjointXorC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineDisjointGeneralC (dest, src, mask, width, CombineXor); +} + +static FASTCALL void +fbCombineConjointGeneralC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width, CARD8 combine) +{ + int i; + fbCombineMaskC(src, mask, width); + for (i = 0; i < width; ++i) { + CARD32 s, d; + CARD32 m,n,o,p; + CARD32 Fa, Fb; + CARD16 t, u, v; + CARD32 sa; + CARD8 da; + + s = src[i]; + sa = mask[i]; + d = dest[i]; + da = d >> 24; + + switch (combine & CombineA) { + default: + Fa = 0; + break; + case CombineAOut: + m = fbCombineConjointOutPart ((CARD8) (sa >> 0), da); + n = fbCombineConjointOutPart ((CARD8) (sa >> 8), da) << 8; + o = fbCombineConjointOutPart ((CARD8) (sa >> 16), da) << 16; + p = fbCombineConjointOutPart ((CARD8) (sa >> 24), da) << 24; + Fa = m|n|o|p; + break; + case CombineAIn: + m = fbCombineConjointInPart ((CARD8) (sa >> 0), da); + n = fbCombineConjointInPart ((CARD8) (sa >> 8), da) << 8; + o = fbCombineConjointInPart ((CARD8) (sa >> 16), da) << 16; + p = fbCombineConjointInPart ((CARD8) (sa >> 24), da) << 24; + Fa = m|n|o|p; + break; + case CombineA: + Fa = 0xffffffff; + break; + } + + switch (combine & CombineB) { + default: + Fb = 0; + break; + case CombineBOut: + m = fbCombineConjointOutPart (da, (CARD8) (sa >> 0)); + n = fbCombineConjointOutPart (da, (CARD8) (sa >> 8)) << 8; + o = fbCombineConjointOutPart (da, (CARD8) (sa >> 16)) << 16; + p = fbCombineConjointOutPart (da, (CARD8) (sa >> 24)) << 24; + Fb = m|n|o|p; + break; + case CombineBIn: + m = fbCombineConjointInPart (da, (CARD8) (sa >> 0)); + n = fbCombineConjointInPart (da, (CARD8) (sa >> 8)) << 8; + o = fbCombineConjointInPart (da, (CARD8) (sa >> 16)) << 16; + p = fbCombineConjointInPart (da, (CARD8) (sa >> 24)) << 24; + Fb = m|n|o|p; + break; + case CombineB: + Fb = 0xffffffff; + break; + } + m = FbGen (s,d,0,FbGet8(Fa,0),FbGet8(Fb,0),t, u, v); + n = FbGen (s,d,8,FbGet8(Fa,8),FbGet8(Fb,8),t, u, v); + o = FbGen (s,d,16,FbGet8(Fa,16),FbGet8(Fb,16),t, u, v); + p = FbGen (s,d,24,FbGet8(Fa,24),FbGet8(Fb,24),t, u, v); + s = m|n|o|p; + dest[i] = s; + } +} + +static FASTCALL void +fbCombineConjointOverC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineConjointGeneralC (dest, src, mask, width, CombineAOver); +} + +static FASTCALL void +fbCombineConjointOverReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineConjointGeneralC (dest, src, mask, width, CombineBOver); +} + +static FASTCALL void +fbCombineConjointInC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineConjointGeneralC (dest, src, mask, width, CombineAIn); +} + +static FASTCALL void +fbCombineConjointInReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineConjointGeneralC (dest, src, mask, width, CombineBIn); +} + +static FASTCALL void +fbCombineConjointOutC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineConjointGeneralC (dest, src, mask, width, CombineAOut); +} + +static FASTCALL void +fbCombineConjointOutReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineConjointGeneralC (dest, src, mask, width, CombineBOut); +} + +static FASTCALL void +fbCombineConjointAtopC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineConjointGeneralC (dest, src, mask, width, CombineAAtop); +} + +static FASTCALL void +fbCombineConjointAtopReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineConjointGeneralC (dest, src, mask, width, CombineBAtop); +} + +static FASTCALL void +fbCombineConjointXorC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + fbCombineConjointGeneralC (dest, src, mask, width, CombineXor); +} + +static CombineFuncC fbCombineFuncC[] = { + fbCombineClearC, + fbCombineSrcC, + 0, /* Dest */ + fbCombineOverC, + fbCombineOverReverseC, + fbCombineInC, + fbCombineInReverseC, + fbCombineOutC, + fbCombineOutReverseC, + fbCombineAtopC, + fbCombineAtopReverseC, + fbCombineXorC, + fbCombineAddC, + fbCombineSaturateC, + 0, + 0, + fbCombineClearC, /* 0x10 */ + fbCombineSrcC, + 0, /* Dest */ + fbCombineDisjointOverC, + fbCombineSaturateC, /* DisjointOverReverse */ + fbCombineDisjointInC, + fbCombineDisjointInReverseC, + fbCombineDisjointOutC, + fbCombineDisjointOutReverseC, + fbCombineDisjointAtopC, + fbCombineDisjointAtopReverseC, + fbCombineDisjointXorC, /* 0x1b */ + 0, + 0, + 0, + 0, + fbCombineClearC, + fbCombineSrcC, + 0, /* Dest */ + fbCombineConjointOverC, + fbCombineConjointOverReverseC, + fbCombineConjointInC, + fbCombineConjointInReverseC, + fbCombineConjointOutC, + fbCombineConjointOutReverseC, + fbCombineConjointAtopC, + fbCombineConjointAtopReverseC, + fbCombineConjointXorC, +}; + + +FbComposeFunctions composeFunctions = { + fbCombineFuncU, + fbCombineFuncC, + fbCombineMaskU +}; + + +static void fbFetchSolid(PicturePtr pict, int x, int y, int width, CARD32 *buffer) +{ + FbBits *bits; + FbStride stride; + int bpp; + int xoff, yoff; + CARD32 color; + CARD32 *end; + fetchPixelProc fetch = fetchPixelProcForPicture(pict); +#ifdef PIXMAN_INDEXED_FORMATS + miIndexedPtr indexed = (miIndexedPtr) pict->pFormat->index.devPrivate; +#else + miIndexedPtr indexed = 0; +#endif + + fbGetDrawable (pict->pDrawable, bits, stride, bpp, xoff, yoff); + bits += yoff*stride + (xoff*bpp >> FB_SHIFT); + + color = fetch(bits, 0, indexed); + + end = buffer + width; + while (buffer < end) + *buffer++ = color; +} + +static void fbFetch(PicturePtr pict, int x, int y, int width, CARD32 *buffer) +{ + FbBits *bits; + FbStride stride; + int bpp; + int xoff, yoff; + fetchProc fetch = fetchProcForPicture(pict); +#ifdef PIXMAN_INDEXED_FORMATS + miIndexedPtr indexed = (miIndexedPtr) pict->pFormat->index.devPrivate; +#else + miIndexedPtr indexed = 0; +#endif + + fbGetDrawable (pict->pDrawable, bits, stride, bpp, xoff, yoff); + x += xoff; + y += yoff; + + bits += y*stride; + + fetch(bits, x, width, buffer, indexed); +} + +#define DIV(a,b) ((((a) < 0) == ((b) < 0)) ? (a) / (b) :\ + ((a) - (b) + 1 - (((b) < 0) << 1)) / (b)) + +#ifdef PIXMAN_GRADIENTS +static CARD32 gradientPixel(const SourcePictPtr pGradient, xFixed_48_16 pos, unsigned int spread) +{ + int ipos = (pos * PICT_GRADIENT_STOPTABLE_SIZE - 1) >> 16; + + /* calculate the actual offset. */ + if (ipos < 0 || ipos >= PICT_GRADIENT_STOPTABLE_SIZE) { + if (pGradient->type == SourcePictTypeConical || spread == RepeatNormal) { + ipos = ipos % PICT_GRADIENT_STOPTABLE_SIZE; + ipos = ipos < 0 ? PICT_GRADIENT_STOPTABLE_SIZE + ipos : ipos; + + } else if (spread == RepeatReflect) { + const int limit = PICT_GRADIENT_STOPTABLE_SIZE * 2 - 1; + ipos = ipos % limit; + ipos = ipos < 0 ? limit + ipos : ipos; + ipos = ipos >= PICT_GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos; + + } else if (spread == RepeatPad) { + if (ipos < 0) + ipos = 0; + else if (ipos >= PICT_GRADIENT_STOPTABLE_SIZE) + ipos = PICT_GRADIENT_STOPTABLE_SIZE-1; + } else { /* RepeatNone */ + return 0; + } + } + + assert(ipos >= 0); + assert(ipos < PICT_GRADIENT_STOPTABLE_SIZE); + + return pGradient->linear.colorTable[ipos]; +} + +static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *buffer) +{ + SourcePictPtr pGradient = pict->pSourcePict; + CARD32 *end = buffer + width; + + if (pGradient->type == SourcePictTypeSolidFill) { + register CARD32 color = pGradient->solidFill.color; + while (buffer < end) { + *buffer++ = color; + } + } else if (pGradient->type == SourcePictTypeLinear) { + PictVector v, unit; + xFixed_32_32 l; + xFixed_48_16 dx, dy, a, b, off; + + v.vector[0] = IntToxFixed(x); + v.vector[1] = IntToxFixed(y); + v.vector[2] = xFixed1; + if (pict->transform) { + if (!PictureTransformPoint3d (pict->transform, &v)) + return; + unit.vector[0] = pict->transform->matrix[0][0]; + unit.vector[1] = pict->transform->matrix[1][0]; + unit.vector[2] = pict->transform->matrix[2][0]; + } else { + unit.vector[0] = xFixed1; + unit.vector[1] = 0; + unit.vector[2] = 0; + } + + dx = pGradient->linear.p2.x - pGradient->linear.p1.x; + dy = pGradient->linear.p2.y - pGradient->linear.p1.y; + l = dx*dx + dy*dy; + if (l != 0) { + a = (dx << 32) / l; + b = (dy << 32) / l; + off = (-a*pGradient->linear.p1.x - b*pGradient->linear.p1.y)>>16; + } + if (l == 0 || (unit.vector[2] == 0 && v.vector[2] == xFixed1)) { + xFixed_48_16 inc, t; + /* affine transformation only */ + if (l == 0) { + t = 0; + inc = 0; + } else { + t = ((a*v.vector[0] + b*v.vector[1]) >> 16) + off; + inc = (a * unit.vector[0] + b * unit.vector[1]) >> 16; + } + while (buffer < end) { + *buffer++ = gradientPixel(pGradient, t, pict->repeat); + t += inc; + } + } else { + /* projective transformation */ + while (buffer < end) { + xFixed_48_16 t; + if (v.vector[2] == 0) { + t = 0; + } else { + xFixed_48_16 x, y; + x = ((xFixed_48_16)v.vector[0] << 16) / v.vector[2]; + y = ((xFixed_48_16)v.vector[1] << 16) / v.vector[2]; + t = ((a*x + b*y) >> 16) + off; + } + *buffer++ = gradientPixel(pGradient, t, pict->repeat); + v.vector[0] += unit.vector[0]; + v.vector[1] += unit.vector[1]; + v.vector[2] += unit.vector[2]; + } + } + } else { + /* radial or conical */ + Bool projective = FALSE; + double cx = 1.; + double cy = 0.; + double cz = 0.; + double rx = x; + double ry = y; + double rz = 1.; + + if (pict->transform) { + PictVector v; + v.vector[0] = IntToxFixed(x); + v.vector[1] = IntToxFixed(y); + v.vector[2] = xFixed1; + if (!PictureTransformPoint3d (pict->transform, &v)) + return; + + cx = pict->transform->matrix[0][0]/65536.; + cy = pict->transform->matrix[1][0]/65536.; + cz = pict->transform->matrix[2][0]/65536.; + rx = v.vector[0]/65536.; + ry = v.vector[1]/65536.; + rz = v.vector[2]/65536.; + projective = pict->transform->matrix[2][0] != 0 || v.vector[2] != xFixed1; + } + + if (pGradient->type == SourcePictTypeRadial) { + if (!projective) { + rx -= pGradient->radial.fx; + ry -= pGradient->radial.fy; + + while (buffer < end) { + double b = 2*(rx*pGradient->radial.dx + ry*pGradient->radial.dy); + double c = -(rx*rx + ry*ry); + double det = (b * b) - (4 * pGradient->radial.a * c); + double s = (-b + sqrt(det))/(2. * pGradient->radial.a); + *buffer = gradientPixel(pGradient, + (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536), + pict->repeat); + ++buffer; + rx += cx; + ry += cy; + } + } else { + while (buffer < end) { + double x, y; + double b, c, det, s; + if (rz != 0) { + x = rx/rz; + y = ry/rz; + } else { + x = y = 0.; + } + x -= pGradient->radial.fx; + y -= pGradient->radial.fy; + b = 2*(x*pGradient->radial.dx + y*pGradient->radial.dy); + c = -(x*x + y*y); + det = (b * b) - (4 * pGradient->radial.a * c); + s = (-b + sqrt(det))/(2. * pGradient->radial.a); + *buffer = gradientPixel(pGradient, + (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536), + pict->repeat); + ++buffer; + rx += cx; + ry += cy; + rz += cz; + } + } + } else /* SourcePictTypeConical */ { + double a = pGradient->conical.angle/(180.*65536); + if (!projective) { + rx -= pGradient->conical.center.x/65536.; + ry -= pGradient->conical.center.y/65536.; + + while (buffer < end) { + double angle = atan2(ry, rx) + a; + *buffer = gradientPixel(pGradient, (xFixed_48_16) (angle * (65536. / (2*M_PI))), + pict->repeat); + ++buffer; + rx += cx; + ry += cy; + } + } else { + + while (buffer < end) { + double x, y; + if (rz != 0) { + x = rx/rz; + y = ry/rz; + } else { + x = y = 0.; + } + x -= pGradient->conical.center.x/65536.; + y -= pGradient->conical.center.y/65536.; + double angle = atan2(y, x) + a; + *buffer = gradientPixel(pGradient, (xFixed_48_16) (angle * (65536. / (2*M_PI))), + pict->repeat); + ++buffer; + rx += cx; + ry += cy; + rz += cz; + } + } + } + } +} +#endif /* PIXMAN_GRADIENTS */ + + +static void fbFetchTransformed(PicturePtr pict, int x, int y, int width, CARD32 *buffer) +{ + FbBits *bits; + FbStride stride; + int bpp; + int xoff, yoff; + fetchPixelProc fetch; + PictVector v; + PictVector unit; + int i; + BoxRec box; +#ifdef PIXMAN_INDEXED_FORMATS + miIndexedPtr indexed = (miIndexedPtr) pict->pFormat->index.devPrivate; +#else + miIndexedPtr indexed = 0; +#endif + + fetch = fetchPixelProcForPicture(pict); + + fbGetDrawable(pict->pDrawable, bits, stride, bpp, xoff, yoff); + x += xoff; + y += yoff; + + v.vector[0] = IntToxFixed(x); + v.vector[1] = IntToxFixed(y); + v.vector[2] = xFixed1; + + /* when using convolution filters one might get here without a transform */ + if (pict->transform) { + if (!PictureTransformPoint3d (pict->transform, &v)) + return; + unit.vector[0] = pict->transform->matrix[0][0]; + unit.vector[1] = pict->transform->matrix[1][0]; + unit.vector[2] = pict->transform->matrix[2][0]; + } else { + unit.vector[0] = xFixed1; + unit.vector[1] = 0; + unit.vector[2] = 0; + } + + if (pict->filter == PIXMAN_FILTER_NEAREST || pict->filter == PIXMAN_FILTER_FAST) + { + if (pict->repeat == RepeatNormal) { + if (PIXREGION_NUM_RECTS(pict->pCompositeClip) == 1) { + box = pict->pCompositeClip->extents; + for (i = 0; i < width; ++i) { + if (!v.vector[2]) { + buffer[i] = 0; + } else { + y = MOD(DIV(v.vector[1],v.vector[2]), pict->pDrawable->height); + x = MOD(DIV(v.vector[0],v.vector[2]), pict->pDrawable->width); + buffer[i] = fetch(bits + (y + pict->pDrawable->y)*stride, x + pict->pDrawable->x, indexed); + } + v.vector[0] += unit.vector[0]; + v.vector[1] += unit.vector[1]; + v.vector[2] += unit.vector[2]; + } + } else { + for (i = 0; i < width; ++i) { + if (!v.vector[2]) { + buffer[i] = 0; + } else { + y = MOD(DIV(v.vector[1],v.vector[2]), pict->pDrawable->height); + x = MOD(DIV(v.vector[0],v.vector[2]), pict->pDrawable->width); + if (pixman_region_contains_point (pict->pCompositeClip, x, y, &box)) + buffer[i] = fetch(bits + (y + pict->pDrawable->y)*stride, x + pict->pDrawable->x, indexed); + else + buffer[i] = 0; + } + v.vector[0] += unit.vector[0]; + v.vector[1] += unit.vector[1]; + v.vector[2] += unit.vector[2]; + } + } + } else { + if (PIXREGION_NUM_RECTS(pict->pCompositeClip) == 1) { + box = pict->pCompositeClip->extents; + for (i = 0; i < width; ++i) { + if (!v.vector[2]) { + buffer[i] = 0; + } else { + y = DIV(v.vector[1],v.vector[2]); + x = DIV(v.vector[0],v.vector[2]); + buffer[i] = ((x < box.x1) | (x >= box.x2) | (y < box.y1) | (y >= box.y2)) ? + 0 : fetch(bits + (y + pict->pDrawable->y)*stride, x + pict->pDrawable->x, indexed); + } + v.vector[0] += unit.vector[0]; + v.vector[1] += unit.vector[1]; + v.vector[2] += unit.vector[2]; + } + } else { + for (i = 0; i < width; ++i) { + if (!v.vector[2]) { + buffer[i] = 0; + } else { + y = DIV(v.vector[1],v.vector[2]); + x = DIV(v.vector[0],v.vector[2]); + if (pixman_region_contains_point (pict->pCompositeClip, x, y, &box)) + buffer[i] = fetch(bits + (y + pict->pDrawable->y)*stride, x + pict->pDrawable->x, indexed); + else + buffer[i] = 0; + } + v.vector[0] += unit.vector[0]; + v.vector[1] += unit.vector[1]; + v.vector[2] += unit.vector[2]; + } + } + } + } else if (pict->filter == PIXMAN_FILTER_BILINEAR || pict->filter == PIXMAN_FILTER_GOOD || pict->filter == PIXMAN_FILTER_BEST) { + if (pict->repeat == RepeatNormal) { + if (PIXREGION_NUM_RECTS(pict->pCompositeClip) == 1) { + box = pict->pCompositeClip->extents; + for (i = 0; i < width; ++i) { + if (!v.vector[2]) { + buffer[i] = 0; + } else { + int x1, x2, y1, y2, distx, idistx, disty, idisty, k; + FbBits *b; + CARD32 tl, tr, bl, br, r; + xFixed_48_16 div; + + div = ((xFixed_48_16)v.vector[0] << 16)/v.vector[2]; + x1 = div >> 16; + distx = ((xFixed)div >> 8) & 0xff; + x2 = x1 + 1; + div = ((xFixed_48_16)v.vector[1] << 16)/v.vector[2]; + y1 = div >> 16; + y2 = y1 + 1; + disty = ((xFixed)div >> 8) & 0xff; + + idistx = 256 - distx; + idisty = 256 - disty; + + x1 = MOD (x1, pict->pDrawable->width); + x2 = MOD (x2, pict->pDrawable->width); + y1 = MOD (y1, pict->pDrawable->height); + y2 = MOD (y2, pict->pDrawable->height); + + b = bits + (y1 + pict->pDrawable->y)*stride; + + tl = fetch(b, x1 + pict->pDrawable->x, indexed); + tr = fetch(b, x2 + pict->pDrawable->x, indexed); + b = bits + (y2 + pict->pDrawable->y)*stride; + bl = fetch(b, x1 + pict->pDrawable->x, indexed); + br = fetch(b, x2 + pict->pDrawable->x, indexed); + + r = 0; + for (k = 0; k < 32; k += 8) { + CARD32 t, b; + t = FbGet8(tl,k) * idistx + FbGet8(tr,k) * distx; + b = FbGet8(bl,k) * idistx + FbGet8(br,k) * distx; + r |= ((((t * idisty) + (b * disty)) >> 16) & 0xff) << k; + } + buffer[i] = r; + } + v.vector[0] += unit.vector[0]; + v.vector[1] += unit.vector[1]; + v.vector[2] += unit.vector[2]; + } + } else { + for (i = 0; i < width; ++i) { + if (!v.vector[2]) { + buffer[i] = 0; + } else { + int x1, x2, y1, y2, distx, idistx, disty, idisty, k; + FbBits *b; + CARD32 tl, tr, bl, br, r; + xFixed_48_16 div; + + div = ((xFixed_48_16)v.vector[0] << 16)/v.vector[2]; + x1 = div >> 16; + distx = ((xFixed)div >> 8) & 0xff; + x2 = x1 + 1; + div = ((xFixed_48_16)v.vector[1] << 16)/v.vector[2]; + y1 = div >> 16; + y2 = y1 + 1; + disty = ((xFixed)div >> 8) & 0xff; + + idistx = 256 - distx; + idisty = 256 - disty; + + x1 = MOD (x1, pict->pDrawable->width); + x2 = MOD (x2, pict->pDrawable->width); + y1 = MOD (y1, pict->pDrawable->height); + y2 = MOD (y2, pict->pDrawable->height); + + b = bits + (y1 + pict->pDrawable->y)*stride; + + tl = pixman_region_contains_point(pict->pCompositeClip, x1, y1, &box) + ? fetch(b, x1 + pict->pDrawable->x, indexed) : 0; + tr = pixman_region_contains_point(pict->pCompositeClip, x2, y1, &box) + ? fetch(b, x2 + pict->pDrawable->x, indexed) : 0; + b = bits + (y2 + pict->pDrawable->y)*stride; + bl = pixman_region_contains_point(pict->pCompositeClip, x1, y2, &box) + ? fetch(b, x1 + pict->pDrawable->x, indexed) : 0; + br = pixman_region_contains_point(pict->pCompositeClip, x2, y2, &box) + ? fetch(b, x2 + pict->pDrawable->x, indexed) : 0; + + r = 0; + for (k = 0; k < 32; k += 8) { + CARD32 t, b; + t = FbGet8(tl,k) * idistx + FbGet8(tr,k) * distx; + b = FbGet8(bl,k) * idistx + FbGet8(br,k) * distx; + r |= ((((t * idisty) + (b * disty)) >> 16) & 0xff) << k; + } + buffer[i] = r; + } + v.vector[0] += unit.vector[0]; + v.vector[1] += unit.vector[1]; + v.vector[2] += unit.vector[2]; + } + } + } else { + if (PIXREGION_NUM_RECTS(pict->pCompositeClip) == 1) { + box = pict->pCompositeClip->extents; + for (i = 0; i < width; ++i) { + if (!v.vector[2]) { + buffer[i] = 0; + } else { + int x1, x2, y1, y2, distx, idistx, disty, idisty, x_off, k; + FbBits *b; + CARD32 tl, tr, bl, br, r; + Bool x1_out, x2_out, y1_out, y2_out; + xFixed_48_16 div; + + div = ((xFixed_48_16)v.vector[0] << 16)/v.vector[2]; + x1 = div >> 16; + distx = ((xFixed)div >> 8) & 0xff; + x2 = x1 + 1; + div = ((xFixed_48_16)v.vector[1] << 16)/v.vector[2]; + y1 = div >> 16; + y2 = y1 + 1; + disty = ((xFixed)div >> 8) & 0xff; + + idistx = 256 - distx; + idisty = 256 - disty; + + b = bits + (y1 + pict->pDrawable->y)*stride; + x_off = x1 + pict->pDrawable->x; + + x1_out = (x1 < box.x1) | (x1 >= box.x2); + x2_out = (x2 < box.x1) | (x2 >= box.x2); + y1_out = (y1 < box.y1) | (y1 >= box.y2); + y2_out = (y2 < box.y1) | (y2 >= box.y2); + + tl = x1_out|y1_out ? 0 : fetch(b, x_off, indexed); + tr = x2_out|y1_out ? 0 : fetch(b, x_off + 1, indexed); + b += stride; + bl = x1_out|y2_out ? 0 : fetch(b, x_off, indexed); + br = x2_out|y2_out ? 0 : fetch(b, x_off + 1, indexed); + + r = 0; + for (k = 0; k < 32; k += 8) { + CARD32 t, b; + t = FbGet8(tl,k) * idistx + FbGet8(tr,k) * distx; + b = FbGet8(bl,k) * idistx + FbGet8(br,k) * distx; + r |= ((((t * idisty) + (b * disty)) >> 16) & 0xff) << k; + } + buffer[i] = r; + } + v.vector[0] += unit.vector[0]; + v.vector[1] += unit.vector[1]; + v.vector[2] += unit.vector[2]; + } + } else { + for (i = 0; i < width; ++i) { + if (!v.vector[2]) { + buffer[i] = 0; + } else { + int x1, x2, y1, y2, distx, idistx, disty, idisty, x_off, k; + FbBits *b; + CARD32 tl, tr, bl, br, r; + xFixed_48_16 div; + + div = ((xFixed_48_16)v.vector[0] << 16)/v.vector[2]; + x1 = div >> 16; + distx = ((xFixed)div >> 8) & 0xff; + x2 = x1 + 1; + div = ((xFixed_48_16)v.vector[1] << 16)/v.vector[2]; + y1 = div >> 16; + y2 = y1 + 1; + disty = ((xFixed)div >> 8) & 0xff; + + idistx = 256 - distx; + idisty = 256 - disty; + + b = bits + (y1 + pict->pDrawable->y)*stride; + x_off = x1 + pict->pDrawable->x; + + tl = pixman_region_contains_point(pict->pCompositeClip, x1, y1, &box) + ? fetch(b, x_off, indexed) : 0; + tr = pixman_region_contains_point(pict->pCompositeClip, x2, y1, &box) + ? fetch(b, x_off + 1, indexed) : 0; + b += stride; + bl = pixman_region_contains_point(pict->pCompositeClip, x1, y2, &box) + ? fetch(b, x_off, indexed) : 0; + br = pixman_region_contains_point(pict->pCompositeClip, x2, y2, &box) + ? fetch(b, x_off + 1, indexed) : 0; + + r = 0; + for (k = 0; k < 32; k += 8) { + CARD32 t, b; + t = FbGet8(tl,k) * idistx + FbGet8(tr,k) * distx; + b = FbGet8(bl,k) * idistx + FbGet8(br,k) * distx; + r |= ((((t * idisty) + (b * disty)) >> 16) & 0xff) << k; + } + buffer[i] = r; + } + v.vector[0] += unit.vector[0]; + v.vector[1] += unit.vector[1]; + v.vector[2] += unit.vector[2]; + } + } + } +#ifdef PIXMAN_CONVOLUTION + } else if (pict->filter == PictFilterConvolution) { + xFixed *params = pict->filter_params; + INT32 cwidth = xFixedToInt(params[0]); + INT32 cheight = xFixedToInt(params[1]); + int xoff = params[0] >> 1; + int yoff = params[1] >> 1; + params += 2; + for (i = 0; i < width; ++i) { + if (!v.vector[2]) { + buffer[i] = 0; + } else { + int x1, x2, y1, y2, x, y; + INT32 srtot, sgtot, sbtot, satot; + xFixed *p = params; + xFixed_48_16 tmp; + tmp = ((xFixed_48_16)v.vector[0] << 16)/v.vector[2] - xoff; + x1 = xFixedToInt(tmp); + x2 = x1 + cwidth; + tmp = ((xFixed_48_16)v.vector[1] << 16)/v.vector[2] - yoff; + y1 = xFixedToInt(tmp); + y2 = y1 + cheight; + + srtot = sgtot = sbtot = satot = 0; + + for (y = y1; y < y2; y++) { + int ty = (pict->repeat == RepeatNormal) ? MOD (y, pict->pDrawable->height) : y; + for (x = x1; x < x2; x++) { + if (*p) { + int tx = (pict->repeat == RepeatNormal) ? MOD (x, pict->pDrawable->width) : x; + if (pixman_region_contains_point (pict->pCompositeClip, tx, ty, &box)) { + FbBits *b = bits + (ty + pict->pDrawable->y)*stride; + CARD32 c = fetch(b, tx + pict->pDrawable->x, indexed); + + srtot += Red(c) * *p; + sgtot += Green(c) * *p; + sbtot += Blue(c) * *p; + satot += Alpha(c) * *p; + } + } + p++; + } + } + + if (satot < 0) satot = 0; else if (satot > 0xff) satot = 0xff; + if (srtot < 0) srtot = 0; else if (srtot > 0xff) srtot = 0xff; + if (sgtot < 0) sgtot = 0; else if (sgtot > 0xff) sgtot = 0xff; + if (sbtot < 0) sbtot = 0; else if (sbtot > 0xff) sbtot = 0xff; + + buffer[i] = ((satot << 24) | + (srtot << 16) | + (sgtot << 8) | + (sbtot )); + } + v.vector[0] += unit.vector[0]; + v.vector[1] += unit.vector[1]; + v.vector[2] += unit.vector[2]; + } +#endif + } +} + + +static void fbFetchExternalAlpha(PicturePtr pict, int x, int y, int width, CARD32 *buffer) +{ + int i; + CARD32 _alpha_buffer[SCANLINE_BUFFER_LENGTH]; + CARD32 *alpha_buffer = _alpha_buffer; + + if (!pict->alphaMap) { + fbFetchTransformed(pict, x, y, width, buffer); + return; + } + + if (width > SCANLINE_BUFFER_LENGTH) + alpha_buffer = (CARD32 *) malloc(width*sizeof(CARD32)); + + fbFetchTransformed(pict, x, y, width, buffer); + fbFetchTransformed(pict->alphaMap, x - pict->alphaOrigin.x, y - pict->alphaOrigin.y, width, alpha_buffer); + for (i = 0; i < width; ++i) { + int a = alpha_buffer[i]>>24; + buffer[i] = (a << 24) + | (div_255(Red(buffer[i]) * a) << 16) + | (div_255(Green(buffer[i]) * a) << 8) + | (div_255(Blue(buffer[i]) * a)); + } + + if (alpha_buffer != _alpha_buffer) + free(alpha_buffer); +} + +static void fbStore(PicturePtr pict, int x, int y, int width, CARD32 *buffer) +{ + FbBits *bits; + FbStride stride; + int bpp; + int xoff, yoff; + storeProc store = storeProcForPicture(pict); +#ifdef PIXMAN_INDEXED_FORMATS + miIndexedPtr indexed = (miIndexedPtr) pict->pFormat->index.devPrivate; +#else + miIndexedPtr indexed = 0; +#endif + + fbGetDrawable (pict->pDrawable, bits, stride, bpp, xoff, yoff); + x += xoff; + y += yoff; + + bits += y*stride; + store(bits, buffer, x, width, indexed); +} + +static void fbStoreExternalAlpha(PicturePtr pict, int x, int y, int width, CARD32 *buffer) +{ + FbBits *bits, *alpha_bits; + FbStride stride, astride; + int bpp, abpp; + int xoff, yoff; + int ax, ay; + storeProc store; + storeProc astore; +#ifdef PIXMAN_INDEXED_FORMATS + miIndexedPtr indexed = (miIndexedPtr) pict->pFormat->index.devPrivate; +#else + miIndexedPtr indexed = 0; +#endif + miIndexedPtr aindexed; + + if (!pict->alphaMap) { + fbStore(pict, x, y, width, buffer); + return; + } + + store = storeProcForPicture(pict); + astore = storeProcForPicture(pict->alphaMap); +#ifdef PIXMAN_INDEXED_FORMATS + aindexed = (miIndexedPtr) pict->alphaMap->pFormat->index.devPrivate; +#else + aindexed = 0; +#endif + + ax = x; + ay = y; + + fbGetDrawable (pict->pDrawable, bits, stride, bpp, xoff, yoff); + x += xoff; + y += yoff; + fbGetDrawable (pict->alphaMap->pDrawable, alpha_bits, astride, abpp, xoff, yoff); + ax += xoff; + ay += yoff; + + bits += y*stride; + alpha_bits += (ay - pict->alphaOrigin.y)*astride; + + + store(bits, buffer, x, width, indexed); + astore(alpha_bits, buffer, ax - pict->alphaOrigin.x, width, aindexed); +} + +typedef void (*scanStoreProc)(PicturePtr , int , int , int , CARD32 *); +typedef void (*scanFetchProc)(PicturePtr , int , int , int , CARD32 *); + +static void +fbCompositeRect (const FbComposeData *data, CARD32 *scanline_buffer) +{ + CARD32 *src_buffer = scanline_buffer; + CARD32 *dest_buffer = src_buffer + data->width; + int i; + scanStoreProc store; + scanFetchProc fetchSrc = 0, fetchMask = 0, fetchDest = 0; + + if (data->op == PIXMAN_OPERATOR_CLEAR) + fetchSrc = 0; + else if (!data->src->pDrawable) { +#ifdef PIXMAN_GRADIENTS + if (data->src->pSourcePict) + fetchSrc = fbFetchSourcePict; +#endif + } else if (data->src->alphaMap) + fetchSrc = fbFetchExternalAlpha; + else if (data->src->repeat == RepeatNormal && + data->src->pDrawable->width == 1 && data->src->pDrawable->height == 1) + fetchSrc = fbFetchSolid; +#ifdef PIXMAN_CONVOLUTION + else if (!data->src->transform && data->src->filter != PictFilterConvolution) + fetchSrc = fbFetch; +#else + else if (!data->src->transform) + fetchSrc = fbFetch; +#endif + else + fetchSrc = fbFetchTransformed; + + if (data->mask && data->op != PIXMAN_OPERATOR_CLEAR) { + if (!data->mask->pDrawable) { +#ifdef PIXMAN_GRADIENTS + if (data->mask->pSourcePict) + fetchMask = fbFetchSourcePict; +#endif + } else if (data->mask->alphaMap) + fetchMask = fbFetchExternalAlpha; + else if (data->mask->repeat == RepeatNormal + && data->mask->pDrawable->width == 1 && data->mask->pDrawable->height == 1) + fetchMask = fbFetchSolid; +#ifdef PIXMAN_CONVOLUTION + else if (!data->mask->transform && data->mask->filter != PictFilterConvolution) + fetchMask = fbFetch; +#else + else if (!data->mask->transform) + fetchMask = fbFetch; +#endif + else + fetchMask = fbFetchTransformed; + } else { + fetchMask = 0; + } + + if (data->dest->alphaMap) { + fetchDest = fbFetchExternalAlpha; + store = fbStoreExternalAlpha; + } else { + fetchDest = fbFetch; + store = fbStore; + } + if (data->op == PIXMAN_OPERATOR_CLEAR || data->op == PIXMAN_OPERATOR_SRC) + fetchDest = 0; + + if (fetchSrc && fetchMask && data->mask && data->mask->componentAlpha && PICT_FORMAT_RGB(data->mask->format_code)) { + CARD32 *mask_buffer = dest_buffer + data->width; + CombineFuncC compose = composeFunctions.combineC[data->op]; + if (!compose) + return; + + for (i = 0; i < data->height; ++i) + { + /* fill first half of scanline with source */ + fetchSrc(data->src, data->xSrc, data->ySrc + i, data->width, src_buffer); + fetchMask(data->mask, data->xMask, data->yMask + i, data->width, mask_buffer); + + /* fill dest into second half of scanline */ + if (fetchDest) + fetchDest(data->dest, data->xDest, data->yDest + i, data->width, dest_buffer); + + /* blend */ + compose(dest_buffer, src_buffer, mask_buffer, data->width); + + /* write back */ + store(data->dest, data->xDest, data->yDest + i, data->width, dest_buffer); + } + } else { + + CombineFuncU compose = composeFunctions.combineU[data->op]; + if (!compose) + return; + + if (fetchSrc == fbFetchSolid && (!fetchMask || fetchMask == fbFetchSolid)) { + fetchSrc(data->src, data->xSrc, data->ySrc, data->width, src_buffer); + if (fetchMask) { + fetchMask(data->mask, data->xMask, data->yMask, data->width, dest_buffer); + composeFunctions.combineMaskU(src_buffer, dest_buffer, data->width); + } + fetchSrc = 0; + fetchMask = 0; + } + + for (i = 0; i < data->height; ++i) { + /* fill first half of scanline with source */ + if (fetchSrc) { + fetchSrc(data->src, data->xSrc, data->ySrc + i, data->width, src_buffer); + + /* add in mask */ + if (fetchMask) { + fetchMask(data->mask, data->xMask, data->yMask + i, data->width, dest_buffer); + composeFunctions.combineMaskU(src_buffer, dest_buffer, data->width); + } + } + + /* fill dest into second half of scanline */ + if (fetchDest) + fetchDest(data->dest, data->xDest, data->yDest + i, data->width, dest_buffer); + + /* blend */ + compose(dest_buffer, src_buffer, data->width); + + /* write back */ + store(data->dest, data->xDest, data->yDest + i, data->width, dest_buffer); + } + } +} + +void +pixman_compositeGeneral (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + pixman_region16_t *region; + int n; + BoxPtr pbox; + Bool srcRepeat = FALSE; + Bool maskRepeat = FALSE; + int w, h; + CARD32 _scanline_buffer[SCANLINE_BUFFER_LENGTH*3]; + CARD32 *scanline_buffer = _scanline_buffer; + FbComposeData compose_data; + + if (pSrc->pDrawable) + srcRepeat = pSrc->repeat == RepeatNormal && !pSrc->transform + && (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1); + + if (pMask && pMask->pDrawable) + maskRepeat = pMask->repeat == RepeatNormal && !pMask->transform + && (pMask->pDrawable->width != 1 || pMask->pDrawable->height != 1); + + if (op == PIXMAN_OPERATOR_OVER && !pMask && !pSrc->transform && !PICT_FORMAT_A(pSrc->format_code) && !pSrc->alphaMap) + op = PIXMAN_OPERATOR_SRC; + + region = pixman_region_create(); + pixman_region_union_rect (region, region, xDst, yDst, width, height); + + if (!FbComputeCompositeRegion (region, + pSrc, + pMask, + pDst, + xSrc, + ySrc, + xMask, + yMask, + xDst, + yDst, + width, + height)) + return; + + compose_data.op = op; + compose_data.src = pSrc; + compose_data.mask = pMask; + compose_data.dest = pDst; + if (width > SCANLINE_BUFFER_LENGTH) + scanline_buffer = (CARD32 *) malloc(width * 3 * sizeof(CARD32)); + + n = pixman_region_num_rects (region); + pbox = pixman_region_rects (region); + while (n--) + { + h = pbox->y2 - pbox->y1; + compose_data.ySrc = pbox->y1 - yDst + ySrc; + compose_data.yMask = pbox->y1 - yDst + yMask; + compose_data.yDest = pbox->y1; + while (h) + { + compose_data.height = h; + w = pbox->x2 - pbox->x1; + compose_data.xSrc = pbox->x1 - xDst + xSrc; + compose_data.xMask = pbox->x1 - xDst + xMask; + compose_data.xDest = pbox->x1; + if (maskRepeat) + { + compose_data.yMask = mod (compose_data.yMask, pMask->pDrawable->height); + if (compose_data.height > pMask->pDrawable->height - compose_data.yMask) + compose_data.height = pMask->pDrawable->height - compose_data.yMask; + } + if (srcRepeat) + { + compose_data.ySrc = mod (compose_data.ySrc, pSrc->pDrawable->height); + if (compose_data.height > pSrc->pDrawable->height - compose_data.ySrc) + compose_data.height = pSrc->pDrawable->height - compose_data.ySrc; + } + while (w) + { + compose_data.width = w; + if (maskRepeat) + { + compose_data.xMask = mod (compose_data.xMask, pMask->pDrawable->width); + if (compose_data.width > pMask->pDrawable->width - compose_data.xMask) + compose_data.width = pMask->pDrawable->width - compose_data.xMask; + } + if (srcRepeat) + { + compose_data.xSrc = mod (compose_data.xSrc, pSrc->pDrawable->width); + if (compose_data.width > pSrc->pDrawable->width - compose_data.xSrc) + compose_data.width = pSrc->pDrawable->width - compose_data.xSrc; + } + fbCompositeRect(&compose_data, scanline_buffer); + w -= compose_data.width; + compose_data.xSrc += compose_data.width; + compose_data.xMask += compose_data.width; + compose_data.xDest += compose_data.width; + } + h -= compose_data.height; + compose_data.ySrc += compose_data.height; + compose_data.yMask += compose_data.height; + compose_data.yDest += compose_data.height; + } + pbox++; + } + pixman_region_destroy (region); + + if (scanline_buffer != _scanline_buffer) + free(scanline_buffer); +} + +#endif diff --git a/gfx/cairo/libpixman/src/fbedge.c b/gfx/cairo/libpixman/src/fbedge.c index 47370ed24963..0238c15efa61 100644 --- a/gfx/cairo/libpixman/src/fbedge.c +++ b/gfx/cairo/libpixman/src/fbedge.c @@ -1,5 +1,5 @@ /* - * $Id: fbedge.c,v 1.3 2005/06/04 07:03:28 vladimir%pobox.com Exp $ + * $Id: fbedge.c,v 1.8 2006/02/03 04:49:30 vladimir%pobox.com Exp $ * * Copyright © 2004 Keith Packard * @@ -22,35 +22,11 @@ * PERFORMANCE OF THIS SOFTWARE. */ +#include #include "pixman-xserver-compat.h" #ifdef RENDER -/* - * 8 bit alpha - */ - -#define N_BITS 8 -#define rasterizeEdges fbRasterizeEdges8 - -#define DefineAlpha(line,x) \ - CARD8 *__ap = (CARD8 *) line + (x) - -#define StepAlpha __ap++ - -#define AddAlpha(a) { \ - CARD16 __a = a + *__ap; \ - *__ap = ((CARD8) ((__a) | (0 - ((__a) >> 8)))); \ -} - -#include "fbedgeimp.h" - -#undef AddAlpha -#undef StepAlpha -#undef DefineAlpha -#undef rasterizeEdges -#undef N_BITS - /* * 4 bit alpha */ @@ -100,6 +76,208 @@ #undef rasterizeEdges #undef N_BITS +/* + * 8 bit alpha + */ + +static INLINE CARD8 +clip255 (int x) +{ + if (x > 255) return 255; + return x; +} + +static INLINE void +add_saturate_8 (CARD8 *buf, int value, int length) +{ + while (length--) + { + *buf = clip255 (*buf + value); + buf++; + } +} + +/* + * We want to detect the case where we add the same value to a long + * span of pixels. The triangles on the end are filled in while we + * count how many sub-pixel scanlines contribute to the middle section. + * + * +--------------------------+ + * fill_height =| \ / + * +------------------+ + * |================| + * fill_start fill_end + */ +static void +fbRasterizeEdges8 (FbBits *buf, + int width, + int stride, + RenderEdge *l, + RenderEdge *r, + xFixed t, + xFixed b) +{ + xFixed y = t; + FbBits *line; + int fill_start = -1, fill_end = -1; + int fill_size = 0; + + line = buf + xFixedToInt (y) * stride; + + for (;;) + { + CARD8 *ap = (CARD8 *) line; + xFixed lx, rx; + int lxi, rxi; + + /* clip X */ + lx = l->x; + if (lx < 0) + lx = 0; + rx = r->x; + if (xFixedToInt (rx) >= width) + rx = IntToxFixed (width); + + /* Skip empty (or backwards) sections */ + if (rx > lx) + { + int lxs, rxs; + + /* Find pixel bounds for span. */ + lxi = xFixedToInt (lx); + rxi = xFixedToInt (rx); + + /* Sample coverage for edge pixels */ + lxs = RenderSamplesX (lx, 8); + rxs = RenderSamplesX (rx, 8); + + /* Add coverage across row */ + if (lxi == rxi) + { + ap[lxi] = clip255 (ap[lxi] + rxs - lxs); + } + else + { + ap[lxi] = clip255 (ap[lxi] + N_X_FRAC(8) - lxs); + + /* Move forward so that lxi/rxi is the pixel span */ + lxi++; + + /* Don't bother trying to optimize the fill unless + * the span is longer than 4 pixels. */ + if (rxi - lxi > 4) + { + if (fill_start < 0) + { + fill_start = lxi; + fill_end = rxi; + fill_size++; + } + else + { + if (lxi >= fill_end || rxi < fill_start) + { + /* We're beyond what we saved, just fill it */ + add_saturate_8 (ap + fill_start, + fill_size * N_X_FRAC(8), + fill_end - fill_start); + fill_start = lxi; + fill_end = rxi; + fill_size = 1; + } + else + { + /* Update fill_start */ + if (lxi > fill_start) + { + add_saturate_8 (ap + fill_start, + fill_size * N_X_FRAC(8), + lxi - fill_start); + fill_start = lxi; + } + else if (lxi < fill_start) + { + add_saturate_8 (ap + lxi, N_X_FRAC(8), + fill_start - lxi); + } + + /* Update fill_end */ + if (rxi < fill_end) + { + add_saturate_8 (ap + rxi, + fill_size * N_X_FRAC(8), + fill_end - rxi); + fill_end = rxi; + } + else if (fill_end < rxi) + { + add_saturate_8 (ap + fill_end, + N_X_FRAC(8), + rxi - fill_end); + } + fill_size++; + } + } + } + else + { + add_saturate_8 (ap + lxi, N_X_FRAC(8), rxi - lxi); + } + + /* Do not add in a 0 alpha here. This check is + * necessary to avoid a buffer overrun, (when rx + * is exactly on a pixel boundary). */ + if (rxs) + ap[rxi] = clip255 (ap[rxi] + rxs); + } + } + + if (y == b) { + /* We're done, make sure we clean up any remaining fill. */ + if (fill_start != fill_end) { + if (fill_size == N_Y_FRAC(8)) + { + memset (ap + fill_start, 0xff, fill_end - fill_start); + } + else + { + add_saturate_8 (ap + fill_start, fill_size * N_X_FRAC(8), + fill_end - fill_start); + } + } + break; + } + + if (xFixedFrac (y) != Y_FRAC_LAST(8)) + { + RenderEdgeStepSmall (l); + RenderEdgeStepSmall (r); + y += STEP_Y_SMALL(8); + } + else + { + RenderEdgeStepBig (l); + RenderEdgeStepBig (r); + y += STEP_Y_BIG(8); + if (fill_start != fill_end) + { + if (fill_size == N_Y_FRAC(8)) + { + memset (ap + fill_start, 0xff, fill_end - fill_start); + } + else + { + add_saturate_8 (ap + fill_start, fill_size * N_X_FRAC(8), + fill_end - fill_start); + } + fill_start = fill_end = -1; + fill_size = 0; + } + line += stride; + } + } +} + void fbRasterizeEdges (FbBits *buf, int bpp, diff --git a/gfx/cairo/libpixman/src/fbmmx.c b/gfx/cairo/libpixman/src/fbmmx.c new file mode 100644 index 000000000000..347a51214557 --- /dev/null +++ b/gfx/cairo/libpixman/src/fbmmx.c @@ -0,0 +1,2503 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * Copyright © 2004 Nicholas Miell + * Copyright © 2005 Trolltech AS + * + * 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 not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Red Hat makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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: Søren Sandmann (sandmann@redhat.com) + * Minor Improvements: Nicholas Miell (nmiell@gmail.com) + * MMX code paths for fbcompose.c by Lars Knoll (lars@trolltech.com) + * + * Based on work by Owen Taylor + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include "fbpict.h" +#include "pixman-xserver-compat.h" +#include "fbmmx.h" + +#if defined(__amd64__) || defined(__x86_64__) +#define USE_SSE +#endif + +#include +#include /* for _mm_shuffle_pi16 and _MM_SHUFFLE */ + +#ifdef RENDER + +#include "fbpict.h" + +#define noVERBOSE + +#ifdef VERBOSE +#define CHECKPOINT() ErrorF ("at %s %d\n", __FUNCTION__, __LINE__) +#else +#define CHECKPOINT() +#endif + +/* Notes about writing mmx code + * + * give memory operands as the second operand. If you give it as the + * first, gcc will first load it into a register, then use that + * register + * + * ie. use + * + * _mm_mullo_pi16 (x, mmx_constant); + * + * not + * + * _mm_mullo_pi16 (mmx_constant, x); + * + * Also try to minimize dependencies. i.e. when you need a value, try + * to calculate it from a value that was calculated as early as + * possible. + */ + +/* --------------- MMX primitivess ------------------------------------ */ + +typedef unsigned long long ullong; + +typedef struct +{ + ullong mmx_4x00ff; + ullong mmx_4x0080; + ullong mmx_565_rgb; + ullong mmx_565_unpack_multiplier; + ullong mmx_565_r; + ullong mmx_565_g; + ullong mmx_565_b; + ullong mmx_mask_0; + ullong mmx_mask_1; + ullong mmx_mask_2; + ullong mmx_mask_3; + ullong mmx_full_alpha; + ullong mmx_ffff0000ffff0000; + ullong mmx_0000ffff00000000; + ullong mmx_000000000000ffff; +} MMXData; + +static const MMXData c = +{ + .mmx_4x00ff = 0x00ff00ff00ff00ffULL, + .mmx_4x0080 = 0x0080008000800080ULL, + .mmx_565_rgb = 0x000001f0003f001fULL, + .mmx_565_r = 0x000000f800000000ULL, + .mmx_565_g = 0x0000000000fc0000ULL, + .mmx_565_b = 0x00000000000000f8ULL, + .mmx_mask_0 = 0xffffffffffff0000ULL, + .mmx_mask_1 = 0xffffffff0000ffffULL, + .mmx_mask_2 = 0xffff0000ffffffffULL, + .mmx_mask_3 = 0x0000ffffffffffffULL, + .mmx_full_alpha = 0x00ff000000000000ULL, + .mmx_565_unpack_multiplier = 0x0000008404100840ULL, + .mmx_ffff0000ffff0000 = 0xffff0000ffff0000ULL, + .mmx_0000ffff00000000 = 0x0000ffff00000000ULL, + .mmx_000000000000ffff = 0x000000000000ffffULL, +}; + +#define MC(x) ((__m64) c.mmx_##x) + +static __inline__ __m64 +shift (__m64 v, int s) +{ + if (s > 0) + return _mm_slli_si64 (v, s); + else if (s < 0) + return _mm_srli_si64 (v, -s); + else + return v; +} + +static __inline__ __m64 +negate (__m64 mask) +{ + return _mm_xor_si64 (mask, MC(4x00ff)); +} + +static __inline__ __m64 +pix_multiply (__m64 a, __m64 b) +{ + __m64 res; + + res = _mm_mullo_pi16 (a, b); + res = _mm_adds_pu16 (res, MC(4x0080)); + res = _mm_adds_pu16 (res, _mm_srli_pi16 (res, 8)); + res = _mm_srli_pi16 (res, 8); + + return res; +} + +static __inline__ __m64 +pix_add (__m64 a, __m64 b) +{ + return _mm_adds_pu8 (a, b); +} + +#ifdef USE_SSE + +static __inline__ __m64 +expand_alpha (__m64 pixel) +{ + return _mm_shuffle_pi16 (pixel, _MM_SHUFFLE(3, 3, 3, 3)); +} + +static __inline__ __m64 +expand_alpha_rev (__m64 pixel) +{ + return _mm_shuffle_pi16 (pixel, _MM_SHUFFLE(0, 0, 0, 0)); +} + +static __inline__ __m64 +invert_colors (__m64 pixel) +{ + return _mm_shuffle_pi16 (pixel, _MM_SHUFFLE(3, 0, 1, 2)); +} + +#else + +static __inline__ __m64 +expand_alpha (__m64 pixel) +{ + __m64 t1, t2; + + t1 = shift (pixel, -48); + t2 = shift (t1, 16); + t1 = _mm_or_si64 (t1, t2); + t2 = shift (t1, 32); + t1 = _mm_or_si64 (t1, t2); + + return t1; +} + +static __inline__ __m64 +expand_alpha_rev (__m64 pixel) +{ + __m64 t1, t2; + + /* move alpha to low 16 bits and zero the rest */ + t1 = shift (pixel, 48); + t1 = shift (t1, -48); + + t2 = shift (t1, 16); + t1 = _mm_or_si64 (t1, t2); + t2 = shift (t1, 32); + t1 = _mm_or_si64 (t1, t2); + + return t1; +} + +static __inline__ __m64 +invert_colors (__m64 pixel) +{ + __m64 x, y, z; + + x = y = z = pixel; + + x = _mm_and_si64 (x, MC(ffff0000ffff0000)); + y = _mm_and_si64 (y, MC(000000000000ffff)); + z = _mm_and_si64 (z, MC(0000ffff00000000)); + + y = shift (y, 32); + z = shift (z, -32); + + x = _mm_or_si64 (x, y); + x = _mm_or_si64 (x, z); + + return x; +} + +#endif + +static __inline__ __m64 +over (__m64 src, __m64 srca, __m64 dest) +{ + return _mm_adds_pu8 (src, pix_multiply(dest, negate(srca))); +} + +static __inline__ __m64 +over_rev_non_pre (__m64 src, __m64 dest) +{ + __m64 srca = expand_alpha (src); + __m64 srcfaaa = _mm_or_si64 (srca, MC(full_alpha)); + + return over(pix_multiply(invert_colors(src), srcfaaa), srca, dest); +} + +static __inline__ __m64 +in (__m64 src, + __m64 mask) +{ + return pix_multiply (src, mask); +} + +static __inline__ __m64 +in_over (__m64 src, + __m64 srca, + __m64 mask, + __m64 dest) +{ + return over(in(src, mask), pix_multiply(srca, mask), dest); +} + +static __inline__ __m64 +load8888 (CARD32 v) +{ + return _mm_unpacklo_pi8 (_mm_cvtsi32_si64 (v), _mm_setzero_si64()); +} + +static __inline__ __m64 +pack8888 (__m64 lo, __m64 hi) +{ + return _mm_packs_pu16 (lo, hi); +} + +static __inline__ CARD32 +store8888 (__m64 v) +{ + return _mm_cvtsi64_si32(pack8888(v, _mm_setzero_si64())); +} + +/* Expand 16 bits positioned at @pos (0-3) of a mmx register into + * + * 00RR00GG00BB + * + * --- Expanding 565 in the low word --- + * + * m = (m << (32 - 3)) | (m << (16 - 5)) | m; + * m = m & (01f0003f001f); + * m = m * (008404100840); + * m = m >> 8; + * + * Note the trick here - the top word is shifted by another nibble to + * avoid it bumping into the middle word + */ +static __inline__ __m64 +expand565 (__m64 pixel, int pos) +{ + __m64 p = pixel; + __m64 t1, t2; + + /* move pixel to low 16 bit and zero the rest */ + p = shift (shift (p, (3 - pos) * 16), -48); + + t1 = shift (p, 36 - 11); + t2 = shift (p, 16 - 5); + + p = _mm_or_si64 (t1, p); + p = _mm_or_si64 (t2, p); + p = _mm_and_si64 (p, MC(565_rgb)); + + pixel = _mm_mullo_pi16 (p, MC(565_unpack_multiplier)); + return _mm_srli_pi16 (pixel, 8); +} + +static __inline__ __m64 +expand8888 (__m64 in, int pos) +{ + if (pos == 0) + return _mm_unpacklo_pi8 (in, _mm_setzero_si64()); + else + return _mm_unpackhi_pi8 (in, _mm_setzero_si64()); +} + +static __inline__ __m64 +pack565 (__m64 pixel, __m64 target, int pos) +{ + __m64 p = pixel; + __m64 t = target; + __m64 r, g, b; + + r = _mm_and_si64 (p, MC(565_r)); + g = _mm_and_si64 (p, MC(565_g)); + b = _mm_and_si64 (p, MC(565_b)); + + r = shift (r, - (32 - 8) + pos * 16); + g = shift (g, - (16 - 3) + pos * 16); + b = shift (b, - (0 + 3) + pos * 16); + + if (pos == 0) + t = _mm_and_si64 (t, MC(mask_0)); + else if (pos == 1) + t = _mm_and_si64 (t, MC(mask_1)); + else if (pos == 2) + t = _mm_and_si64 (t, MC(mask_2)); + else if (pos == 3) + t = _mm_and_si64 (t, MC(mask_3)); + + p = _mm_or_si64 (r, t); + p = _mm_or_si64 (g, p); + + return _mm_or_si64 (b, p); +} + +static __inline__ __m64 +pix_add_mul (__m64 x, __m64 a, __m64 y, __m64 b) +{ + x = _mm_mullo_pi16 (x, a); + y = _mm_mullo_pi16 (y, b); + x = _mm_adds_pu16 (x, MC(4x0080)); + x = _mm_adds_pu16 (x, y); + x = _mm_adds_pu16 (x, _mm_srli_pi16 (x, 8)); + x = _mm_srli_pi16 (x, 8); + + return x; +} + +/* --------------- MMX code patch for fbcompose.c --------------------- */ + +static FASTCALL void +mmxCombineMaskU (CARD32 *src, const CARD32 *mask, int width) +{ + const CARD32 *end = mask + width; + while (mask < end) { + __m64 a = load8888(*mask); + __m64 s = load8888(*src); + a = expand_alpha(a); + s = pix_multiply(s, a); + *src = store8888(s); + ++src; + ++mask; + } + _mm_empty(); +} + + +static FASTCALL void +mmxCombineOverU (CARD32 *dest, const CARD32 *src, int width) +{ + const CARD32 *end = dest + width; + + while (dest < end) { + __m64 s, sa; + s = load8888(*src); + sa = expand_alpha(s); + *dest = store8888(over(s, sa, load8888(*dest))); + ++dest; + ++src; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineOverReverseU (CARD32 *dest, const CARD32 *src, int width) +{ + const CARD32 *end = dest + width; + + while (dest < end) { + __m64 d, da; + d = load8888(*dest); + da = expand_alpha(d); + *dest = store8888(over (d, da, load8888(*src))); + ++dest; + ++src; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineInU (CARD32 *dest, const CARD32 *src, int width) +{ + const CARD32 *end = dest + width; + + while (dest < end) { + __m64 x, a; + x = load8888(*src); + a = load8888(*dest); + a = expand_alpha(a); + x = pix_multiply(x, a); + *dest = store8888(x); + ++dest; + ++src; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineInReverseU (CARD32 *dest, const CARD32 *src, int width) +{ + const CARD32 *end = dest + width; + + while (dest < end) { + __m64 x, a; + x = load8888(*dest); + a = load8888(*src); + a = expand_alpha(a); + x = pix_multiply(x, a); + *dest = store8888(x); + ++dest; + ++src; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineOutU (CARD32 *dest, const CARD32 *src, int width) +{ + const CARD32 *end = dest + width; + + while (dest < end) { + __m64 x, a; + x = load8888(*src); + a = load8888(*dest); + a = expand_alpha(a); + a = negate(a); + x = pix_multiply(x, a); + *dest = store8888(x); + ++dest; + ++src; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineOutReverseU (CARD32 *dest, const CARD32 *src, int width) +{ + const CARD32 *end = dest + width; + + while (dest < end) { + __m64 x, a; + x = load8888(*dest); + a = load8888(*src); + a = expand_alpha(a); + a = negate(a); + x = pix_multiply(x, a); + *dest = store8888(x); + ++dest; + ++src; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineAtopU (CARD32 *dest, const CARD32 *src, int width) +{ + const CARD32 *end = dest + width; + + while (dest < end) { + __m64 s, da, d, sia; + s = load8888(*src); + d = load8888(*dest); + sia = expand_alpha(s); + sia = negate(sia); + da = expand_alpha(d); + s = pix_add_mul (s, da, d, sia); + *dest = store8888(s); + ++dest; + ++src; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineAtopReverseU (CARD32 *dest, const CARD32 *src, int width) +{ + const CARD32 *end; + + end = dest + width; + + while (dest < end) { + __m64 s, dia, d, sa; + s = load8888(*src); + d = load8888(*dest); + sa = expand_alpha(s); + dia = expand_alpha(d); + dia = negate(dia); + s = pix_add_mul (s, dia, d, sa); + *dest = store8888(s); + ++dest; + ++src; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineXorU (CARD32 *dest, const CARD32 *src, int width) +{ + const CARD32 *end = dest + width; + + while (dest < end) { + __m64 s, dia, d, sia; + s = load8888(*src); + d = load8888(*dest); + sia = expand_alpha(s); + dia = expand_alpha(d); + sia = negate(sia); + dia = negate(dia); + s = pix_add_mul (s, dia, d, sia); + *dest = store8888(s); + ++dest; + ++src; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineAddU (CARD32 *dest, const CARD32 *src, int width) +{ + const CARD32 *end = dest + width; + while (dest < end) { + __m64 s, d; + s = load8888(*src); + d = load8888(*dest); + s = pix_add(s, d); + *dest = store8888(s); + ++dest; + ++src; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineSaturateU (CARD32 *dest, const CARD32 *src, int width) +{ + const CARD32 *end = dest + width; + while (dest < end) { + CARD32 s = *src; + CARD32 d = *dest; + __m64 ms = load8888(s); + __m64 md = load8888(d); + CARD32 sa = s >> 24; + CARD32 da = ~d >> 24; + + if (sa > da) { + __m64 msa = load8888(FbIntDiv(da, sa)<<24); + msa = expand_alpha(msa); + ms = pix_multiply(ms, msa); + } + md = pix_add(md, ms); + *dest = store8888(md); + ++src; + ++dest; + } + _mm_empty(); +} + + +static FASTCALL void +mmxCombineSrcC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + const CARD32 *end = src + width; + while (src < end) { + __m64 a = load8888(*mask); + __m64 s = load8888(*src); + s = pix_multiply(s, a); + *dest = store8888(s); + ++src; + ++mask; + ++dest; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineOverC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + const CARD32 *end = src + width; + while (src < end) { + __m64 a = load8888(*mask); + __m64 s = load8888(*src); + __m64 d = load8888(*dest); + __m64 sa = expand_alpha(s); + + *dest = store8888(in_over (s, sa, a, d)); + + ++src; + ++dest; + ++mask; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineOverReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + const CARD32 *end = src + width; + while (src < end) { + __m64 a = load8888(*mask); + __m64 s = load8888(*src); + __m64 d = load8888(*dest); + __m64 da = expand_alpha(d); + + *dest = store8888(over (d, da, in (s, a))); + + ++src; + ++dest; + ++mask; + } + _mm_empty(); +} + + +static FASTCALL void +mmxCombineInC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + const CARD32 *end = src + width; + while (src < end) { + __m64 a = load8888(*mask); + __m64 s = load8888(*src); + __m64 d = load8888(*dest); + __m64 da = expand_alpha(d); + s = pix_multiply(s, a); + s = pix_multiply(s, da); + *dest = store8888(s); + ++src; + ++dest; + ++mask; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineInReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + const CARD32 *end = src + width; + while (src < end) { + __m64 a = load8888(*mask); + __m64 s = load8888(*src); + __m64 d = load8888(*dest); + __m64 sa = expand_alpha(s); + a = pix_multiply(a, sa); + d = pix_multiply(d, a); + *dest = store8888(d); + ++src; + ++dest; + ++mask; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineOutC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + const CARD32 *end = src + width; + while (src < end) { + __m64 a = load8888(*mask); + __m64 s = load8888(*src); + __m64 d = load8888(*dest); + __m64 da = expand_alpha(d); + da = negate(da); + s = pix_multiply(s, a); + s = pix_multiply(s, da); + *dest = store8888(s); + ++src; + ++dest; + ++mask; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineOutReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + const CARD32 *end = src + width; + while (src < end) { + __m64 a = load8888(*mask); + __m64 s = load8888(*src); + __m64 d = load8888(*dest); + __m64 sa = expand_alpha(s); + a = pix_multiply(a, sa); + a = negate(a); + d = pix_multiply(d, a); + *dest = store8888(d); + ++src; + ++dest; + ++mask; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineAtopC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + const CARD32 *end = src + width; + while (src < end) { + __m64 a = load8888(*mask); + __m64 s = load8888(*src); + __m64 d = load8888(*dest); + __m64 da = expand_alpha(d); + __m64 sa = expand_alpha(s); + s = pix_multiply(s, a); + a = pix_multiply(a, sa); + a = negate(a); + d = pix_add_mul (d, a, s, da); + *dest = store8888(d); + ++src; + ++dest; + ++mask; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineAtopReverseC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + const CARD32 *end = src + width; + while (src < end) { + __m64 a = load8888(*mask); + __m64 s = load8888(*src); + __m64 d = load8888(*dest); + __m64 da = expand_alpha(d); + __m64 sa = expand_alpha(s); + s = pix_multiply(s, a); + a = pix_multiply(a, sa); + da = negate(da); + d = pix_add_mul (d, a, s, da); + *dest = store8888(d); + ++src; + ++dest; + ++mask; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineXorC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + const CARD32 *end = src + width; + while (src < end) { + __m64 a = load8888(*mask); + __m64 s = load8888(*src); + __m64 d = load8888(*dest); + __m64 da = expand_alpha(d); + __m64 sa = expand_alpha(s); + s = pix_multiply(s, a); + a = pix_multiply(a, sa); + da = negate(da); + a = negate(a); + d = pix_add_mul (d, a, s, da); + *dest = store8888(d); + ++src; + ++dest; + ++mask; + } + _mm_empty(); +} + +static FASTCALL void +mmxCombineAddC (CARD32 *dest, CARD32 *src, CARD32 *mask, int width) +{ + const CARD32 *end = src + width; + while (src < end) { + __m64 a = load8888(*mask); + __m64 s = load8888(*src); + __m64 d = load8888(*dest); + s = pix_multiply(s, a); + d = pix_add(s, d); + *dest = store8888(d); + ++src; + ++dest; + ++mask; + } + _mm_empty(); +} + +extern FbComposeFunctions composeFunctions; + +void fbComposeSetupMMX(void) +{ + /* check if we have MMX support and initialize accordingly */ + if (fbHaveMMX()) { + composeFunctions.combineU[PIXMAN_OPERATOR_OVER] = mmxCombineOverU; + composeFunctions.combineU[PIXMAN_OPERATOR_OVER_REVERSE] = mmxCombineOverReverseU; + composeFunctions.combineU[PIXMAN_OPERATOR_IN] = mmxCombineInU; + composeFunctions.combineU[PIXMAN_OPERATOR_IN_REVERSE] = mmxCombineInReverseU; + composeFunctions.combineU[PIXMAN_OPERATOR_OUT] = mmxCombineOutU; + composeFunctions.combineU[PIXMAN_OPERATOR_OUT_REVERSE] = mmxCombineOutReverseU; + composeFunctions.combineU[PIXMAN_OPERATOR_ATOP] = mmxCombineAtopU; + composeFunctions.combineU[PIXMAN_OPERATOR_ATOP_REVERSE] = mmxCombineAtopReverseU; + composeFunctions.combineU[PIXMAN_OPERATOR_XOR] = mmxCombineXorU; + composeFunctions.combineU[PIXMAN_OPERATOR_ADD] = mmxCombineAddU; + composeFunctions.combineU[PIXMAN_OPERATOR_SATURATE] = mmxCombineSaturateU; + + composeFunctions.combineC[PIXMAN_OPERATOR_SRC] = mmxCombineSrcC; + composeFunctions.combineC[PIXMAN_OPERATOR_OVER] = mmxCombineOverC; + composeFunctions.combineC[PIXMAN_OPERATOR_OVER_REVERSE] = mmxCombineOverReverseC; + composeFunctions.combineC[PIXMAN_OPERATOR_IN] = mmxCombineInC; + composeFunctions.combineC[PIXMAN_OPERATOR_IN_REVERSE] = mmxCombineInReverseC; + composeFunctions.combineC[PIXMAN_OPERATOR_OUT] = mmxCombineOutC; + composeFunctions.combineC[PIXMAN_OPERATOR_OUT_REVERSE] = mmxCombineOutReverseC; + composeFunctions.combineC[PIXMAN_OPERATOR_ATOP] = mmxCombineAtopC; + composeFunctions.combineC[PIXMAN_OPERATOR_ATOP_REVERSE] = mmxCombineAtopReverseC; + composeFunctions.combineC[PIXMAN_OPERATOR_XOR] = mmxCombineXorC; + composeFunctions.combineC[PIXMAN_OPERATOR_ADD] = mmxCombineAddC; + + composeFunctions.combineMaskU = mmxCombineMaskU; + } +} + + +/* ------------------ MMX code paths called from fbpict.c ----------------------- */ + +void +fbCompositeSolid_nx8888mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 src; + CARD32 *dstLine, *dst; + CARD16 w; + FbStride dstStride; + __m64 vsrc, vsrca; + + CHECKPOINT(); + + fbComposeGetSolid(pSrc, src); + + if (src >> 24 == 0) + return; + + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + + vsrc = load8888 (src); + vsrca = expand_alpha (vsrc); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + w = width; + + CHECKPOINT(); + + while (w && (unsigned long)dst & 7) + { + *dst = store8888(over(vsrc, vsrca, load8888(*dst))); + + w--; + dst++; + } + + while (w >= 2) + { + __m64 vdest; + __m64 dest0, dest1; + + vdest = *(__m64 *)dst; + + dest0 = over(vsrc, vsrca, expand8888(vdest, 0)); + dest1 = over(vsrc, vsrca, expand8888(vdest, 1)); + + *(__m64 *)dst = pack8888(dest0, dest1); + + dst += 2; + w -= 2; + } + + CHECKPOINT(); + + while (w) + { + *dst = store8888(over(vsrc, vsrca, load8888(*dst))); + + w--; + dst++; + } + } + + _mm_empty(); +} + +void +fbCompositeSolid_nx0565mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 src; + CARD16 *dstLine, *dst; + CARD16 w; + FbStride dstStride; + __m64 vsrc, vsrca; + + CHECKPOINT(); + + fbComposeGetSolid(pSrc, src); + + if (src >> 24 == 0) + return; + + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); + + vsrc = load8888 (src); + vsrca = expand_alpha (vsrc); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + w = width; + + CHECKPOINT(); + + while (w && (unsigned long)dst & 7) + { + ullong d = *dst; + __m64 vdest = expand565 ((__m64)d, 0); + vdest = pack565(over(vsrc, vsrca, vdest), vdest, 0); + *dst = (ullong)vdest; + + w--; + dst++; + } + + while (w >= 4) + { + __m64 vdest; + + vdest = *(__m64 *)dst; + + vdest = pack565 (over(vsrc, vsrca, expand565(vdest, 0)), vdest, 0); + vdest = pack565 (over(vsrc, vsrca, expand565(vdest, 1)), vdest, 1); + vdest = pack565 (over(vsrc, vsrca, expand565(vdest, 2)), vdest, 2); + vdest = pack565 (over(vsrc, vsrca, expand565(vdest, 3)), vdest, 3); + + *(__m64 *)dst = vdest; + + dst += 4; + w -= 4; + } + + CHECKPOINT(); + + while (w) + { + ullong d = *dst; + __m64 vdest = expand565 ((__m64)d, 0); + vdest = pack565(over(vsrc, vsrca, vdest), vdest, 0); + *dst = (ullong)vdest; + + w--; + dst++; + } + } + + _mm_empty(); +} + +void +fbCompositeSolidMask_nx8888x8888Cmmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 src, srca; + CARD32 *dstLine; + CARD32 *maskLine; + FbStride dstStride, maskStride; + __m64 vsrc, vsrca; + + CHECKPOINT(); + + fbComposeGetSolid(pSrc, src); + + srca = src >> 24; + if (srca == 0) + return; + + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD32, maskStride, maskLine, 1); + + vsrc = load8888(src); + vsrca = expand_alpha(vsrc); + + while (height--) + { + int twidth = width; + CARD32 *p = (CARD32 *)maskLine; + CARD32 *q = (CARD32 *)dstLine; + + while (twidth && (unsigned long)q & 7) + { + CARD32 m = *(CARD32 *)p; + + if (m) + { + __m64 vdest = load8888(*q); + vdest = in_over(vsrc, vsrca, load8888(m), vdest); + *q = store8888(vdest); + } + + twidth--; + p++; + q++; + } + + while (twidth >= 2) + { + CARD32 m0, m1; + m0 = *p; + m1 = *(p + 1); + + if (m0 | m1) + { + __m64 dest0, dest1; + __m64 vdest = *(__m64 *)q; + + dest0 = in_over(vsrc, vsrca, load8888(m0), + expand8888 (vdest, 0)); + dest1 = in_over(vsrc, vsrca, load8888(m1), + expand8888 (vdest, 1)); + + *(__m64 *)q = pack8888(dest0, dest1); + } + + p += 2; + q += 2; + twidth -= 2; + } + + while (twidth) + { + CARD32 m = *(CARD32 *)p; + + if (m) + { + __m64 vdest = load8888(*q); + vdest = in_over(vsrc, vsrca, load8888(m), vdest); + *q = store8888(vdest); + } + + twidth--; + p++; + q++; + } + + dstLine += dstStride; + maskLine += maskStride; + } + + _mm_empty(); +} + +void +fbCompositeSrc_8888x8x8888mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 *dstLine, *dst; + CARD32 *srcLine, *src; + CARD8 *maskLine; + CARD32 mask; + __m64 vmask; + FbStride dstStride, srcStride, maskStride; + CARD16 w; + __m64 srca; + + CHECKPOINT(); + + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD8, maskStride, maskLine, 1); + + mask = *maskLine << 24 | *maskLine << 16 | *maskLine << 8 | *maskLine; + vmask = load8888 (mask); + srca = MC(4x00ff); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + while (w && (unsigned long)dst & 7) + { + __m64 s = load8888 (*src); + __m64 d = load8888 (*dst); + + *dst = store8888 (over (s, expand_alpha (s), d)); + + w--; + dst++; + src++; + } + + while (w >= 2) + { + __m64 vs = *(__m64 *)dst; + __m64 vd = *(__m64 *)src; + __m64 vsrc0 = expand8888 (vs, 0); + __m64 vsrc1 = expand8888 (vs, 1); + + *(__m64 *)dst = (__m64)pack8888 ( + in_over (vsrc0, expand_alpha (vsrc0), vmask, expand8888 (vd, 0)), + in_over (vsrc1, expand_alpha (vsrc1), vmask, expand8888 (vd, 1))); + + w -= 2; + dst += 2; + src += 2; + } + + while (w) + { + __m64 s = load8888 (*src); + __m64 d = load8888 (*dst); + + *dst = store8888 (in_over (s, expand_alpha (s), vmask, d)); + + w--; + dst++; + src++; + } + } + + _mm_empty(); +} + +void +fbCompositeSrc_x888x8x8888mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 *dstLine, *dst; + CARD32 *srcLine, *src; + CARD8 *maskLine; + CARD32 mask; + __m64 vmask; + FbStride dstStride, srcStride, maskStride; + CARD16 w; + __m64 srca; + + CHECKPOINT(); + + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD8, maskStride, maskLine, 1); + + mask = *maskLine << 24 | *maskLine << 16 | *maskLine << 8 | *maskLine; + vmask = load8888 (mask); + srca = MC(4x00ff); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + while (w && (unsigned long)dst & 7) + { + __m64 s = load8888 (*src); + __m64 d = load8888 (*dst); + + *dst = store8888 (in_over (s, srca, vmask, d)); + + w--; + dst++; + src++; + } + + while (w >= 16) + { + __m64 vd0 = *(__m64 *)(dst + 0); + __m64 vd1 = *(__m64 *)(dst + 2); + __m64 vd2 = *(__m64 *)(dst + 4); + __m64 vd3 = *(__m64 *)(dst + 6); + __m64 vd4 = *(__m64 *)(dst + 8); + __m64 vd5 = *(__m64 *)(dst + 10); + __m64 vd6 = *(__m64 *)(dst + 12); + __m64 vd7 = *(__m64 *)(dst + 14); + + __m64 vs0 = *(__m64 *)(src + 0); + __m64 vs1 = *(__m64 *)(src + 2); + __m64 vs2 = *(__m64 *)(src + 4); + __m64 vs3 = *(__m64 *)(src + 6); + __m64 vs4 = *(__m64 *)(src + 8); + __m64 vs5 = *(__m64 *)(src + 10); + __m64 vs6 = *(__m64 *)(src + 12); + __m64 vs7 = *(__m64 *)(src + 14); + + vd0 = (__m64)pack8888 ( + in_over (expand8888 (vs0, 0), srca, vmask, expand8888 (vd0, 0)), + in_over (expand8888 (vs0, 1), srca, vmask, expand8888 (vd0, 1))); + + vd1 = (__m64)pack8888 ( + in_over (expand8888 (vs1, 0), srca, vmask, expand8888 (vd1, 0)), + in_over (expand8888 (vs1, 1), srca, vmask, expand8888 (vd1, 1))); + + vd2 = (__m64)pack8888 ( + in_over (expand8888 (vs2, 0), srca, vmask, expand8888 (vd2, 0)), + in_over (expand8888 (vs2, 1), srca, vmask, expand8888 (vd2, 1))); + + vd3 = (__m64)pack8888 ( + in_over (expand8888 (vs3, 0), srca, vmask, expand8888 (vd3, 0)), + in_over (expand8888 (vs3, 1), srca, vmask, expand8888 (vd3, 1))); + + vd4 = (__m64)pack8888 ( + in_over (expand8888 (vs4, 0), srca, vmask, expand8888 (vd4, 0)), + in_over (expand8888 (vs4, 1), srca, vmask, expand8888 (vd4, 1))); + + vd5 = (__m64)pack8888 ( + in_over (expand8888 (vs5, 0), srca, vmask, expand8888 (vd5, 0)), + in_over (expand8888 (vs5, 1), srca, vmask, expand8888 (vd5, 1))); + + vd6 = (__m64)pack8888 ( + in_over (expand8888 (vs6, 0), srca, vmask, expand8888 (vd6, 0)), + in_over (expand8888 (vs6, 1), srca, vmask, expand8888 (vd6, 1))); + + vd7 = (__m64)pack8888 ( + in_over (expand8888 (vs7, 0), srca, vmask, expand8888 (vd7, 0)), + in_over (expand8888 (vs7, 1), srca, vmask, expand8888 (vd7, 1))); + + *(__m64 *)(dst + 0) = vd0; + *(__m64 *)(dst + 2) = vd1; + *(__m64 *)(dst + 4) = vd2; + *(__m64 *)(dst + 6) = vd3; + *(__m64 *)(dst + 8) = vd4; + *(__m64 *)(dst + 10) = vd5; + *(__m64 *)(dst + 12) = vd6; + *(__m64 *)(dst + 14) = vd7; + + w -= 16; + dst += 16; + src += 16; + } + + while (w) + { + __m64 s = load8888 (*src); + __m64 d = load8888 (*dst); + + *dst = store8888 (in_over (s, srca, vmask, d)); + + w--; + dst++; + src++; + } + } + + _mm_empty(); +} + +void +fbCompositeSolidMask_nx8x8888mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 src, srca; + CARD32 *dstLine, *dst; + CARD8 *maskLine, *mask; + FbStride dstStride, maskStride; + CARD16 w; + __m64 vsrc, vsrca; + ullong srcsrc; + + CHECKPOINT(); + + fbComposeGetSolid(pSrc, src); + + srca = src >> 24; + if (srca == 0) + return; + + srcsrc = (unsigned long long)src << 32 | src; + + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD8, maskStride, maskLine, 1); + + vsrc = load8888 (src); + vsrca = expand_alpha (vsrc); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + mask = maskLine; + maskLine += maskStride; + w = width; + + CHECKPOINT(); + + while (w && (unsigned long)dst & 7) + { + ullong m = *mask; + + if (m) + { + __m64 vdest = in_over(vsrc, vsrca, expand_alpha_rev ((__m64)m), load8888(*dst)); + *dst = store8888(vdest); + } + + w--; + mask++; + dst++; + } + + CHECKPOINT(); + + while (w >= 2) + { + ullong m0, m1; + m0 = *mask; + m1 = *(mask + 1); + + if (srca == 0xff && (m0 & m1) == 0xff) + { + *(unsigned long long *)dst = srcsrc; + } + else if (m0 | m1) + { + __m64 vdest; + __m64 dest0, dest1; + + vdest = *(__m64 *)dst; + + dest0 = in_over(vsrc, vsrca, expand_alpha_rev ((__m64)m0), expand8888(vdest, 0)); + dest1 = in_over(vsrc, vsrca, expand_alpha_rev ((__m64)m1), expand8888(vdest, 1)); + + *(__m64 *)dst = pack8888(dest0, dest1); + } + + mask += 2; + dst += 2; + w -= 2; + } + + CHECKPOINT(); + + while (w) + { + ullong m = *mask; + + if (m) + { + __m64 vdest = load8888(*dst); + vdest = in_over(vsrc, vsrca, expand_alpha_rev ((__m64)m), vdest); + *dst = store8888(vdest); + } + + w--; + mask++; + dst++; + } + } + + _mm_empty(); +} + +void +fbCompositeSolidMaskSrc_nx8x8888mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 src, srca; + CARD32 *dstLine, *dst; + CARD8 *maskLine, *mask; + FbStride dstStride, maskStride; + CARD16 w; + __m64 vsrc, vsrca; + ullong srcsrc; + + CHECKPOINT(); + + fbComposeGetSolid(pSrc, src); + + srca = src >> 24; + if (srca == 0) + { + if (fbSolidFillmmx (pDst->pDrawable, xDst, yDst, width, height, 0)) + return; + } + + srcsrc = (unsigned long long)src << 32 | src; + + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD8, maskStride, maskLine, 1); + + vsrc = load8888 (src); + vsrca = expand_alpha (vsrc); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + mask = maskLine; + maskLine += maskStride; + w = width; + + CHECKPOINT(); + + while (w && (unsigned long)dst & 7) + { + ullong m = *mask; + + if (m) + { + __m64 vdest = in(vsrc, expand_alpha_rev ((__m64)m)); + *dst = store8888(vdest); + } + + w--; + mask++; + dst++; + } + + CHECKPOINT(); + + while (w >= 2) + { + ullong m0, m1; + m0 = *mask; + m1 = *(mask + 1); + + if (srca == 0xff && (m0 & m1) == 0xff) + { + *(unsigned long long *)dst = srcsrc; + } + else if (m0 | m1) + { + __m64 vdest; + __m64 dest0, dest1; + + vdest = *(__m64 *)dst; + + dest0 = in(vsrc, expand_alpha_rev ((__m64)m0)); + dest1 = in(vsrc, expand_alpha_rev ((__m64)m1)); + + *(__m64 *)dst = pack8888(dest0, dest1); + } + + mask += 2; + dst += 2; + w -= 2; + } + + CHECKPOINT(); + + while (w) + { + ullong m = *mask; + + if (m) + { + __m64 vdest = load8888(*dst); + vdest = in(vsrc, expand_alpha_rev ((__m64)m)); + *dst = store8888(vdest); + } + + w--; + mask++; + dst++; + } + } + + _mm_empty(); +} + + +void +fbCompositeSolidMask_nx8x0565mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 src, srca; + CARD16 *dstLine, *dst; + CARD8 *maskLine, *mask; + FbStride dstStride, maskStride; + CARD16 w; + __m64 vsrc, vsrca; + unsigned long long srcsrcsrcsrc, src16; + + CHECKPOINT(); + + fbComposeGetSolid(pSrc, src); + + srca = src >> 24; + if (srca == 0) + return; + + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD8, maskStride, maskLine, 1); + + vsrc = load8888 (src); + vsrca = expand_alpha (vsrc); + + src16 = (ullong)pack565(vsrc, _mm_setzero_si64(), 0); + + srcsrcsrcsrc = (ullong)src16 << 48 | (ullong)src16 << 32 | + (ullong)src16 << 16 | (ullong)src16; + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + mask = maskLine; + maskLine += maskStride; + w = width; + + CHECKPOINT(); + + while (w && (unsigned long)dst & 7) + { + ullong m = *mask; + + if (m) + { + ullong d = *dst; + __m64 vd = (__m64)d; + __m64 vdest = in_over(vsrc, vsrca, expand_alpha_rev ((__m64)m), expand565(vd, 0)); + *dst = (ullong)pack565(vdest, _mm_setzero_si64(), 0); + } + + w--; + mask++; + dst++; + } + + CHECKPOINT(); + + while (w >= 4) + { + ullong m0, m1, m2, m3; + m0 = *mask; + m1 = *(mask + 1); + m2 = *(mask + 2); + m3 = *(mask + 3); + + if (srca == 0xff && (m0 & m1 & m2 & m3) == 0xff) + { + *(unsigned long long *)dst = srcsrcsrcsrc; + } + else if (m0 | m1 | m2 | m3) + { + __m64 vdest; + __m64 vm0, vm1, vm2, vm3; + + vdest = *(__m64 *)dst; + + vm0 = (__m64)m0; + vdest = pack565(in_over(vsrc, vsrca, expand_alpha_rev(vm0), expand565(vdest, 0)), vdest, 0); + vm1 = (__m64)m1; + vdest = pack565(in_over(vsrc, vsrca, expand_alpha_rev(vm1), expand565(vdest, 1)), vdest, 1); + vm2 = (__m64)m2; + vdest = pack565(in_over(vsrc, vsrca, expand_alpha_rev(vm2), expand565(vdest, 2)), vdest, 2); + vm3 = (__m64)m3; + vdest = pack565(in_over(vsrc, vsrca, expand_alpha_rev(vm3), expand565(vdest, 3)), vdest, 3); + + *(__m64 *)dst = vdest; + } + + w -= 4; + mask += 4; + dst += 4; + } + + CHECKPOINT(); + + while (w) + { + ullong m = *mask; + + if (m) + { + ullong d = *dst; + __m64 vd = (__m64)d; + __m64 vdest = in_over(vsrc, vsrca, expand_alpha_rev ((__m64)m), expand565(vd, 0)); + *dst = (ullong)pack565(vdest, _mm_setzero_si64(), 0); + } + + w--; + mask++; + dst++; + } + } + + _mm_empty(); +} + +void +fbCompositeSrc_8888RevNPx0565mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD16 *dstLine, *dst; + CARD32 *srcLine, *src; + FbStride dstStride, srcStride; + CARD16 w; + + CHECKPOINT(); + + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); + fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); + + assert (pSrc->pDrawable == pMask->pDrawable); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + CHECKPOINT(); + + while (w && (unsigned long)dst & 7) + { + __m64 vsrc = load8888 (*src); + ullong d = *dst; + __m64 vdest = expand565 ((__m64)d, 0); + + vdest = pack565(over_rev_non_pre(vsrc, vdest), vdest, 0); + + *dst = (ullong)vdest; + + w--; + dst++; + src++; + } + + CHECKPOINT(); + + while (w >= 4) + { + CARD32 s0, s1, s2, s3; + unsigned char a0, a1, a2, a3; + + s0 = *src; + s1 = *(src + 1); + s2 = *(src + 2); + s3 = *(src + 3); + + a0 = (s0 >> 24); + a1 = (s1 >> 24); + a2 = (s2 >> 24); + a3 = (s3 >> 24); + + if ((a0 & a1 & a2 & a3) == 0xFF) + { + __m64 vdest; + vdest = pack565(invert_colors(load8888(s0)), _mm_setzero_si64(), 0); + vdest = pack565(invert_colors(load8888(s1)), vdest, 1); + vdest = pack565(invert_colors(load8888(s2)), vdest, 2); + vdest = pack565(invert_colors(load8888(s3)), vdest, 3); + + *(__m64 *)dst = vdest; + } + else if (a0 | a1 | a2 | a3) + { + __m64 vdest = *(__m64 *)dst; + + vdest = pack565(over_rev_non_pre(load8888(s0), expand565(vdest, 0)), vdest, 0); + vdest = pack565(over_rev_non_pre(load8888(s1), expand565(vdest, 1)), vdest, 1); + vdest = pack565(over_rev_non_pre(load8888(s2), expand565(vdest, 2)), vdest, 2); + vdest = pack565(over_rev_non_pre(load8888(s3), expand565(vdest, 3)), vdest, 3); + + *(__m64 *)dst = vdest; + } + + w -= 4; + dst += 4; + src += 4; + } + + CHECKPOINT(); + + while (w) + { + __m64 vsrc = load8888 (*src); + ullong d = *dst; + __m64 vdest = expand565 ((__m64)d, 0); + + vdest = pack565(over_rev_non_pre(vsrc, vdest), vdest, 0); + + *dst = (ullong)vdest; + + w--; + dst++; + src++; + } + } + + _mm_empty(); +} + +/* "8888RevNP" is GdkPixbuf's format: ABGR, non premultiplied */ + +void +fbCompositeSrc_8888RevNPx8888mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 *dstLine, *dst; + CARD32 *srcLine, *src; + FbStride dstStride, srcStride; + CARD16 w; + + CHECKPOINT(); + + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); + + assert (pSrc->pDrawable == pMask->pDrawable); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + while (w && (unsigned long)dst & 7) + { + __m64 s = load8888 (*src); + __m64 d = load8888 (*dst); + + *dst = store8888 (over_rev_non_pre (s, d)); + + w--; + dst++; + src++; + } + + while (w >= 2) + { + ullong s0, s1; + unsigned char a0, a1; + __m64 d0, d1; + + s0 = *src; + s1 = *(src + 1); + + a0 = (s0 >> 24); + a1 = (s1 >> 24); + + if ((a0 & a1) == 0xFF) + { + d0 = invert_colors(load8888(s0)); + d1 = invert_colors(load8888(s1)); + + *(__m64 *)dst = pack8888 (d0, d1); + } + else if (a0 | a1) + { + __m64 vdest = *(__m64 *)dst; + + d0 = over_rev_non_pre (load8888(s0), expand8888 (vdest, 0)); + d1 = over_rev_non_pre (load8888(s1), expand8888 (vdest, 1)); + + *(__m64 *)dst = pack8888 (d0, d1); + } + + w -= 2; + dst += 2; + src += 2; + } + + while (w) + { + __m64 s = load8888 (*src); + __m64 d = load8888 (*dst); + + *dst = store8888 (over_rev_non_pre (s, d)); + + w--; + dst++; + src++; + } + } + + _mm_empty(); +} + +void +fbCompositeSolidMask_nx8888x0565Cmmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 src, srca; + CARD16 *dstLine; + CARD32 *maskLine; + FbStride dstStride, maskStride; + __m64 vsrc, vsrca; + + CHECKPOINT(); + + fbComposeGetSolid(pSrc, src); + + srca = src >> 24; + if (srca == 0) + return; + + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD32, maskStride, maskLine, 1); + + vsrc = load8888 (src); + vsrca = expand_alpha (vsrc); + + while (height--) + { + int twidth = width; + CARD32 *p = (CARD32 *)maskLine; + CARD16 *q = (CARD16 *)dstLine; + + while (twidth && ((unsigned long)q & 7)) + { + CARD32 m = *(CARD32 *)p; + + if (m) + { + ullong d = *q; + __m64 vdest = expand565 ((__m64)d, 0); + vdest = pack565 (in_over (vsrc, vsrca, load8888 (m), vdest), vdest, 0); + *q = (ullong)vdest; + } + + twidth--; + p++; + q++; + } + + while (twidth >= 4) + { + CARD32 m0, m1, m2, m3; + + m0 = *p; + m1 = *(p + 1); + m2 = *(p + 2); + m3 = *(p + 3); + + if ((m0 | m1 | m2 | m3)) + { + __m64 vdest = *(__m64 *)q; + + vdest = pack565(in_over(vsrc, vsrca, load8888(m0), expand565(vdest, 0)), vdest, 0); + vdest = pack565(in_over(vsrc, vsrca, load8888(m1), expand565(vdest, 1)), vdest, 1); + vdest = pack565(in_over(vsrc, vsrca, load8888(m2), expand565(vdest, 2)), vdest, 2); + vdest = pack565(in_over(vsrc, vsrca, load8888(m3), expand565(vdest, 3)), vdest, 3); + + *(__m64 *)q = vdest; + } + twidth -= 4; + p += 4; + q += 4; + } + + while (twidth) + { + CARD32 m; + + m = *(CARD32 *)p; + if (m) + { + ullong d = *q; + __m64 vdest = expand565((__m64)d, 0); + vdest = pack565 (in_over(vsrc, vsrca, load8888(m), vdest), vdest, 0); + *q = (ullong)vdest; + } + + twidth--; + p++; + q++; + } + + maskLine += maskStride; + dstLine += dstStride; + } + + _mm_empty (); +} + +void +fbCompositeSrcAdd_8000x8000mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD8 *dstLine, *dst; + CARD8 *srcLine, *src; + FbStride dstStride, srcStride; + CARD16 w; + CARD8 s, d; + CARD16 t; + + CHECKPOINT(); + + fbComposeGetStart (pSrc, xSrc, ySrc, CARD8, srcStride, srcLine, 1); + fbComposeGetStart (pDst, xDst, yDst, CARD8, dstStride, dstLine, 1); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + while (w && (unsigned long)dst & 7) + { + s = *src; + d = *dst; + t = d + s; + s = t | (0 - (t >> 8)); + *dst = s; + + dst++; + src++; + w--; + } + + while (w >= 8) + { + *(__m64*)dst = _mm_adds_pu8(*(__m64*)src, *(__m64*)dst); + dst += 8; + src += 8; + w -= 8; + } + + while (w) + { + s = *src; + d = *dst; + t = d + s; + s = t | (0 - (t >> 8)); + *dst = s; + + dst++; + src++; + w--; + } + } + + _mm_empty(); +} + +void +fbCompositeSrcAdd_8888x8888mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 *dstLine, *dst; + CARD32 *srcLine, *src; + FbStride dstStride, srcStride; + CARD16 w; + + CHECKPOINT(); + + fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + while (w && (unsigned long)dst & 7) + { + *dst = _mm_cvtsi64_si32(_mm_adds_pu8(_mm_cvtsi32_si64(*src), + _mm_cvtsi32_si64(*dst))); + dst++; + src++; + w--; + } + + while (w >= 2) + { + *(ullong*)dst = (ullong) _mm_adds_pu8(*(__m64*)src, *(__m64*)dst); + dst += 2; + src += 2; + w -= 2; + } + + if (w) + { + *dst = _mm_cvtsi64_si32(_mm_adds_pu8(_mm_cvtsi32_si64(*src), + _mm_cvtsi32_si64(*dst))); + + } + } + + _mm_empty(); +} + +Bool +fbSolidFillmmx (FbPixels *pDraw, + int x, + int y, + int width, + int height, + FbBits xor) +{ + FbStride stride; + int bpp; + ullong fill; + __m64 vfill; + CARD32 byte_width; + CARD8 *byte_line; + FbBits *bits; + int xoff, yoff; + + CHECKPOINT(); + + fbGetDrawable(pDraw, bits, stride, bpp, xoff, yoff); + + if (bpp == 16 && (xor >> 16 != (xor & 0xffff))) + return FALSE; + + if (bpp != 16 && bpp != 32) + return FALSE; + + if (bpp == 16) + { + stride = stride * sizeof (FbBits) / 2; + byte_line = (CARD8 *)(((CARD16 *)bits) + stride * (y + yoff) + (x + xoff)); + byte_width = 2 * width; + stride *= 2; + } + else + { + stride = stride * sizeof (FbBits) / 4; + byte_line = (CARD8 *)(((CARD32 *)bits) + stride * (y + yoff) + (x + xoff)); + byte_width = 4 * width; + stride *= 4; + } + + fill = ((ullong)xor << 32) | xor; + vfill = (__m64)fill; + + while (height--) + { + int w; + CARD8 *d = byte_line; + byte_line += stride; + w = byte_width; + + while (w >= 2 && ((unsigned long)d & 3)) + { + *(CARD16 *)d = xor; + w -= 2; + d += 2; + } + + while (w >= 4 && ((unsigned long)d & 7)) + { + *(CARD32 *)d = xor; + + w -= 4; + d += 4; + } + + while (w >= 64) + { + *(__m64*) (d + 0) = vfill; + *(__m64*) (d + 8) = vfill; + *(__m64*) (d + 16) = vfill; + *(__m64*) (d + 24) = vfill; + *(__m64*) (d + 32) = vfill; + *(__m64*) (d + 40) = vfill; + *(__m64*) (d + 48) = vfill; + *(__m64*) (d + 56) = vfill; + + w -= 64; + d += 64; + } + while (w >= 4) + { + *(CARD32 *)d = xor; + + w -= 4; + d += 4; + } + if (w >= 2) + { + *(CARD16 *)d = xor; + w -= 2; + d += 2; + } + } + + _mm_empty(); + return TRUE; +} + +Bool +fbCopyAreammx (FbPixels *pSrc, + FbPixels *pDst, + int src_x, + int src_y, + int dst_x, + int dst_y, + int width, + int height) +{ + FbBits * src_bits; + FbStride src_stride; + int src_bpp; + int src_xoff; + int src_yoff; + + FbBits * dst_bits; + FbStride dst_stride; + int dst_bpp; + int dst_xoff; + int dst_yoff; + + CARD8 * src_bytes; + CARD8 * dst_bytes; + int byte_width; + + fbGetDrawable(pSrc, src_bits, src_stride, src_bpp, src_xoff, src_yoff); + fbGetDrawable(pDst, dst_bits, dst_stride, dst_bpp, dst_xoff, dst_yoff); + + if (src_bpp != 16 && src_bpp != 32) + return FALSE; + + if (dst_bpp != 16 && dst_bpp != 32) + return FALSE; + + if (src_bpp != dst_bpp) + { + return FALSE; + } + + if (src_bpp == 16) + { + src_stride = src_stride * sizeof (FbBits) / 2; + dst_stride = dst_stride * sizeof (FbBits) / 2; + src_bytes = (CARD8 *)(((CARD16 *)src_bits) + src_stride * (src_y + src_yoff) + (src_x + src_xoff)); + dst_bytes = (CARD8 *)(((CARD16 *)dst_bits) + dst_stride * (dst_y + dst_yoff) + (dst_x + dst_xoff)); + byte_width = 2 * width; + src_stride *= 2; + dst_stride *= 2; + } + else + { + src_stride = src_stride * sizeof (FbBits) / 4; + dst_stride = dst_stride * sizeof (FbBits) / 4; + src_bytes = (CARD8 *)(((CARD32 *)src_bits) + src_stride * (src_y + src_yoff) + (src_x + src_xoff)); + dst_bytes = (CARD8 *)(((CARD32 *)dst_bits) + dst_stride * (dst_y + dst_yoff) + (dst_x + dst_xoff)); + byte_width = 4 * width; + src_stride *= 4; + dst_stride *= 4; + } + + while (height--) + { + int w; + CARD8 *s = src_bytes; + CARD8 *d = dst_bytes; + src_bytes += src_stride; + dst_bytes += dst_stride; + w = byte_width; + + while (w >= 2 && ((unsigned long)d & 3)) + { + *(CARD16 *)d = *(CARD16 *)s; + w -= 2; + s += 2; + d += 2; + } + + while (w >= 4 && ((unsigned int)d & 7)) + { + *(CARD32 *)d = *(CARD32 *)s; + + w -= 4; + s += 4; + d += 4; + } + + while (w >= 64) + { + *(__m64 *)(d + 0) = *(__m64 *)(s + 0); + *(__m64 *)(d + 8) = *(__m64 *)(s + 8); + *(__m64 *)(d + 16) = *(__m64 *)(s + 16); + *(__m64 *)(d + 24) = *(__m64 *)(s + 24); + *(__m64 *)(d + 32) = *(__m64 *)(s + 32); + *(__m64 *)(d + 40) = *(__m64 *)(s + 40); + *(__m64 *)(d + 48) = *(__m64 *)(s + 48); + *(__m64 *)(d + 56) = *(__m64 *)(s + 56); + w -= 64; + s += 64; + d += 64; + } + while (w >= 4) + { + *(CARD32 *)d = *(CARD32 *)s; + + w -= 4; + s += 4; + d += 4; + } + if (w >= 2) + { + *(CARD16 *)d = *(CARD16 *)s; + w -= 2; + s += 2; + d += 2; + } + } + + _mm_empty(); + return TRUE; +} + +void +fbCompositeCopyAreammx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + fbCopyAreammx (pSrc->pDrawable, + pDst->pDrawable, + xSrc, ySrc, + xDst, yDst, + width, height); +} + +#if !defined(__amd64__) && !defined(__x86_64__) + +enum CPUFeatures { + NoFeatures = 0, + MMX = 0x1, + MMX_Extensions = 0x2, + SSE = 0x6, + SSE2 = 0x8, + CMOV = 0x10 +}; + +static unsigned int detectCPUFeatures(void) { + unsigned int result; + char vendor[13]; + vendor[0] = 0; + vendor[12] = 0; + /* see p. 118 of amd64 instruction set manual Vol3 */ + __asm__ ("push %%ebx\n" + "pushf\n" + "pop %%eax\n" + "mov %%eax, %%ebx\n" + "xor $0x00200000, %%eax\n" + "push %%eax\n" + "popf\n" + "pushf\n" + "pop %%eax\n" + "mov $0x0, %%edx\n" + "xor %%ebx, %%eax\n" + "jz skip\n" + + "mov $0x00000000, %%eax\n" + "cpuid\n" + "mov %%ebx, %1\n" + "mov %%edx, %2\n" + "mov %%ecx, %3\n" + "mov $0x00000001, %%eax\n" + "cpuid\n" + "skip:\n" + "pop %%ebx\n" + "mov %%edx, %0\n" + : "=r" (result), + "=m" (vendor[0]), + "=m" (vendor[4]), + "=m" (vendor[8]) + : + : "%eax", "%ecx", "%edx" + ); + + unsigned int features = 0; + if (result) { + /* result now contains the standard feature bits */ + if (result & (1 << 15)) + features |= CMOV; + if (result & (1 << 23)) + features |= MMX; + if (result & (1 << 25)) + features |= SSE; + if (result & (1 << 26)) + features |= SSE2; + if ((result & MMX) && !(result & SSE) && (strcmp(vendor, "AuthenticAMD") == 0)) { + /* check for AMD MMX extensions */ + + unsigned int result; + __asm__("push %%ebx\n" + "mov $0x80000000, %%eax\n" + "cpuid\n" + "xor %%edx, %%edx\n" + "cmp $0x1, %%eax\n" + "jge skip2\n" + "mov $0x80000001, %%eax\n" + "cpuid\n" + "skip2:\n" + "mov %%edx, %0\n" + "pop %%ebx\n" + : "=r" (result) + : + : "%eax", "%ecx", "%edx" + ); + if (result & (1<<22)) + features |= MMX_Extensions; + } + } + return features; +} + +Bool +fbHaveMMX (void) +{ + static Bool initialized = FALSE; + static Bool mmx_present; + + if (!initialized) + { + unsigned int features = detectCPUFeatures(); + mmx_present = (features & (MMX|MMX_Extensions)) == (MMX|MMX_Extensions); + initialized = TRUE; + } + + return mmx_present; +} +#endif /* __amd64__ */ + + +#endif /* RENDER */ diff --git a/gfx/cairo/libpixman/src/fbmmx.h b/gfx/cairo/libpixman/src/fbmmx.h new file mode 100644 index 000000000000..d9de56a57a73 --- /dev/null +++ b/gfx/cairo/libpixman/src/fbmmx.h @@ -0,0 +1,228 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * Copyright © 2005 Trolltech AS + * + * 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 not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Red Hat makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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: Søren Sandmann (sandmann@redhat.com) + * Lars Knoll (lars@trolltech.com) + * + * Based on work by Owen Taylor + */ +#ifdef USE_MMX + +#if !defined(__amd64__) && !defined(__x86_64__) +Bool fbHaveMMX(void); +#else +#define fbHaveMMX() TRUE +#endif + +#else +#define fbHaveMMX() FALSE +#endif + +#ifdef USE_MMX + +void fbComposeSetupMMX(void); + +void fbCompositeSolidMask_nx8888x0565Cmmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSrcAdd_8888x8888mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSolidMask_nx8888x8888Cmmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSolidMask_nx8x8888mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSolidMaskSrc_nx8x8888mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSrcAdd_8000x8000mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSrc_8888RevNPx8888mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSrc_8888RevNPx0565mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSolid_nx8888mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSolid_nx0565mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSolidMask_nx8x0565mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSrc_x888x8x8888mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSrc_8888x8x8888mmx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +Bool fbCopyAreammx (FbPixels *pSrc, + FbPixels *pDst, + int src_x, + int src_y, + int dst_x, + int dst_y, + int width, + int height); +void fbCompositeCopyAreammx (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +Bool fbSolidFillmmx (FbPixels *pDraw, + int x, + int y, + int width, + int height, + FbBits xor); + +#endif /* USE_MMX */ diff --git a/gfx/cairo/libpixman/src/fbpict.c b/gfx/cairo/libpixman/src/fbpict.c new file mode 100644 index 000000000000..f1a166244b46 --- /dev/null +++ b/gfx/cairo/libpixman/src/fbpict.c @@ -0,0 +1,1904 @@ +/* + * $Id: fbpict.c,v 1.1 2005/08/20 05:34:02 vladimir%pobox.com Exp $ + * + * Copyright © 2000 SuSE, 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 SuSE not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. SuSE makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE + * 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: Keith Packard, SuSE, Inc. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "pixman-xserver-compat.h" + +#ifdef RENDER + +#include "fbpict.h" +#include "fbmmx.h" + +static CARD32 +fbOver (CARD32 x, CARD32 y) +{ + CARD16 a = ~x >> 24; + CARD16 t; + CARD32 m,n,o,p; + + m = FbOverU(x,y,0,a,t); + n = FbOverU(x,y,8,a,t); + o = FbOverU(x,y,16,a,t); + p = FbOverU(x,y,24,a,t); + return m|n|o|p; +} + +static CARD32 +fbOver24 (CARD32 x, CARD32 y) +{ + CARD16 a = ~x >> 24; + CARD16 t; + CARD32 m,n,o; + + m = FbOverU(x,y,0,a,t); + n = FbOverU(x,y,8,a,t); + o = FbOverU(x,y,16,a,t); + return m|n|o; +} + +static CARD32 +fbIn (CARD32 x, CARD8 y) +{ + CARD16 a = y; + CARD16 t; + CARD32 m,n,o,p; + + m = FbInU(x,0,a,t); + n = FbInU(x,8,a,t); + o = FbInU(x,16,a,t); + p = FbInU(x,24,a,t); + return m|n|o|p; +} + +static CARD32 +fbIn24 (CARD32 x, CARD8 y) +{ + CARD16 a = y; + CARD16 t; + CARD32 m,n,o,p; + + m = FbInU(x,0,a,t); + n = FbInU(x,8,a,t); + o = FbInU(x,16,a,t); + p = (y << 24); + return m|n|o|p; +} + +#define genericCombine24(a,b,c,d) (((a)*(c)+(b)*(d))) + +/* + * This macro does src IN mask OVER dst when src and dst are 0888. + * If src has alpha, this will not work + */ +#define inOver0888(alpha, source, destval, dest) { \ + CARD32 dstrb=destval&0xFF00FF; CARD32 dstag=(destval>>8)&0xFF00FF; \ + CARD32 drb=((source&0xFF00FF)-dstrb)*alpha; CARD32 dag=(((source>>8)&0xFF00FF)-dstag)*alpha; \ + dest =((((drb>>8) + dstrb) & 0x00FF00FF) | ((((dag>>8) + dstag) << 8) & 0xFF00FF00)); \ + } + +/* + * This macro does src IN mask OVER dst when src and dst are 0565 and + * mask is a 5-bit alpha value. Again, if src has alpha, this will not + * work. + */ + +#define inOver0565(alpha, source, destval, dest) { \ + CARD16 dstrb = destval & 0xf81f; CARD16 dstg = destval & 0x7e0; \ + CARD32 drb = ((source&0xf81f)-dstrb)*alpha; CARD32 dg=((source & 0x7e0)-dstg)*alpha; \ + dest = ((((drb>>5) + dstrb)&0xf81f) | (((dg>>5) + dstg) & 0x7e0)); \ + } + +#define inOver2x0565(alpha, source, destval, dest) { \ + CARD32 dstrb = destval & 0x07e0f81f; CARD32 dstg = (destval & 0xf81f07e0)>>5; \ + CARD32 drb = ((source&0x07e0f81f)-dstrb)*alpha; CARD32 dg=(((source & 0xf81f07e0)>>5)-dstg)*alpha; \ + dest = ((((drb>>5) + dstrb)&0x07e0f81f) | ((((dg>>5) + dstg)<<5) & 0xf81f07e0)); \ + } + +#if IMAGE_BYTE_ORDER == LSBFirst + #define setupPackedReader(count,temp,where,workingWhere,workingVal) count=(long)where; \ + temp=count&3; \ + where-=temp; \ + workingWhere=(CARD32 *)where; \ + workingVal=*workingWhere++; \ + count=4-temp; \ + workingVal>>=(8*temp) + #define readPacked(where,x,y,z) {if(!(x)) { (x)=4; y=*z++; } where=(y)&0xff; (y)>>=8; (x)--;} + #define readPackedSource(where) readPacked(where,ws,workingSource,wsrc) + #define readPackedDest(where) readPacked(where,wd,workingiDest,widst) + #define writePacked(what) workingoDest>>=8; workingoDest|=(what<<24); ww--; if(!ww) { ww=4; *wodst++=workingoDest; } +#else + #warning "I havn't tested fbCompositeTrans_0888xnx0888() on big endian yet!" + #define setupPackedReader(count,temp,where,workingWhere,workingVal) count=(long)where; \ + temp=count&3; \ + where-=temp; \ + workingWhere=(CARD32 *)where; \ + workingVal=*workingWhere++; \ + count=4-temp; \ + workingVal<<=(8*temp) + #define readPacked(where,x,y,z) {if(!(x)) { (x)=4; y=*z++; } where=(y)>>24; (y)<<=8; (x)--;} + #define readPackedSource(where) readPacked(where,ws,workingSource,wsrc) + #define readPackedDest(where) readPacked(where,wd,workingiDest,widst) + #define writePacked(what) workingoDest<<=8; workingoDest|=what; ww--; if(!ww) { ww=4; *wodst++=workingoDest; } +#endif +/* + * Naming convention: + * + * opSRCxMASKxDST + */ + +static void +fbCompositeSolidMask_nx8x8888 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 src, srca; + CARD32 *dstLine, *dst, d, dstMask; + CARD8 *maskLine, *mask, m; + FbStride dstStride, maskStride; + CARD16 w; + + fbComposeGetSolid(pSrc, src); + + dstMask = FbFullMask (pDst->pDrawable->depth); + srca = src >> 24; + if (src == 0) + return; + + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD8, maskStride, maskLine, 1); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + mask = maskLine; + maskLine += maskStride; + w = width; + + while (w--) + { + m = *mask++; + if (m == 0xff) + { + if (srca == 0xff) + *dst = src & dstMask; + else + *dst = fbOver (src, *dst) & dstMask; + } + else if (m) + { + d = fbIn (src, m); + *dst = fbOver (d, *dst) & dstMask; + } + dst++; + } + } +} + +static void +fbCompositeSolidMask_nx8888x8888C (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 src, srca; + CARD32 *dstLine, *dst, d, dstMask; + CARD32 *maskLine, *mask, ma; + FbStride dstStride, maskStride; + CARD16 w; + CARD32 m, n, o, p; + + fbComposeGetSolid(pSrc, src); + + dstMask = FbFullMask (pDst->pDrawable->depth); + srca = src >> 24; + if (src == 0) + return; + + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD32, maskStride, maskLine, 1); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + mask = maskLine; + maskLine += maskStride; + w = width; + + while (w--) + { + ma = *mask++; + if (ma == 0xffffffff) + { + if (srca == 0xff) + *dst = src & dstMask; + else + *dst = fbOver (src, *dst) & dstMask; + } + else if (ma) + { + d = *dst; +#define FbInOverC(src,srca,msk,dst,i,result) { \ + CARD16 __a = FbGet8(msk,i); \ + CARD32 __t, __ta; \ + CARD32 __i; \ + __t = FbIntMult (FbGet8(src,i), __a,__i); \ + __ta = (CARD8) ~FbIntMult (srca, __a,__i); \ + __t = __t + FbIntMult(FbGet8(dst,i),__ta,__i); \ + __t = (CARD32) (CARD8) (__t | (-(__t >> 8))); \ + result = __t << (i); \ +} + FbInOverC (src, srca, ma, d, 0, m); + FbInOverC (src, srca, ma, d, 8, n); + FbInOverC (src, srca, ma, d, 16, o); + FbInOverC (src, srca, ma, d, 24, p); + *dst = m|n|o|p; + } + dst++; + } + } +} + +#define srcAlphaCombine24(a,b) genericCombine24(a,b,srca,srcia) +static void +fbCompositeSolidMask_nx8x0888 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 src, srca, srcia; + CARD8 *dstLine, *dst, *edst; + CARD8 *maskLine, *mask, m; + FbStride dstStride, maskStride; + CARD16 w; + CARD32 rs,gs,bs,rd,gd,bd; + + fbComposeGetSolid(pSrc, src); + + srca = src >> 24; + srcia = 255-srca; + if (src == 0) + return; + + rs=src&0xff; + gs=(src>>8)&0xff; + bs=(src>>16)&0xff; + + fbComposeGetStart (pDst, xDst, yDst, CARD8, dstStride, dstLine, 3); + fbComposeGetStart (pMask, xMask, yMask, CARD8, maskStride, maskLine, 1); + + while (height--) + { + /* fixme: cleanup unused */ + unsigned long wt,wd; + CARD32 workingiDest; + CARD32 *widst; + + edst=dst = dstLine; + dstLine += dstStride; + mask = maskLine; + maskLine += maskStride; + w = width; + +#ifndef NO_MASKED_PACKED_READ + setupPackedReader(wd,wt,edst,widst,workingiDest); +#endif + + while (w--) + { +#ifndef NO_MASKED_PACKED_READ + readPackedDest(rd); + readPackedDest(gd); + readPackedDest(bd); +#else + rd= *edst++; + gd= *edst++; + bd= *edst++; +#endif + m = *mask++; + if (m == 0xff) + { + if (srca == 0xff) + { + *dst++=rs; + *dst++=gs; + *dst++=bs; + } + else + { + *dst++=(srcAlphaCombine24(rs, rd)>>8); + *dst++=(srcAlphaCombine24(gs, gd)>>8); + *dst++=(srcAlphaCombine24(bs, bd)>>8); + } + } + else if (m) + { + int na=(srca*(int)m)>>8; + int nia=255-na; + *dst++=(genericCombine24(rs, rd, na, nia)>>8); + *dst++=(genericCombine24(gs, gd, na, nia)>>8); + *dst++=(genericCombine24(bs, bd, na, nia)>>8); + } + else + { + dst+=3; + } + } + } +} + +static void +fbCompositeSolidMask_nx8x0565 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 src, srca8, srca5; + CARD16 *dstLine, *dst; + CARD16 d; + CARD32 t; + CARD8 *maskLine, *mask, m; + FbStride dstStride, maskStride; + CARD16 w,src16; + + fbComposeGetSolid(pSrc, src); + + if (src == 0) + return; + + srca8 = (src >> 24); + srca5 = (srca8 >> 3); + + src16 = cvt8888to0565(src); + + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD8, maskStride, maskLine, 1); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + mask = maskLine; + maskLine += maskStride; + w = width; + + while (w--) + { + m = *mask++; + if (m == 0) + dst++; + else if (srca5 == (0xff >> 3)) + { + if (m == 0xff) + *dst++ = src16; + else + { + d = *dst; + m >>= 3; + inOver0565 (m, src16, d, *dst++); + } + } + else + { + d = *dst; + if (m == 0xff) + { + t = fbOver24 (src, cvt0565to0888 (d)); + } + else + { + t = fbIn (src, m); + t = fbOver (t, cvt0565to0888 (d)); + } + *dst++ = cvt8888to0565 (t); + } + } + } +} + +static void +fbCompositeSolidMask_nx8888x0565 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 src, srca8, srca5; + CARD16 *dstLine, *dst; + CARD16 d; + CARD32 *maskLine, *mask; + CARD32 t; + CARD8 m; + FbStride dstStride, maskStride; + CARD16 w, src16; + + fbComposeGetSolid(pSrc, src); + + if (src == 0) + return; + + srca8 = src >> 24; + srca5 = srca8 >> 3; + src16 = cvt8888to0565(src); + + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD32, maskStride, maskLine, 1); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + mask = maskLine; + maskLine += maskStride; + w = width; + + while (w--) + { + m = *mask++ >> 24; + if (m == 0) + dst++; + else if (srca5 == (0xff >> 3)) + { + if (m == 0xff) + *dst++ = src16; + else + { + d = *dst; + m >>= 3; + inOver0565 (m, src16, d, *dst++); + } + } + else + { + if (m == 0xff) + { + d = *dst; + t = fbOver24 (src, cvt0565to0888 (d)); + *dst++ = cvt8888to0565 (t); + } + else + { + d = *dst; + t = fbIn (src, m); + t = fbOver (t, cvt0565to0888 (d)); + *dst++ = cvt8888to0565 (t); + } + } + } + } +} + +static void +fbCompositeSolidMask_nx8888x0565C (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 src, srca; + CARD16 src16; + CARD16 *dstLine, *dst; + CARD32 d; + CARD32 *maskLine, *mask, ma; + FbStride dstStride, maskStride; + CARD16 w; + CARD32 m, n, o; + + fbComposeGetSolid(pSrc, src); + + srca = src >> 24; + if (src == 0) + return; + + src16 = cvt8888to0565(src); + + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD32, maskStride, maskLine, 1); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + mask = maskLine; + maskLine += maskStride; + w = width; + + while (w--) + { + ma = *mask++; + if (ma == 0xffffffff) + { + if (srca == 0xff) + { + *dst = src16; + } + else + { + d = *dst; + d = fbOver24 (src, cvt0565to0888(d)); + *dst = cvt8888to0565(d); + } + } + else if (ma) + { + d = *dst; + d = cvt0565to0888(d); + FbInOverC (src, srca, ma, d, 0, m); + FbInOverC (src, srca, ma, d, 8, n); + FbInOverC (src, srca, ma, d, 16, o); + d = m|n|o; + *dst = cvt8888to0565(d); + } + dst++; + } + } +} + +static void +fbCompositeSrc_8888x8888 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 *dstLine, *dst, dstMask; + CARD32 *srcLine, *src, s; + FbStride dstStride, srcStride; + CARD8 a; + CARD16 w; + + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); + + dstMask = FbFullMask (pDst->pDrawable->depth); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + while (w--) + { + s = *src++; + a = s >> 24; + if (a == 0xff) + *dst = s & dstMask; + else if (a) + *dst = fbOver (s, *dst) & dstMask; + dst++; + } + } +} + +static void +fbCompositeSrc_8888x0888 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD8 *dstLine, *dst; + CARD32 d; + CARD32 *srcLine, *src, s; + CARD8 a; + FbStride dstStride, srcStride; + CARD16 w; + + fbComposeGetStart (pDst, xDst, yDst, CARD8, dstStride, dstLine, 3); + fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + while (w--) + { + s = *src++; + a = s >> 24; + if (a) + { + if (a == 0xff) + d = s; + else + d = fbOver24 (s, Fetch24(dst)); + Store24(dst,d); + } + dst += 3; + } + } +} + +static void +fbCompositeSrc_8888x0565 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD16 *dstLine, *dst; + CARD32 d; + CARD32 *srcLine, *src, s; + CARD8 a; + FbStride dstStride, srcStride; + CARD16 w; + + fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + while (w--) + { + s = *src++; + a = s >> 24; + if (a) + { + if (a == 0xff) + d = s; + else + { + d = *dst; + d = fbOver24 (s, cvt0565to0888(d)); + } + *dst = cvt8888to0565(d); + } + dst++; + } + } +} + + + +static void +fbCompositeSrcAdd_8000x8000 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD8 *dstLine, *dst; + CARD8 *srcLine, *src; + FbStride dstStride, srcStride; + CARD16 w; + CARD8 s, d; + CARD16 t; + + fbComposeGetStart (pSrc, xSrc, ySrc, CARD8, srcStride, srcLine, 1); + fbComposeGetStart (pDst, xDst, yDst, CARD8, dstStride, dstLine, 1); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + while (w--) + { + s = *src++; + if (s) + { + if (s != 0xff) + { + d = *dst; + t = d + s; + s = t | (0 - (t >> 8)); + } + *dst = s; + } + dst++; + } + } +} + +static void +fbCompositeSrcAdd_8888x8888 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 *dstLine, *dst; + CARD32 *srcLine, *src; + FbStride dstStride, srcStride; + CARD16 w; + CARD32 s, d; + CARD16 t; + CARD32 m,n,o,p; + + fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + while (w--) + { + s = *src++; + if (s) + { + if (s != 0xffffffff) + { + d = *dst; + if (d) + { + m = FbAdd(s,d,0,t); + n = FbAdd(s,d,8,t); + o = FbAdd(s,d,16,t); + p = FbAdd(s,d,24,t); + s = m|n|o|p; + } + } + *dst = s; + } + dst++; + } + } +} + +static void +fbCompositeSrcAdd_1000x1000 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + FbBits *dstBits, *srcBits; + FbStride dstStride, srcStride; + int dstBpp, srcBpp; + int dstXoff, dstYoff; + int srcXoff, srcYoff; + + fbGetDrawable(pSrc->pDrawable, srcBits, srcStride, srcBpp, srcXoff, srcYoff); + + fbGetDrawable(pDst->pDrawable, dstBits, dstStride, dstBpp, dstXoff, dstYoff); + + fbBlt (srcBits + srcStride * (ySrc + srcYoff), + srcStride, + xSrc + srcXoff, + + dstBits + dstStride * (yDst + dstYoff), + dstStride, + xDst + dstXoff, + + width, + height, + + GXor, + FB_ALLONES, + srcBpp, + + FALSE, + FALSE); +} + +static void +fbCompositeSolidMask_nx1xn (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + FbBits *dstBits; + FbStip *maskBits; + FbStride dstStride, maskStride; + int dstBpp, maskBpp; + int dstXoff, dstYoff; + int maskXoff, maskYoff; + FbBits src; + + fbComposeGetSolid(pSrc, src); + + if ((src & 0xff000000) != 0xff000000) + { + pixman_compositeGeneral (op, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, yDst, + width, height); + return; + } + FbGetStipPixels (pMask->pixels, maskBits, maskStride, maskBpp, maskXoff, maskYoff); + fbGetDrawable (pDst->pDrawable, dstBits, dstStride, dstBpp, dstXoff, dstYoff); + + switch (dstBpp) { + case 32: + break; + case 24: + break; + case 16: + src = cvt8888to0565(src); + break; + } + + src = fbReplicatePixel (src, dstBpp); + + fbBltOne (maskBits + maskStride * (yMask + maskYoff), + maskStride, + xMask + maskXoff, + + dstBits + dstStride * (yDst + dstYoff), + dstStride, + (xDst + dstXoff) * dstBpp, + dstBpp, + + width * dstBpp, + height, + + 0x0, + src, + FB_ALLONES, + 0x0); +} + +/* prototype to help with merging */ +static void +fbCompositeSrcSrc_nxn (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +/* + * Apply a constant alpha value in an over computation + */ +static void +fbCompositeTrans_0565xnx0565(pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD16 *dstLine, *dst; + CARD16 *srcLine, *src; + FbStride dstStride, srcStride; + CARD16 w; + FbBits mask; + CARD8 maskAlpha; + CARD16 s_16, d_16; + CARD32 s_32, d_32; + + fbComposeGetSolid (pMask, mask); + maskAlpha = mask >> 27; + + if (!maskAlpha) + return; + if (maskAlpha == 0xff) + { + fbCompositeSrcSrc_nxn (PIXMAN_OPERATOR_SRC, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, yDst, + width, height); + return; + } + + fbComposeGetStart (pSrc, xSrc, ySrc, CARD16, srcStride, srcLine, 1); + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); + + while (height--) + { + CARD32 *isrc, *idst; + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + if(((long)src&1)==1) + { + s_16 = *src++; + d_16 = *dst; + inOver0565(maskAlpha, s_16, d_16, *dst++); + w--; + } + isrc=(CARD32 *)src; + if(((long)dst&1)==0) + { + idst=(CARD32 *)dst; + while (w>1) + { + s_32 = *isrc++; + d_32 = *idst; + inOver2x0565(maskAlpha,s_32,d_32,*idst++); + w-=2; + } + dst=(CARD16 *)idst; + } + else + { + while (w > 1) + { + s_32 = *isrc++; +#if IMAGE_BYTE_ORDER == LSBFirst + s_16=s_32&0xffff; +#else + s_16=s_32>>16; +#endif + d_16 = *dst; + inOver0565(maskAlpha, s_16, d_16, *dst++); +#if IMAGE_BYTE_ORDER == LSBFirst + s_16=s_32>>16; +#else + s_16=s_32&0xffff; +#endif + d_16 = *dst; + inOver0565(maskAlpha, s_16, d_16, *dst++); + w-=2; + } + } + src=(CARD16 *)isrc; + if(w!=0) + { + s_16 = *src; + d_16 = *dst; + inOver0565(maskAlpha, s_16, d_16, *dst); + } + } +} + + + +/* macros for "i can't believe it's not fast" packed pixel handling */ +#define alphamaskCombine24(a,b) genericCombine24(a,b,maskAlpha,maskiAlpha) +static void +fbCompositeTrans_0888xnx0888(pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD8 *dstLine, *dst,*idst; + CARD8 *srcLine, *src; + FbStride dstStride, srcStride; + CARD16 w; + FbBits mask; + CARD16 maskAlpha,maskiAlpha; + + fbComposeGetSolid (pMask, mask); + maskAlpha = mask >> 24; + maskiAlpha= 255-maskAlpha; + + if (!maskAlpha) + return; + /* + if (maskAlpha == 0xff) + { + fbCompositeSrc_0888x0888 (op, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, yDst, + width, height); + return; + } + */ + + fbComposeGetStart (pSrc, xSrc, ySrc, CARD8, srcStride, srcLine, 3); + fbComposeGetStart (pDst, xDst, yDst, CARD8, dstStride, dstLine, 3); + + { + unsigned long ws,wt; + CARD32 workingSource; + CARD32 *wsrc, *wdst, *widst; + CARD32 rs, rd, nd; + CARD8 *isrc; + + /* are xSrc and xDst at the same alignment? if not, we need to be complicated :)*/ + /* if(0==0) */ + if( (((xSrc*3)&3)!=((xDst*3)&3)) || ((srcStride&3)!=(dstStride&3))) + { + while (height--) + { + dst = dstLine; + dstLine += dstStride; + isrc = src = srcLine; + srcLine += srcStride; + w = width*3; + + setupPackedReader(ws,wt,isrc,wsrc,workingSource); + + /* get to word aligned */ + switch(!(long)dst&3) + { + case 1: + readPackedSource(rs); + /* *dst++=alphamaskCombine24(rs, *dst)>>8; */ + rd=*dst; /* make gcc happy. hope it doens't cost us too much performance*/ + *dst++=alphamaskCombine24(rs, rd)>>8; + w--; if(w==0) break; + case 2: + readPackedSource(rs); + rd=*dst; + *dst++=alphamaskCombine24(rs, rd)>>8; + w--; if(w==0) break; + case 3: + readPackedSource(rs); + rd=*dst; + *dst++=alphamaskCombine24(rs, rd)>>8; + w--; if(w==0) break; + } + wdst=(CARD32 *)dst; + while (w>3) + { + /* FIXME: write a special readPackedWord macro, which knows how to + * halfword combine + */ + +#if IMAGE_BYTE_ORDER == LSBFirst + rd=*wdst; + readPackedSource(nd); + readPackedSource(rs); + nd|=rs<<8; + readPackedSource(rs); + nd|=rs<<16; + readPackedSource(rs); + nd|=rs<<24; +#else + readPackedSource(nd); + nd<<=24; + readPackedSource(rs); + nd|=rs<<16; + readPackedSource(rs); + nd|=rs<<8; + readPackedSource(rs); + nd|=rs; +#endif + inOver0888(maskAlpha, nd, rd, *wdst++) + w-=4; + } + dst=(CARD8 *)wdst; + switch(w) + { + case 3: + readPackedSource(rs); + rd=*dst; + *dst++=alphamaskCombine24(rs, rd)>>8; + case 2: + readPackedSource(rs); + rd=*dst; + *dst++=alphamaskCombine24(rs, rd)>>8; + case 1: + readPackedSource(rs); + rd=*dst; + *dst++=alphamaskCombine24(rs, rd)>>8; + } + } + } + else + { + while (height--) + { + idst=dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width*3; + /* get to word aligned */ + switch(!(long)src&3) + { + case 1: + rd=alphamaskCombine24(*src++, *dst)>>8; + *dst++=rd; + w--; if(w==0) break; + case 2: + rd=alphamaskCombine24(*src++, *dst)>>8; + *dst++=rd; + w--; if(w==0) break; + case 3: + rd=alphamaskCombine24(*src++, *dst)>>8; + *dst++=rd; + w--; if(w==0) break; + } + wsrc=(CARD32 *)src; + widst=(CARD32 *)dst; + + while(w>3) + { + rs = *wsrc++; + rd = *widst; + inOver0888(maskAlpha, rs, rd, *widst++); + w-=4; + } + src=(CARD8 *)wsrc; + dst=(CARD8 *)widst; + switch(w) + { + case 3: + rd=alphamaskCombine24(*src++, *dst)>>8; + *dst++=rd; + case 2: + rd=alphamaskCombine24(*src++, *dst)>>8; + *dst++=rd; + case 1: + rd=alphamaskCombine24(*src++, *dst)>>8; + *dst++=rd; + } + } + } + } +} + +/* + * Simple bitblt + */ + +static void +fbCompositeSrcSrc_nxn (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + FbBits *dst; + FbBits *src; + FbStride dstStride, srcStride; + int srcXoff, srcYoff; + int dstXoff, dstYoff; + int srcBpp; + int dstBpp; + Bool reverse = FALSE; + Bool upsidedown = FALSE; + + fbGetDrawable(pSrc->pDrawable,src,srcStride,srcBpp,srcXoff,srcYoff); + fbGetDrawable(pDst->pDrawable,dst,dstStride,dstBpp,dstXoff,dstYoff); + + fbBlt (src + (ySrc + srcYoff) * srcStride, + srcStride, + (xSrc + srcXoff) * srcBpp, + + dst + (yDst + dstYoff) * dstStride, + dstStride, + (xDst + dstXoff) * dstBpp, + + (width) * dstBpp, + (height), + + GXcopy, + FB_ALLONES, + dstBpp, + + reverse, + upsidedown); +} + +/* + * Solid fill +void +fbCompositeSolidSrc_nxn (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + +} + */ + +# define mod(a,b) ((b) == 1 ? 0 : (a) >= 0 ? (a) % (b) : (b) - (-a) % (b)) + +void +pixman_composite (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + int xSrc, + int ySrc, + int xMask, + int yMask, + int xDst, + int yDst, + int width, + int height) +{ + pixman_region16_t *region; + int n; + pixman_box16_t *pbox; + CompositeFunc func = 0; + Bool srcRepeat = pSrc->pDrawable && pSrc->repeat == RepeatNormal; + Bool maskRepeat = FALSE; + Bool srcTransform = pSrc->transform != 0; + Bool maskTransform = FALSE; + Bool srcAlphaMap = pSrc->alphaMap != 0; + Bool maskAlphaMap = FALSE; + Bool dstAlphaMap = pDst->alphaMap != 0; + int x_msk, y_msk, x_src, y_src, x_dst, y_dst; + int w, h, w_this, h_this; + +#ifdef USE_MMX + static Bool mmx_setup = FALSE; + if (!mmx_setup) { + fbComposeSetupMMX(); + mmx_setup = TRUE; + } +#endif + + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + if (pSrc->pDrawable) { + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + } + + if (srcRepeat && srcTransform && + pSrc->pDrawable->width == 1 && + pSrc->pDrawable->height == 1) + srcTransform = FALSE; + + if (pMask && pMask->pDrawable) + { + xMask += pMask->pDrawable->x; + yMask += pMask->pDrawable->y; + maskRepeat = pMask->repeat == RepeatNormal; + maskTransform = pMask->transform != 0; +#ifdef PIXMAN_CONVOLUTION + if (pMask->filter == PictFilterConvolution) + maskTransform = TRUE; +#endif + + maskAlphaMap = pMask->alphaMap != 0; + + if (maskRepeat && maskTransform && + pMask->pDrawable->width == 1 && + pMask->pDrawable->height == 1) + maskTransform = FALSE; + } + + if (pSrc->pDrawable && (!pMask || pMask->pDrawable) + && !srcTransform && !maskTransform + && !maskAlphaMap && !srcAlphaMap && !dstAlphaMap +#ifdef PIXMAN_CONVOLUTION + && (pSrc->filter != PictFilterConvolution) + && (!pMask || pMask->filter != PictFilterConvolution)) +#else + && !pMask) +#endif + switch (op) { + case PIXMAN_OPERATOR_OVER: + if (pMask) + { + if (srcRepeat && + pSrc->pDrawable->width == 1 && + pSrc->pDrawable->height == 1) + { + if (PICT_FORMAT_COLOR(pSrc->format_code)) { + switch (pMask->format_code) { + case PICT_a8: + switch (pDst->format_code) { + case PICT_r5g6b5: + case PICT_b5g6r5: +#ifdef USE_MMX + if (fbHaveMMX()) + func = fbCompositeSolidMask_nx8x0565mmx; + else +#endif + func = fbCompositeSolidMask_nx8x0565; + break; + case PICT_r8g8b8: + case PICT_b8g8r8: + func = fbCompositeSolidMask_nx8x0888; + break; + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: + case PICT_a8b8g8r8: + case PICT_x8b8g8r8: +#ifdef USE_MMX + if (fbHaveMMX()) + func = fbCompositeSolidMask_nx8x8888mmx; + else +#endif + func = fbCompositeSolidMask_nx8x8888; + break; + } + break; + case PICT_a8r8g8b8: + if (pMask->componentAlpha) { + switch (pDst->format_code) { + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: +#ifdef USE_MMX + if (fbHaveMMX()) + func = fbCompositeSolidMask_nx8888x8888Cmmx; + else +#endif + func = fbCompositeSolidMask_nx8888x8888C; + break; + case PICT_r5g6b5: +#ifdef USE_MMX + if (fbHaveMMX()) + func = fbCompositeSolidMask_nx8888x0565Cmmx; + else +#endif + func = fbCompositeSolidMask_nx8888x0565C; + break; + } + } + else + { + switch (pDst->format_code) { + case PICT_r5g6b5: + func = fbCompositeSolidMask_nx8888x0565; + break; + } + } + break; + case PICT_a8b8g8r8: + if (pMask->componentAlpha) { + switch (pDst->format_code) { + case PICT_a8b8g8r8: + case PICT_x8b8g8r8: +#ifdef USE_MMX + if (fbHaveMMX()) + func = fbCompositeSolidMask_nx8888x8888Cmmx; + else +#endif + func = fbCompositeSolidMask_nx8888x8888C; + break; + case PICT_b5g6r5: +#ifdef USE_MMX + if (fbHaveMMX()) + func = fbCompositeSolidMask_nx8888x0565Cmmx; + else +#endif + func = fbCompositeSolidMask_nx8888x0565C; + break; + } + } + else + { + switch (pDst->format_code) { + case PICT_b5g6r5: + func = fbCompositeSolidMask_nx8888x0565; + break; + } + } + break; + case PICT_a1: + switch (pDst->format_code) { + case PICT_r5g6b5: + case PICT_b5g6r5: + case PICT_r8g8b8: + case PICT_b8g8r8: + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: + case PICT_a8b8g8r8: + case PICT_x8b8g8r8: + func = fbCompositeSolidMask_nx1xn; + break; + } + } + } + if (func != pixman_compositeGeneral) + srcRepeat = FALSE; + } + else /* has mask and non-repeating source */ + { + if (pSrc->pDrawable == pMask->pDrawable && + xSrc == xMask && ySrc == yMask && + !pMask->componentAlpha) + { + /* source == mask: non-premultiplied data */ + switch (pSrc->format_code) { + case PICT_x8b8g8r8: + switch (pMask->format_code) { + case PICT_a8r8g8b8: + case PICT_a8b8g8r8: + switch (pDst->format_code) { + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: +#ifdef USE_MMX + if (fbHaveMMX()) + func = fbCompositeSrc_8888RevNPx8888mmx; +#endif + break; + case PICT_r5g6b5: +#ifdef USE_MMX + if (fbHaveMMX()) + func = fbCompositeSrc_8888RevNPx0565mmx; +#endif + break; + } + break; + } + break; + case PICT_x8r8g8b8: + switch (pMask->format_code) { + case PICT_a8r8g8b8: + case PICT_a8b8g8r8: + switch (pDst->format_code) { + case PICT_a8b8g8r8: + case PICT_x8b8g8r8: +#ifdef USE_MMX + if (fbHaveMMX()) + func = fbCompositeSrc_8888RevNPx8888mmx; +#endif + break; + case PICT_r5g6b5: +#ifdef USE_MMX + if (fbHaveMMX()) + func = fbCompositeSrc_8888RevNPx0565mmx; +#endif + break; + } + break; + } + break; + } + break; + } + else + { + /* non-repeating source, repeating mask => translucent window */ + if (maskRepeat && + pMask->pDrawable->width == 1 && + pMask->pDrawable->height == 1) + { + switch (pSrc->format_code) { + case PICT_r5g6b5: + case PICT_b5g6r5: + if (pDst->format_code == pSrc->format_code) + func = fbCompositeTrans_0565xnx0565; + break; + case PICT_r8g8b8: + case PICT_b8g8r8: + if (pDst->format_code == pSrc->format_code) + func = fbCompositeTrans_0888xnx0888; + break; +#ifdef USE_MMX + case PICT_x8r8g8b8: + case PICT_x8b8g8r8: + if (pDst->format_code == pSrc->format_code && + pMask->format_code == PICT_a8 && fbHaveMMX()) + func = fbCompositeSrc_x888x8x8888mmx; + break; +#if 0 /* This case fails rendercheck for me */ + case PICT_a8r8g8b8: + if ((pDst->format == PICT_a8r8g8b8 || + pDst->format == PICT_x8r8g8b8) && + pMask->format == PICT_a8 && fbHaveMMX()) + func = fbCompositeSrc_8888x8x8888mmx; + break; +#endif + case PICT_a8b8g8r8: + if ((pDst->format_code == PICT_a8b8g8r8 || + pDst->format_code == PICT_x8b8g8r8) && + pMask->format_code == PICT_a8 && fbHaveMMX()) + func = fbCompositeSrc_8888x8x8888mmx; + break; +#endif + } + + if (func != pixman_compositeGeneral) + maskRepeat = FALSE; + } + } + } + } + else /* no mask */ + { + if (srcRepeat && + pSrc->pDrawable->width == 1 && + pSrc->pDrawable->height == 1) + { + /* no mask and repeating source */ + switch (pSrc->format_code) { + case PICT_a8r8g8b8: + switch (pDst->format_code) { + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: +#ifdef USE_MMX + if (fbHaveMMX()) + { + srcRepeat = FALSE; + func = fbCompositeSolid_nx8888mmx; + } +#endif + break; + case PICT_r5g6b5: +#ifdef USE_MMX + if (fbHaveMMX()) + { + srcRepeat = FALSE; + func = fbCompositeSolid_nx0565mmx; + } +#endif + break; + } + break; + } + } + else + { + /* + * Formats without alpha bits are just Copy with Over + */ + if (pSrc->format_code == pDst->format_code && !PICT_FORMAT_A(pSrc->format_code)) + { +#ifdef USE_MMX + if (fbHaveMMX() && + (pSrc->format_code == PICT_x8r8g8b8 || pSrc->format_code == PICT_x8b8g8r8)) + func = fbCompositeCopyAreammx; + else +#endif + func = fbCompositeSrcSrc_nxn; + } + else switch (pSrc->format_code) { + case PICT_a8r8g8b8: + switch (pDst->format_code) { + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: + func = fbCompositeSrc_8888x8888; + break; + case PICT_r8g8b8: + func = fbCompositeSrc_8888x0888; + break; + case PICT_r5g6b5: + func = fbCompositeSrc_8888x0565; + break; + } + break; + case PICT_a8b8g8r8: + switch (pDst->format_code) { + case PICT_a8b8g8r8: + case PICT_x8b8g8r8: + func = fbCompositeSrc_8888x8888; + break; + case PICT_b8g8r8: + func = fbCompositeSrc_8888x0888; + break; + case PICT_b5g6r5: + func = fbCompositeSrc_8888x0565; + break; + } + break; + } + } + } + break; + case PIXMAN_OPERATOR_ADD: + if (pMask == 0) + { + switch (pSrc->format_code) { + case PICT_a8r8g8b8: + switch (pDst->format_code) { + case PICT_a8r8g8b8: +#ifdef USE_MMX + if (fbHaveMMX()) + func = fbCompositeSrcAdd_8888x8888mmx; + else +#endif + func = fbCompositeSrcAdd_8888x8888; + break; + } + break; + case PICT_a8b8g8r8: + switch (pDst->format_code) { + case PICT_a8b8g8r8: +#ifdef USE_MMX + if (fbHaveMMX()) + func = fbCompositeSrcAdd_8888x8888mmx; + else +#endif + func = fbCompositeSrcAdd_8888x8888; + break; + } + break; + case PICT_a8: + switch (pDst->format_code) { + case PICT_a8: +#ifdef USE_MMX + if (fbHaveMMX()) + func = fbCompositeSrcAdd_8000x8000mmx; + else +#endif + func = fbCompositeSrcAdd_8000x8000; + break; + } + break; + case PICT_a1: + switch (pDst->format_code) { + case PICT_a1: + func = fbCompositeSrcAdd_1000x1000; + break; + } + break; + } + } + break; + case PIXMAN_OPERATOR_SRC: + if (pMask) + { +#ifdef USE_MMX + if (srcRepeat && + pSrc->pDrawable->width == 1 && + pSrc->pDrawable->height == 1) + { + if (pMask->format_code == PICT_a8) + { + switch (pDst->format_code) { + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: + case PICT_a8b8g8r8: + case PICT_x8b8g8r8: + if (fbHaveMMX()) + func = fbCompositeSolidMaskSrc_nx8x8888mmx; + break; + } + } + } +#endif + } + else + { + if (pSrc->format_code == pDst->format_code) + { +#ifdef USE_MMX + if (pSrc->pDrawable != pDst->pDrawable && + (PICT_FORMAT_BPP (pSrc->format_code) == 16 || + PICT_FORMAT_BPP (pSrc->format_code) == 32)) + func = fbCompositeCopyAreammx; + else +#endif + func = fbCompositeSrcSrc_nxn; + } + } + break; + } + + if (!func) { + /* no fast path, use the general code */ + pixman_compositeGeneral(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height); + return; + } + + /* if we are transforming, we handle repeats in IcFetch[a]_transform */ + if (srcTransform) + srcRepeat = 0; + if (maskTransform) + maskRepeat = 0; + + region = pixman_region_create(); + pixman_region_union_rect (region, region, xDst, yDst, width, height); + + if (!FbComputeCompositeRegion (region, + pSrc, + pMask, + pDst, + xSrc, + ySrc, + xMask, + yMask, + xDst, + yDst, + width, + height)) + return; + + n = pixman_region_num_rects (region); + pbox = pixman_region_rects (region); + while (n--) + { + h = pbox->y2 - pbox->y1; + y_src = pbox->y1 - yDst + ySrc; + y_msk = pbox->y1 - yDst + yMask; + y_dst = pbox->y1; + while (h) + { + h_this = h; + w = pbox->x2 - pbox->x1; + x_src = pbox->x1 - xDst + xSrc; + x_msk = pbox->x1 - xDst + xMask; + x_dst = pbox->x1; + if (maskRepeat) + { + y_msk = mod (y_msk, pMask->pDrawable->height); + if (h_this > pMask->pDrawable->height - y_msk) + h_this = pMask->pDrawable->height - y_msk; + } + if (srcRepeat) + { + y_src = mod (y_src, pSrc->pDrawable->height); + if (h_this > pSrc->pDrawable->height - y_src) + h_this = pSrc->pDrawable->height - y_src; + } + while (w) + { + w_this = w; + if (maskRepeat) + { + x_msk = mod (x_msk, pMask->pDrawable->width); + if (w_this > pMask->pDrawable->width - x_msk) + w_this = pMask->pDrawable->width - x_msk; + } + if (srcRepeat) + { + x_src = mod (x_src, pSrc->pDrawable->width); + if (w_this > pSrc->pDrawable->width - x_src) + w_this = pSrc->pDrawable->width - x_src; + } + (*func) (op, pSrc, pMask, pDst, + x_src, y_src, x_msk, y_msk, x_dst, y_dst, + w_this, h_this); + w -= w_this; + x_src += w_this; + x_msk += w_this; + x_dst += w_this; + } + h -= h_this; + y_src += h_this; + y_msk += h_this; + y_dst += h_this; + } + pbox++; + } + pixman_region_destroy (region); +} +slim_hidden_def(pixman_composite); +#endif /* RENDER */ diff --git a/gfx/cairo/libpixman/src/fbpict.h b/gfx/cairo/libpixman/src/fbpict.h new file mode 100644 index 000000000000..528a9f418f6d --- /dev/null +++ b/gfx/cairo/libpixman/src/fbpict.h @@ -0,0 +1,356 @@ +/* + * $Id: fbpict.h,v 1.1 2005/08/20 05:34:02 vladimir%pobox.com Exp $ + * + * Copyright © 2000 Keith Packard + * 2005 Lars Knoll & Zack Rusin, Trolltech + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef _FBPICT_H_ +#define _FBPICT_H_ + +#include "pixman-xserver-compat.h" +#include "renderedge.h" + +#define FbIntMult(a,b,t) ( (t) = (a) * (b) + 0x80, ( ( ( (t)>>8 ) + (t) )>>8 ) ) +#define FbIntDiv(a,b) (((CARD16) (a) * 255) / (b)) + +#define FbGet8(v,i) ((CARD16) (CARD8) ((v) >> i)) + +/* + * There are two ways of handling alpha -- either as a single unified value or + * a separate value for each component, hence each macro must have two + * versions. The unified alpha version has a 'U' at the end of the name, + * the component version has a 'C'. Similarly, functions which deal with + * this difference will have two versions using the same convention. + */ + +#define FbOverU(x,y,i,a,t) ((t) = FbIntMult(FbGet8(y,i),(a),(t)) + FbGet8(x,i),\ + (CARD32) ((CARD8) ((t) | (0 - ((t) >> 8)))) << (i)) + +#define FbOverC(x,y,i,a,t) ((t) = FbIntMult(FbGet8(y,i),FbGet8(a,i),(t)) + FbGet8(x,i),\ + (CARD32) ((CARD8) ((t) | (0 - ((t) >> 8)))) << (i)) + +#define FbInU(x,i,a,t) ((CARD32) FbIntMult(FbGet8(x,i),(a),(t)) << (i)) + +#define FbInC(x,i,a,t) ((CARD32) FbIntMult(FbGet8(x,i),FbGet8(a,i),(t)) << (i)) + +#define FbGen(x,y,i,ax,ay,t,u,v) ((t) = (FbIntMult(FbGet8(y,i),ay,(u)) + \ + FbIntMult(FbGet8(x,i),ax,(v))),\ + (CARD32) ((CARD8) ((t) | \ + (0 - ((t) >> 8)))) << (i)) + +#define FbAdd(x,y,i,t) ((t) = FbGet8(x,i) + FbGet8(y,i), \ + (CARD32) ((CARD8) ((t) | (0 - ((t) >> 8)))) << (i)) + + +#define Alpha(x) ((x) >> 24) +#define Red(x) (((x) >> 16) & 0xff) +#define Green(x) (((x) >> 8) & 0xff) +#define Blue(x) ((x) & 0xff) + +#define fbComposeGetSolid(pict, bits) { \ + FbBits *__bits__; \ + FbStride __stride__; \ + int __bpp__; \ + int __xoff__,__yoff__; \ +\ + fbGetDrawable((pict)->pDrawable,__bits__,__stride__,__bpp__,__xoff__,__yoff__); \ + switch (__bpp__) { \ + case 32: \ + (bits) = *(CARD32 *) __bits__; \ + break; \ + case 24: \ + (bits) = Fetch24 ((CARD8 *) __bits__); \ + break; \ + case 16: \ + (bits) = *(CARD16 *) __bits__; \ + (bits) = cvt0565to0888(bits); \ + break; \ + case 8: \ + (bits) = *(CARD8 *) __bits__; \ + (bits) = (bits) << 24; \ + break; \ + case 1: \ + (bits) = *(CARD32 *) __bits__; \ + (bits) = FbLeftStipBits((bits),1) ? 0xff000000 : 0x00000000;\ + break; \ + default: \ + return; \ + } \ + /* manage missing src alpha */ \ + if ((pict)->image_format.alphaMask == 0) \ + (bits) |= 0xff000000; \ +} + +#define fbComposeGetStart(pict,x,y,type,stride,line,mul) {\ + FbBits *__bits__; \ + FbStride __stride__; \ + int __bpp__; \ + int __xoff__,__yoff__; \ +\ + fbGetDrawable((pict)->pDrawable,__bits__,__stride__,__bpp__,__xoff__,__yoff__); \ + (stride) = __stride__ * sizeof (FbBits) / sizeof (type); \ + (line) = ((type *) __bits__) + (stride) * ((y) + __yoff__) + (mul) * ((x) + __xoff__); \ +} + +#define cvt8888to0565(s) ((((s) >> 3) & 0x001f) | \ + (((s) >> 5) & 0x07e0) | \ + (((s) >> 8) & 0xf800)) +#define cvt0565to0888(s) (((((s) << 3) & 0xf8) | (((s) >> 2) & 0x7)) | \ + ((((s) << 5) & 0xfc00) | (((s) >> 1) & 0x300)) | \ + ((((s) << 8) & 0xf80000) | (((s) << 3) & 0x70000))) + +#if IMAGE_BYTE_ORDER == MSBFirst +#define Fetch24(a) ((unsigned long) (a) & 1 ? \ + ((*(a) << 16) | *((CARD16 *) ((a)+1))) : \ + ((*((CARD16 *) (a)) << 8) | *((a)+2))) +#define Store24(a,v) ((unsigned long) (a) & 1 ? \ + ((*(a) = (CARD8) ((v) >> 16)), \ + (*((CARD16 *) ((a)+1)) = (CARD16) (v))) : \ + ((*((CARD16 *) (a)) = (CARD16) ((v) >> 8)), \ + (*((a)+2) = (CARD8) (v)))) +#else +#define Fetch24(a) ((unsigned long) (a) & 1 ? \ + ((*(a)) | (*((CARD16 *) ((a)+1)) << 8)) : \ + ((*((CARD16 *) (a))) | (*((a)+2) << 16))) +#define Store24(a,v) ((unsigned long) (a) & 1 ? \ + ((*(a) = (CARD8) (v)), \ + (*((CARD16 *) ((a)+1)) = (CARD16) ((v) >> 8))) : \ + ((*((CARD16 *) (a)) = (CARD16) (v)),\ + (*((a)+2) = (CARD8) ((v) >> 16)))) +#endif + +/* + The methods below use some tricks to be able to do two color + components at the same time. +*/ + +/* + x_c = (x_c * a) / 255 +*/ +#define FbByteMul(x, a) do { \ + CARD32 t = ((x & 0xff00ff) * a) + 0x800080; \ + t = (t + ((t >> 8) & 0xff00ff)) >> 8; \ + t &= 0xff00ff; \ + \ + x = (((x >> 8) & 0xff00ff) * a) + 0x800080; \ + x = (x + ((x >> 8) & 0xff00ff)); \ + x &= 0xff00ff00; \ + x += t; \ + } while (0) + +/* + x_c = (x_c * a) / 255 + y +*/ +#define FbByteMulAdd(x, a, y) do { \ + CARD32 t = ((x & 0xff00ff) * a) + 0x800080; \ + t = (t + ((t >> 8) & 0xff00ff)) >> 8; \ + t &= 0xff00ff; \ + t += y & 0xff00ff; \ + t |= 0x1000100 - ((t >> 8) & 0xff00ff); \ + t &= 0xff00ff; \ + \ + x = (((x >> 8) & 0xff00ff) * a) + 0x800080; \ + x = (x + ((x >> 8) & 0xff00ff)) >> 8; \ + x &= 0xff00ff; \ + x += (y >> 8) & 0xff00ff; \ + x |= 0x1000100 - ((t >> 8) & 0xff00ff); \ + x &= 0xff00ff; \ + x <<= 8; \ + x += t; \ + } while (0) + +/* + x_c = (x_c * a + y_c * b) / 255 +*/ +#define FbByteAddMul(x, a, y, b) do { \ + CARD32 t; \ + CARD32 r = (x >> 24) * a + (y >> 24) * b + 0x80; \ + r += (r >> 8); \ + r >>= 8; \ + \ + t = (x & 0xff00) * a + (y & 0xff00) * b + 0x8000; \ + t += (t >> 8); \ + t >>= 16; \ + \ + t |= r << 16; \ + t |= 0x1000100 - ((t >> 8) & 0xff00ff); \ + t &= 0xff00ff; \ + t <<= 8; \ + \ + r = ((x >> 16) & 0xff) * a + ((y >> 16) & 0xff) * b + 0x80; \ + r += (r >> 8); \ + r >>= 8; \ + \ + x = (x & 0xff) * a + (y & 0xff) * b + 0x80; \ + x += (x >> 8); \ + x >>= 8; \ + x |= r << 16; \ + x |= 0x1000100 - ((x >> 8) & 0xff00ff); \ + x &= 0xff00ff; \ + x |= t; \ +} while (0) + +/* + x_c = (x_c * a + y_c *b) / 256 +*/ +#define FbByteAddMul_256(x, a, y, b) do { \ + CARD32 t = (x & 0xff00ff) * a + (y & 0xff00ff) * b; \ + t >>= 8; \ + t &= 0xff00ff; \ + \ + x = ((x >> 8) & 0xff00ff) * a + ((y >> 8) & 0xff00ff) * b; \ + x &= 0xff00ff00; \ + x += t; \ +} while (0) +/* + x_c = (x_c * a_c) / 255 +*/ +#define FbByteMulC(x, a) do { \ + CARD32 t; \ + CARD32 r = (x & 0xff) * (a & 0xff); \ + r |= (x & 0xff0000) * ((a >> 16) & 0xff); \ + r += 0x800080; \ + r = (r + ((r >> 8) & 0xff00ff)) >> 8; \ + r &= 0xff00ff; \ + \ + x >>= 8; \ + t = (x & 0xff) * ((a >> 8) & 0xff); \ + t |= (x & 0xff0000) * (a >> 24); \ + t += 0x800080; \ + t = t + ((t >> 8) & 0xff00ff); \ + x = r | (t & 0xff00ff00); \ + \ + } while (0) + +/* + x_c = (x_c * a) / 255 + y +*/ +#define FbByteMulAddC(x, a, y) do { \ + CARD32 t; \ + CARD32 r = (x & 0xff) * (a & 0xff); \ + r |= (x & 0xff0000) * ((a >> 16) & 0xff); \ + r += 0x800080; \ + r = (r + ((r >> 8) & 0xff00ff)) >> 8; \ + r &= 0xff00ff; \ + r += y & 0xff00ff; \ + r |= 0x1000100 - ((r >> 8) & 0xff00ff); \ + r &= 0xff00ff; \ + \ + x >>= 8; \ + t = (x & 0xff) * ((a >> 8) & 0xff); \ + t |= (x & 0xff0000) * (a >> 24); \ + t += 0x800080; \ + t = (t + ((t >> 8) & 0xff00ff)) >> 8; \ + t &= 0xff00ff; \ + t += (y >> 8) & 0xff00ff; \ + t |= 0x1000100 - ((t >> 8) & 0xff00ff); \ + t &= 0xff00ff; \ + x = r | (t << 8); \ + } while (0) + +/* + x_c = (x_c * a_c + y_c * b) / 255 +*/ +#define FbByteAddMulC(x, a, y, b) do { \ + CARD32 t; \ + CARD32 r = (x >> 24) * (a >> 24) + (y >> 24) * b + 0x80; \ + r += (r >> 8); \ + r >>= 8; \ + \ + t = (x & 0xff00) * ((a >> 8) & 0xff) + (y & 0xff00) * b + 0x8000; \ + t += (t >> 8); \ + t >>= 16; \ + \ + t |= r << 16; \ + t |= 0x1000100 - ((t >> 8) & 0xff00ff); \ + t &= 0xff00ff; \ + t <<= 8; \ + \ + r = ((x >> 16) & 0xff) * ((a >> 16) & 0xff) + ((y >> 16) & 0xff) * b + 0x80; \ + r += (r >> 8); \ + r >>= 8; \ + \ + x = (x & 0xff) * (a & 0xff) + (y & 0xff) * b + 0x80; \ + x += (x >> 8); \ + x >>= 8; \ + x |= r << 16; \ + x |= 0x1000100 - ((x >> 8) & 0xff00ff); \ + x &= 0xff00ff; \ + x |= t; \ +} while (0) + +/* + x_c = min(x_c + y_c, 255) +*/ +#define FbByteAdd(x, y) do { \ + CARD32 t; \ + CARD32 r = (x & 0xff00ff) + (y & 0xff00ff); \ + r |= 0x1000100 - ((r >> 8) & 0xff00ff); \ + r &= 0xff00ff; \ + \ + t = ((x >> 8) & 0xff00ff) + ((y >> 8) & 0xff00ff); \ + t |= 0x1000100 - ((t >> 8) & 0xff00ff); \ + r |= (t & 0xff00ff) << 8; \ + x = r; \ + } while (0) + +#define div_255(x) (((x) + 0x80 + (((x) + 0x80) >> 8)) >> 8) + +#if defined(__i386__) && defined(__GNUC__) +#define FASTCALL __attribute__((regparm(3))) +#else +#define FASTCALL +#endif + +#if defined(__GNUC__) +#define INLINE __inline__ +#else +#define INLINE +#endif + +typedef struct _FbComposeData { + CARD8 op; + PicturePtr src; + PicturePtr mask; + PicturePtr dest; + INT16 xSrc; + INT16 ySrc; + INT16 xMask; + INT16 yMask; + INT16 xDest; + INT16 yDest; + CARD16 width; + CARD16 height; +} FbComposeData; + +typedef FASTCALL void (*CombineMaskU) (CARD32 *src, const CARD32 *mask, int width); +typedef FASTCALL void (*CombineFuncU) (CARD32 *dest, const CARD32 *src, int width); +typedef FASTCALL void (*CombineFuncC) (CARD32 *dest, CARD32 *src, CARD32 *mask, int width); + +typedef struct _FbComposeFunctions { + CombineFuncU *combineU; + CombineFuncC *combineC; + CombineMaskU combineMaskU; +} FbComposeFunctions; + +#endif /* _FBPICT_H_ */ diff --git a/gfx/cairo/libpixman/src/ic.c b/gfx/cairo/libpixman/src/ic.c index 231fb57dbc7c..6bdaba5ad129 100644 --- a/gfx/cairo/libpixman/src/ic.c +++ b/gfx/cairo/libpixman/src/ic.c @@ -21,113 +21,146 @@ * Author: Keith Packard, SuSE, Inc. */ -#include "icint.h" +#include "pixman-xserver-compat.h" +#include "fbpict.h" #define cvt8888to0565(s) ((((s) >> 3) & 0x001f) | \ (((s) >> 5) & 0x07e0) | \ (((s) >> 8) & 0xf800)) -#define cvt0565to8888(s) (((((s) << 3) & 0xf8) | (((s) >> 2) & 0x7)) | \ +#define cvt0565to0888(s) (((((s) << 3) & 0xf8) | (((s) >> 2) & 0x7)) | \ ((((s) << 5) & 0xfc00) | (((s) >> 1) & 0x300)) | \ ((((s) << 8) & 0xf80000) | (((s) << 3) & 0x70000))) #if IMAGE_BYTE_ORDER == MSBFirst #define Fetch24(a) ((unsigned long) (a) & 1 ? \ - ((*(a) << 16) | *((uint16_t *) ((a)+1))) : \ - ((*((uint16_t *) (a)) << 8) | *((a)+2))) + ((*(a) << 16) | *((CARD16 *) ((a)+1))) : \ + ((*((CARD16 *) (a)) << 8) | *((a)+2))) #define Store24(a,v) ((unsigned long) (a) & 1 ? \ - ((*(a) = (uint8_t) ((v) >> 16)), \ - (*((uint16_t *) ((a)+1)) = (uint16_t) (v))) : \ - ((*((uint16_t *) (a)) = (uint16_t) ((v) >> 8)), \ - (*((a)+2) = (uint8_t) (v)))) + ((*(a) = (CARD8) ((v) >> 16)), \ + (*((CARD16 *) ((a)+1)) = (CARD16) (v))) : \ + ((*((CARD16 *) (a)) = (CARD16) ((v) >> 8)), \ + (*((a)+2) = (CARD8) (v)))) #else #define Fetch24(a) ((unsigned long) (a) & 1 ? \ - ((*(a)) | (*((uint16_t *) ((a)+1)) << 8)) : \ - ((*((uint16_t *) (a))) | (*((a)+2) << 16))) + ((*(a)) | (*((CARD16 *) ((a)+1)) << 8)) : \ + ((*((CARD16 *) (a))) | (*((a)+2) << 16))) #define Store24(a,v) ((unsigned long) (a) & 1 ? \ - ((*(a) = (uint8_t) (v)), \ - (*((uint16_t *) ((a)+1)) = (uint16_t) ((v) >> 8))) : \ - ((*((uint16_t *) (a)) = (uint16_t) (v)),\ - (*((a)+2) = (uint8_t) ((v) >> 16)))) + ((*(a) = (CARD8) (v)), \ + (*((CARD16 *) ((a)+1)) = (CARD16) ((v) >> 8))) : \ + ((*((CARD16 *) (a)) = (CARD16) (v)),\ + (*((a)+2) = (CARD8) ((v) >> 16)))) #endif -static uint32_t -IcOver (uint32_t x, uint32_t y) +static CARD32 +fbOver (CARD32 x, CARD32 y) { - uint16_t a = ~x >> 24; - uint16_t t; - uint32_t m,n,o,p; + CARD16 a = ~x >> 24; + CARD16 t; + CARD32 m,n,o,p; - m = IcOverU(x,y,0,a,t); - n = IcOverU(x,y,8,a,t); - o = IcOverU(x,y,16,a,t); - p = IcOverU(x,y,24,a,t); + m = FbOverU(x,y,0,a,t); + n = FbOverU(x,y,8,a,t); + o = FbOverU(x,y,16,a,t); + p = FbOverU(x,y,24,a,t); return m|n|o|p; } -static uint32_t -IcOver24 (uint32_t x, uint32_t y) +static CARD32 +fbOver24 (CARD32 x, CARD32 y) { - uint16_t a = ~x >> 24; - uint16_t t; - uint32_t m,n,o; + CARD16 a = ~x >> 24; + CARD16 t; + CARD32 m,n,o; - m = IcOverU(x,y,0,a,t); - n = IcOverU(x,y,8,a,t); - o = IcOverU(x,y,16,a,t); + m = FbOverU(x,y,0,a,t); + n = FbOverU(x,y,8,a,t); + o = FbOverU(x,y,16,a,t); return m|n|o; } -static uint32_t -IcIn (uint32_t x, uint8_t y) +static CARD32 +fbIn (CARD32 x, CARD8 y) { - uint16_t a = y; - uint16_t t; - uint32_t m,n,o,p; + CARD16 a = y; + CARD16 t; + CARD32 m,n,o,p; - m = IcInU(x,0,a,t); - n = IcInU(x,8,a,t); - o = IcInU(x,16,a,t); - p = IcInU(x,24,a,t); + m = FbInU(x,0,a,t); + n = FbInU(x,8,a,t); + o = FbInU(x,16,a,t); + p = FbInU(x,24,a,t); return m|n|o|p; } -#define IcComposeGetSolid(image, bits) { \ - pixman_bits_t *__bits__; \ - IcStride __stride__; \ - int __bpp__; \ - int __xoff__,__yoff__; \ -\ - IcGetPixels((image)->pixels,__bits__,__stride__,__bpp__,__xoff__,__yoff__); \ - switch (__bpp__) { \ - case 32: \ - (bits) = *(uint32_t *) __bits__; \ - break; \ - case 24: \ - (bits) = Fetch24 ((uint8_t *) __bits__); \ - break; \ - case 16: \ - (bits) = *(uint16_t *) __bits__; \ - (bits) = cvt0565to8888(bits); \ - break; \ - default: \ - return; \ - } \ - /* manage missing src alpha */ \ - if ((image)->image_format.alphaMask == 0) \ - (bits) |= 0xff000000; \ +static CARD32 +fbIn24 (CARD32 x, CARD8 y) +{ + CARD16 a = y; + CARD16 t; + CARD32 m,n,o,p; + + m = FbInU(x,0,a,t); + n = FbInU(x,8,a,t); + o = FbInU(x,16,a,t); + p = (y << 24); + return m|n|o|p; } -#define IcComposeGetStart(image,x,y,type,stride,line,mul) {\ - pixman_bits_t *__bits__; \ - IcStride __stride__; \ - int __bpp__; \ - int __xoff__,__yoff__; \ -\ - IcGetPixels((image)->pixels,__bits__,__stride__,__bpp__,__xoff__,__yoff__); \ - (stride) = __stride__ * sizeof (pixman_bits_t) / sizeof (type); \ - (line) = ((type *) __bits__) + (stride) * ((y) - __yoff__) + (mul) * ((x) - __xoff__); \ -} +#define genericCombine24(a,b,c,d) (((a)*(c)+(b)*(d))) +/* + * This macro does src IN mask OVER dst when src and dst are 0888. + * If src has alpha, this will not work + */ +#define inOver0888(alpha, source, destval, dest) { \ + CARD32 dstrb=destval&0xFF00FF; CARD32 dstag=(destval>>8)&0xFF00FF; \ + CARD32 drb=((source&0xFF00FF)-dstrb)*alpha; CARD32 dag=(((source>>8)&0xFF00FF)-dstag)*alpha; \ + dest =((((drb>>8) + dstrb) & 0x00FF00FF) | ((((dag>>8) + dstag) << 8) & 0xFF00FF00)); \ + } + +/* + * This macro does src IN mask OVER dst when src and dst are 0565 and + * mask is a 5-bit alpha value. Again, if src has alpha, this will not + * work. + */ +#define inOver0565(alpha, source, destval, dest) { \ + CARD16 dstrb = destval & 0xf81f; CARD16 dstg = destval & 0x7e0; \ + CARD32 drb = ((source&0xf81f)-dstrb)*alpha; CARD32 dg=((source & 0x7e0)-dstg)*alpha; \ + dest = ((((drb>>5) + dstrb)&0xf81f) | (((dg>>5) + dstg) & 0x7e0)); \ + } + +#define inOver2x0565(alpha, source, destval, dest) { \ + CARD32 dstrb = destval & 0x07e0f81f; CARD32 dstg = (destval & 0xf81f07e0)>>5; \ + CARD32 drb = ((source&0x07e0f81f)-dstrb)*alpha; CARD32 dg=(((source & 0xf81f07e0)>>5)-dstg)*alpha; \ + dest = ((((drb>>5) + dstrb)&0x07e0f81f) | ((((dg>>5) + dstg)<<5) & 0xf81f07e0)); \ + } + +#if IMAGE_BYTE_ORDER == LSBFirst + #define setupPackedReader(count,temp,where,workingWhere,workingVal) count=(int)where; \ + temp=count&3; \ + where-=temp; \ + workingWhere=(CARD32 *)where; \ + workingVal=*workingWhere++; \ + count=4-temp; \ + workingVal>>=(8*temp) + #define readPacked(where,x,y,z) {if(!(x)) { (x)=4; y=*z++; } where=(y)&0xff; (y)>>=8; (x)--;} + #define readPackedSource(where) readPacked(where,ws,workingSource,wsrc) + #define readPackedDest(where) readPacked(where,wd,workingiDest,widst) + #define writePacked(what) workingoDest>>=8; workingoDest|=(what<<24); ww--; if(!ww) { ww=4; *wodst++=workingoDest; } +#else + #warning "I havn't tested fbCompositeTrans_0888xnx0888() on big endian yet!" + #define setupPackedReader(count,temp,where,workingWhere,workingVal) count=(int)where; \ + temp=count&3; \ + where-=temp; \ + workingWhere=(CARD32 *)where; \ + workingVal=*workingWhere++; \ + count=4-temp; \ + workingVal<<=(8*temp) + #define readPacked(where,x,y,z) {if(!(x)) { (x)=4; y=*z++; } where=(y)>>24; (y)<<=8; (x)--;} + #define readPackedSource(where) readPacked(where,ws,workingSource,wsrc) + #define readPackedDest(where) readPacked(where,wd,workingiDest,widst) + #define writePacked(what) workingoDest<<=8; workingoDest|=what; ww--; if(!ww) { ww=4; *wodst++=workingoDest; } +#endif /* * Naming convention: * @@ -135,35 +168,35 @@ IcIn (uint32_t x, uint8_t y) */ static void -pixman_compositeSolidMask_nx8x8888 (pixman_operator_t op, - pixman_image_t *iSrc, - pixman_image_t *iMask, - pixman_image_t *iDst, - int16_t xSrc, - int16_t ySrc, - int16_t xMask, - int16_t yMask, - int16_t xDst, - int16_t yDst, - uint16_t width, - uint16_t height) +fbCompositeSolidMask_nx8x8888 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) { - uint32_t src, srca; - uint32_t *dstLine, *dst, d, dstMask; - uint8_t *maskLine, *mask, m; - IcStride dstStride, maskStride; - uint16_t w; + CARD32 src, srca; + CARD32 *dstLine, *dst, d, dstMask; + CARD8 *maskLine, *mask, m; + FbStride dstStride, maskStride; + CARD16 w; - IcComposeGetSolid(iSrc, src); + fbComposeGetSolid(pSrc, src); - dstMask = IcFullMask (iDst->pixels->depth); + dstMask = FbFullMask (pDst->pixels->depth); srca = src >> 24; if (src == 0) return; - IcComposeGetStart (iDst, xDst, yDst, uint32_t, dstStride, dstLine, 1); - IcComposeGetStart (iMask, xMask, yMask, uint8_t, maskStride, maskLine, 1); - + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD8, maskStride, maskLine, 1); + while (height--) { dst = dstLine; @@ -180,12 +213,12 @@ pixman_compositeSolidMask_nx8x8888 (pixman_operator_t op, if (srca == 0xff) *dst = src & dstMask; else - *dst = IcOver (src, *dst) & dstMask; + *dst = fbOver (src, *dst) & dstMask; } else if (m) { - d = IcIn (src, m); - *dst = IcOver (d, *dst) & dstMask; + d = fbIn (src, m); + *dst = fbOver (d, *dst) & dstMask; } dst++; } @@ -193,35 +226,35 @@ pixman_compositeSolidMask_nx8x8888 (pixman_operator_t op, } static void -pixman_compositeSolidMask_nx8888x8888C (pixman_operator_t op, - pixman_image_t *iSrc, - pixman_image_t *iMask, - pixman_image_t *iDst, - int16_t xSrc, - int16_t ySrc, - int16_t xMask, - int16_t yMask, - int16_t xDst, - int16_t yDst, - uint16_t width, - uint16_t height) +fbCompositeSolidMask_nx8888x8888C (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) { - uint32_t src, srca; - uint32_t *dstLine, *dst, d, dstMask; - uint32_t *maskLine, *mask, ma; - IcStride dstStride, maskStride; - uint16_t w; - uint32_t m, n, o, p; + CARD32 src, srca; + CARD32 *dstLine, *dst, d, dstMask; + CARD32 *maskLine, *mask, ma; + FbStride dstStride, maskStride; + CARD16 w; + CARD32 m, n, o, p; - IcComposeGetSolid(iSrc, src); + fbComposeGetSolid(pSrc, src); - dstMask = IcFullMask (iDst->pixels->depth); + dstMask = FbFullMask (pDst->pixels->depth); srca = src >> 24; if (src == 0) return; - IcComposeGetStart (iDst, xDst, yDst, uint32_t, dstStride, dstLine, 1); - IcComposeGetStart (iMask, xMask, yMask, uint32_t, maskStride, maskLine, 1); + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD32, maskStride, maskLine, 1); while (height--) { @@ -239,25 +272,25 @@ pixman_compositeSolidMask_nx8888x8888C (pixman_operator_t op, if (srca == 0xff) *dst = src & dstMask; else - *dst = IcOver (src, *dst) & dstMask; + *dst = fbOver (src, *dst) & dstMask; } else if (ma) { d = *dst; -#define IcInOverC(src,srca,msk,dst,i,result) { \ - uint16_t __a = IcGet8(msk,i); \ - uint32_t __t, __ta; \ - uint32_t __i; \ - __t = IcIntMult (IcGet8(src,i), __a,__i); \ - __ta = (uint8_t) ~IcIntMult (srca, __a,__i); \ - __t = __t + IcIntMult(IcGet8(dst,i),__ta,__i); \ - __t = (uint32_t) (uint8_t) (__t | (-(__t >> 8))); \ +#define FbInOverC(src,srca,msk,dst,i,result) { \ + CARD16 __a = FbGet8(msk,i); \ + CARD32 __t, __ta; \ + CARD32 __i; \ + __t = FbIntMult (FbGet8(src,i), __a,__i); \ + __ta = (CARD8) ~FbIntMult (srca, __a,__i); \ + __t = __t + FbIntMult(FbGet8(dst,i),__ta,__i); \ + __t = (CARD32) (CARD8) (__t | (-(__t >> 8))); \ result = __t << (i); \ } - IcInOverC (src, srca, ma, d, 0, m); - IcInOverC (src, srca, ma, d, 8, n); - IcInOverC (src, srca, ma, d, 16, o); - IcInOverC (src, srca, ma, d, 24, p); + FbInOverC (src, srca, ma, d, 0, m); + FbInOverC (src, srca, ma, d, 8, n); + FbInOverC (src, srca, ma, d, 16, o); + FbInOverC (src, srca, ma, d, 24, p); *dst = m|n|o|p; } dst++; @@ -265,36 +298,136 @@ pixman_compositeSolidMask_nx8888x8888C (pixman_operator_t op, } } +#define srcAlphaCombine24(a,b) genericCombine24(a,b,srca,srcia) static void -pixman_compositeSolidMask_nx8x0888 (pixman_operator_t op, - pixman_image_t *iSrc, - pixman_image_t *iMask, - pixman_image_t *iDst, - int16_t xSrc, - int16_t ySrc, - int16_t xMask, - int16_t yMask, - int16_t xDst, - int16_t yDst, - uint16_t width, - uint16_t height) +fbCompositeSolidMask_nx8x0888 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) { - uint32_t src, srca; - uint8_t *dstLine, *dst; - uint32_t d; - uint8_t *maskLine, *mask, m; - IcStride dstStride, maskStride; - uint16_t w; + CARD32 src, srca, srcia; + CARD8 *dstLine, *dst, *edst; + CARD8 *maskLine, *mask, m; + FbStride dstStride, maskStride; + CARD16 w; + CARD32 rs,gs,bs,rd,gd,bd; - IcComposeGetSolid(iSrc, src); + fbComposeGetSolid(pSrc, src); srca = src >> 24; + srcia = 255-srca; + if (src == 0) + return; + + rs=src&0xff; + gs=(src>>8)&0xff; + bs=(src>>16)&0xff; + + fbComposeGetStart (pDst, xDst, yDst, CARD8, dstStride, dstLine, 3); + fbComposeGetStart (pMask, xMask, yMask, CARD8, maskStride, maskLine, 1); + + while (height--) + { + /* fixme: cleanup unused */ + unsigned int wt,wd; + CARD32 workingiDest; + CARD32 *widst; + + edst=dst = dstLine; + dstLine += dstStride; + mask = maskLine; + maskLine += maskStride; + w = width; + +#ifndef NO_MASKED_PACKED_READ + setupPackedReader(wd,wt,edst,widst,workingiDest); +#endif + + while (w--) + { +#ifndef NO_MASKED_PACKED_READ + readPackedDest(rd); + readPackedDest(gd); + readPackedDest(bd); +#else + rd= *edst++; + gd= *edst++; + bd= *edst++; +#endif + m = *mask++; + if (m == 0xff) + { + if (srca == 0xff) + { + *dst++=rs; + *dst++=gs; + *dst++=bs; + } + else + { + *dst++=(srcAlphaCombine24(rs, rd)>>8); + *dst++=(srcAlphaCombine24(gs, gd)>>8); + *dst++=(srcAlphaCombine24(bs, bd)>>8); + } + } + else if (m) + { + int na=(srca*(int)m)>>8; + int nia=255-na; + *dst++=(genericCombine24(rs, rd, na, nia)>>8); + *dst++=(genericCombine24(gs, gd, na, nia)>>8); + *dst++=(genericCombine24(bs, bd, na, nia)>>8); + } + else + { + dst+=3; + } + } + } +} + +static void +fbCompositeSolidMask_nx8x0565 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 src, srca8, srca5; + CARD16 *dstLine, *dst; + CARD16 d; + CARD32 t; + CARD8 *maskLine, *mask, m; + FbStride dstStride, maskStride; + CARD16 w,src16; + + fbComposeGetSolid(pSrc, src); + if (src == 0) return; - IcComposeGetStart (iDst, xDst, yDst, uint8_t, dstStride, dstLine, 3); - IcComposeGetStart (iMask, xMask, yMask, uint8_t, maskStride, maskLine, 1); + srca8 = (src >> 24); + srca5 = (srca8 >> 3); + + src16 = cvt8888to0565(src); + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD8, maskStride, maskLine, 1); while (height--) { dst = dstLine; @@ -306,57 +439,72 @@ pixman_compositeSolidMask_nx8x0888 (pixman_operator_t op, while (w--) { m = *mask++; - if (m == 0xff) + if (m == 0) + dst++; + else if (srca5 == (0xff >> 3)) { - if (srca == 0xff) - d = src; + if (m == 0xff) + *dst++ = src16; + else + { + d = *dst; + m >>= 3; + inOver0565 (m, src16, d, *dst++); + } + } + else + { + d = *dst; + if (m == 0xff) + { + t = fbOver24 (src, cvt0565to0888 (d)); + } else { - d = Fetch24(dst); - d = IcOver24 (src, d); + t = fbIn (src, m); + t = fbOver (t, cvt0565to0888 (d)); } - Store24(dst,d); + *dst++ = cvt8888to0565 (t); } - else if (m) - { - d = IcOver24 (IcIn(src,m), Fetch24(dst)); - Store24(dst,d); - } - dst += 3; } } } static void -pixman_compositeSolidMask_nx8x0565 (pixman_operator_t op, - pixman_image_t *iSrc, - pixman_image_t *iMask, - pixman_image_t *iDst, - int16_t xSrc, - int16_t ySrc, - int16_t xMask, - int16_t yMask, - int16_t xDst, - int16_t yDst, - uint16_t width, - uint16_t height) +fbCompositeSolidMask_nx8888x0565 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) { - uint32_t src, srca; - uint16_t *dstLine, *dst; - uint32_t d; - uint8_t *maskLine, *mask, m; - IcStride dstStride, maskStride; - uint16_t w; + CARD32 src, srca8, srca5; + CARD16 *dstLine, *dst; + CARD16 d; + CARD32 *maskLine, *mask; + CARD32 t; + CARD8 m; + FbStride dstStride, maskStride; + CARD16 w, src16; + + fbComposeGetSolid(pSrc, src); - IcComposeGetSolid(iSrc, src); - - srca = src >> 24; if (src == 0) return; - - IcComposeGetStart (iDst, xDst, yDst, uint16_t, dstStride, dstLine, 1); - IcComposeGetStart (iMask, xMask, yMask, uint8_t, maskStride, maskLine, 1); - + + srca8 = src >> 24; + srca5 = srca8 >> 3; + src16 = cvt8888to0565(src); + + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD32, maskStride, maskLine, 1); + while (height--) { dst = dstLine; @@ -367,53 +515,64 @@ pixman_compositeSolidMask_nx8x0565 (pixman_operator_t op, while (w--) { - m = *mask++; - if (m == 0xff) + m = *mask++ >> 24; + if (m == 0) + dst++; + else if (srca5 == (0xff >> 3)) { - if (srca == 0xff) - d = src; + if (m == 0xff) + *dst++ = src16; else { d = *dst; - d = IcOver24 (src, cvt0565to8888(d)); + m >>= 3; + inOver0565 (m, src16, d, *dst++); } - *dst = cvt8888to0565(d); } - else if (m) + else { - d = *dst; - d = IcOver24 (IcIn(src,m), cvt0565to8888(d)); - *dst = cvt8888to0565(d); + if (m == 0xff) + { + d = *dst; + t = fbOver24 (src, cvt0565to0888 (d)); + *dst++ = cvt8888to0565 (t); + } + else + { + d = *dst; + t = fbIn (src, m); + t = fbOver (t, cvt0565to0888 (d)); + *dst++ = cvt8888to0565 (t); + } } - dst++; } } } static void -pixman_compositeSolidMask_nx8888x0565C (pixman_operator_t op, - pixman_image_t *iSrc, - pixman_image_t *iMask, - pixman_image_t *iDst, - int16_t xSrc, - int16_t ySrc, - int16_t xMask, - int16_t yMask, - int16_t xDst, - int16_t yDst, - uint16_t width, - uint16_t height) +fbCompositeSolidMask_nx8888x0565C (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) { - uint32_t src, srca; - uint16_t src16; - uint16_t *dstLine, *dst; - uint32_t d; - uint32_t *maskLine, *mask, ma; - IcStride dstStride, maskStride; - uint16_t w; - uint32_t m, n, o; + CARD32 src, srca; + CARD16 src16; + CARD16 *dstLine, *dst; + CARD32 d; + CARD32 *maskLine, *mask, ma; + FbStride dstStride, maskStride; + CARD16 w; + CARD32 m, n, o; - IcComposeGetSolid(iSrc, src); + fbComposeGetSolid(pSrc, src); srca = src >> 24; if (src == 0) @@ -421,8 +580,8 @@ pixman_compositeSolidMask_nx8888x0565C (pixman_operator_t op, src16 = cvt8888to0565(src); - IcComposeGetStart (iDst, xDst, yDst, uint16_t, dstStride, dstLine, 1); - IcComposeGetStart (iMask, xMask, yMask, uint32_t, maskStride, maskLine, 1); + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD32, maskStride, maskLine, 1); while (height--) { @@ -444,17 +603,17 @@ pixman_compositeSolidMask_nx8888x0565C (pixman_operator_t op, else { d = *dst; - d = IcOver24 (src, cvt0565to8888(d)); + d = fbOver24 (src, cvt0565to0888(d)); *dst = cvt8888to0565(d); } } else if (ma) { d = *dst; - d = cvt0565to8888(d); - IcInOverC (src, srca, ma, d, 0, m); - IcInOverC (src, srca, ma, d, 8, n); - IcInOverC (src, srca, ma, d, 16, o); + d = cvt0565to0888(d); + FbInOverC (src, srca, ma, d, 0, m); + FbInOverC (src, srca, ma, d, 8, n); + FbInOverC (src, srca, ma, d, 16, o); d = m|n|o; *dst = cvt8888to0565(d); } @@ -464,29 +623,29 @@ pixman_compositeSolidMask_nx8888x0565C (pixman_operator_t op, } static void -pixman_compositeSrc_8888x8888 (pixman_operator_t op, - pixman_image_t *iSrc, - pixman_image_t *iMask, - pixman_image_t *iDst, - int16_t xSrc, - int16_t ySrc, - int16_t xMask, - int16_t yMask, - int16_t xDst, - int16_t yDst, - uint16_t width, - uint16_t height) +fbCompositeSrc_8888x8888 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) { - uint32_t *dstLine, *dst, dstMask; - uint32_t *srcLine, *src, s; - IcStride dstStride, srcStride; - uint8_t a; - uint16_t w; + CARD32 *dstLine, *dst, dstMask; + CARD32 *srcLine, *src, s; + FbStride dstStride, srcStride; + CARD8 a; + CARD16 w; - IcComposeGetStart (iDst, xDst, yDst, uint32_t, dstStride, dstLine, 1); - IcComposeGetStart (iSrc, xSrc, ySrc, uint32_t, srcStride, srcLine, 1); + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); - dstMask = IcFullMask (iDst->pixels->depth); + dstMask = FbFullMask (pDst->pixels->depth); while (height--) { @@ -503,35 +662,35 @@ pixman_compositeSrc_8888x8888 (pixman_operator_t op, if (a == 0xff) *dst = s & dstMask; else if (a) - *dst = IcOver (s, *dst) & dstMask; + *dst = fbOver (s, *dst) & dstMask; dst++; } } } static void -pixman_compositeSrc_8888x0888 (pixman_operator_t op, - pixman_image_t *iSrc, - pixman_image_t *iMask, - pixman_image_t *iDst, - int16_t xSrc, - int16_t ySrc, - int16_t xMask, - int16_t yMask, - int16_t xDst, - int16_t yDst, - uint16_t width, - uint16_t height) +fbCompositeSrc_8888x0888 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) { - uint8_t *dstLine, *dst; - uint32_t d; - uint32_t *srcLine, *src, s; - uint8_t a; - IcStride dstStride, srcStride; - uint16_t w; + CARD8 *dstLine, *dst; + CARD32 d; + CARD32 *srcLine, *src, s; + CARD8 a; + FbStride dstStride, srcStride; + CARD16 w; - IcComposeGetStart (iDst, xDst, yDst, uint8_t, dstStride, dstLine, 3); - IcComposeGetStart (iSrc, xSrc, ySrc, uint32_t, srcStride, srcLine, 1); + fbComposeGetStart (pDst, xDst, yDst, CARD8, dstStride, dstLine, 3); + fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); while (height--) { @@ -550,7 +709,7 @@ pixman_compositeSrc_8888x0888 (pixman_operator_t op, if (a == 0xff) d = s; else - d = IcOver24 (s, Fetch24(dst)); + d = fbOver24 (s, Fetch24(dst)); Store24(dst,d); } dst += 3; @@ -559,28 +718,28 @@ pixman_compositeSrc_8888x0888 (pixman_operator_t op, } static void -pixman_compositeSrc_8888x0565 (pixman_operator_t op, - pixman_image_t *iSrc, - pixman_image_t *iMask, - pixman_image_t *iDst, - int16_t xSrc, - int16_t ySrc, - int16_t xMask, - int16_t yMask, - int16_t xDst, - int16_t yDst, - uint16_t width, - uint16_t height) +fbCompositeSrc_8888x0565 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) { - uint16_t *dstLine, *dst; - uint32_t d; - uint32_t *srcLine, *src, s; - uint8_t a; - IcStride dstStride, srcStride; - uint16_t w; + CARD16 *dstLine, *dst; + CARD32 d; + CARD32 *srcLine, *src, s; + CARD8 a; + FbStride dstStride, srcStride; + CARD16 w; - IcComposeGetStart (iSrc, xSrc, ySrc, uint32_t, srcStride, srcLine, 1); - IcComposeGetStart (iDst, xDst, yDst, uint16_t, dstStride, dstLine, 1); + fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); while (height--) { @@ -601,7 +760,7 @@ pixman_compositeSrc_8888x0565 (pixman_operator_t op, else { d = *dst; - d = IcOver24 (s, cvt0565to8888(d)); + d = fbOver24 (s, cvt0565to0888(d)); } *dst = cvt8888to0565(d); } @@ -610,65 +769,31 @@ pixman_compositeSrc_8888x0565 (pixman_operator_t op, } } -static void -pixman_compositeSrc_0565x0565 (pixman_operator_t op, - pixman_image_t *iSrc, - pixman_image_t *iMask, - pixman_image_t *iDst, - int16_t xSrc, - int16_t ySrc, - int16_t xMask, - int16_t yMask, - int16_t xDst, - int16_t yDst, - uint16_t width, - uint16_t height) -{ - uint16_t *dstLine, *dst; - uint16_t *srcLine, *src; - IcStride dstStride, srcStride; - uint16_t w; - - IcComposeGetStart (iSrc, xSrc, ySrc, uint16_t, srcStride, srcLine, 1); - IcComposeGetStart (iDst, xDst, yDst, uint16_t, dstStride, dstLine, 1); - - while (height--) - { - dst = dstLine; - dstLine += dstStride; - src = srcLine; - srcLine += srcStride; - w = width; - - while (w--) - *dst++ = *src++; - } -} static void -pixman_compositeSrcAdd_8000x8000 (pixman_operator_t op, - pixman_image_t *iSrc, - pixman_image_t *iMask, - pixman_image_t *iDst, - int16_t xSrc, - int16_t ySrc, - int16_t xMask, - int16_t yMask, - int16_t xDst, - int16_t yDst, - uint16_t width, - uint16_t height) +fbCompositeSrcAdd_8000x8000 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) { - uint8_t *dstLine, *dst; - uint8_t *srcLine, *src; - IcStride dstStride, srcStride; - uint8_t w; - uint8_t s, d; - uint16_t t; + CARD8 *dstLine, *dst; + CARD8 *srcLine, *src; + FbStride dstStride, srcStride; + CARD16 w; + CARD8 s, d; + CARD16 t; - IcComposeGetStart (iSrc, xSrc, ySrc, uint8_t, srcStride, srcLine, 1); - IcComposeGetStart (iDst, xDst, yDst, uint8_t, dstStride, dstLine, 1); + fbComposeGetStart (pSrc, xSrc, ySrc, CARD8, srcStride, srcLine, 1); + fbComposeGetStart (pDst, xDst, yDst, CARD8, dstStride, dstLine, 1); while (height--) { @@ -681,95 +806,103 @@ pixman_compositeSrcAdd_8000x8000 (pixman_operator_t op, while (w--) { s = *src++; - if (s != 0xff) + if (s) { - d = *dst; - t = d + s; - s = t | (0 - (t >> 8)); - } - *dst++ = s; - } - } -} - -static void -pixman_compositeSrcAdd_8888x8888 (pixman_operator_t op, - pixman_image_t *iSrc, - pixman_image_t *iMask, - pixman_image_t *iDst, - int16_t xSrc, - int16_t ySrc, - int16_t xMask, - int16_t yMask, - int16_t xDst, - int16_t yDst, - uint16_t width, - uint16_t height) -{ - uint32_t *dstLine, *dst; - uint32_t *srcLine, *src; - IcStride dstStride, srcStride; - uint16_t w; - uint32_t s, d; - uint16_t t; - uint32_t m,n,o,p; - - IcComposeGetStart (iSrc, xSrc, ySrc, uint32_t, srcStride, srcLine, 1); - IcComposeGetStart (iDst, xDst, yDst, uint32_t, dstStride, dstLine, 1); - - while (height--) - { - dst = dstLine; - dstLine += dstStride; - src = srcLine; - srcLine += srcStride; - w = width; - - while (w--) - { - s = *src++; - if (s != 0xffffffff) - { - d = *dst; - if (d) + if (s != 0xff) { - m = IcAdd(s,d,0,t); - n = IcAdd(s,d,8,t); - o = IcAdd(s,d,16,t); - p = IcAdd(s,d,24,t); - s = m|n|o|p; + d = *dst; + t = d + s; + s = t | (0 - (t >> 8)); } + *dst = s; } - *dst++ = s; + dst++; } } } static void -pixman_compositeSrcAdd_1000x1000 (pixman_operator_t op, - pixman_image_t *iSrc, - pixman_image_t *iMask, - pixman_image_t *iDst, - int16_t xSrc, - int16_t ySrc, - int16_t xMask, - int16_t yMask, - int16_t xDst, - int16_t yDst, - uint16_t width, - uint16_t height) +fbCompositeSrcAdd_8888x8888 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) { - pixman_bits_t *dstBits, *srcBits; - IcStride dstStride, srcStride; + CARD32 *dstLine, *dst; + CARD32 *srcLine, *src; + FbStride dstStride, srcStride; + CARD16 w; + CARD32 s, d; + CARD16 t; + CARD32 m,n,o,p; + + fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + while (w--) + { + s = *src++; + if (s) + { + if (s != 0xffffffff) + { + d = *dst; + if (d) + { + m = FbAdd(s,d,0,t); + n = FbAdd(s,d,8,t); + o = FbAdd(s,d,16,t); + p = FbAdd(s,d,24,t); + s = m|n|o|p; + } + } + *dst = s; + } + dst++; + } + } +} + +static void +fbCompositeSrcAdd_1000x1000 (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + FbBits *dstBits, *srcBits; + FbStride dstStride, srcStride; int dstBpp, srcBpp; int dstXoff, dstYoff; int srcXoff, srcYoff; - IcGetPixels(iSrc->pixels, srcBits, srcStride, srcBpp, srcXoff, srcYoff); + FbGetPixels(pSrc->pixels, srcBits, srcStride, srcBpp, srcXoff, srcYoff); - IcGetPixels(iDst->pixels, dstBits, dstStride, dstBpp, dstXoff, dstYoff); + FbGetPixels(pDst->pixels, dstBits, dstStride, dstBpp, dstXoff, dstYoff); - IcBlt (srcBits + srcStride * (ySrc + srcYoff), + fbBlt (srcBits + srcStride * (ySrc + srcYoff), srcStride, xSrc + srcXoff, @@ -781,46 +914,46 @@ pixman_compositeSrcAdd_1000x1000 (pixman_operator_t op, height, GXor, - IC_ALLONES, + FB_ALLONES, srcBpp, - 0, - 0); + FALSE, + FALSE); } static void -pixman_compositeSolidMask_nx1xn (pixman_operator_t op, - pixman_image_t *iSrc, - pixman_image_t *iMask, - pixman_image_t *iDst, - int16_t xSrc, - int16_t ySrc, - int16_t xMask, - int16_t yMask, - int16_t xDst, - int16_t yDst, - uint16_t width, - uint16_t height) +fbCompositeSolidMask_nx1xn (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) { - pixman_bits_t *dstBits; - IcStip *maskBits; - IcStride dstStride, maskStride; + FbBits *dstBits; + FbStip *maskBits; + FbStride dstStride, maskStride; int dstBpp, maskBpp; int dstXoff, dstYoff; int maskXoff, maskYoff; - pixman_bits_t src; - - IcComposeGetSolid(iSrc, src); + FbBits src; + + fbComposeGetSolid(pSrc, src); if ((src & 0xff000000) != 0xff000000) { - pixman_compositeGeneral (op, iSrc, iMask, iDst, + pixman_compositeGeneral (op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height); return; } - IcGetStipPixels (iMask->pixels, maskBits, maskStride, maskBpp, maskXoff, maskYoff); - IcGetPixels (iDst->pixels, dstBits, dstStride, dstBpp, dstXoff, dstYoff); + FbGetStipPixels (pMask->pixels, maskBits, maskStride, maskBpp, maskXoff, maskYoff); + FbGetPixels (pDst->pixels, dstBits, dstStride, dstBpp, dstXoff, dstYoff); switch (dstBpp) { case 32: @@ -832,9 +965,9 @@ pixman_compositeSolidMask_nx1xn (pixman_operator_t op, break; } - src = IcReplicatePixel (src, dstBpp); + src = fbReplicatePixel (src, dstBpp); - IcBltOne (maskBits + maskStride * (yMask + maskYoff), + fbBltOne (maskBits + maskStride * (yMask + maskYoff), maskStride, xMask + maskXoff, @@ -848,15 +981,388 @@ pixman_compositeSolidMask_nx1xn (pixman_operator_t op, 0x0, src, - IC_ALLONES, + FB_ALLONES, 0x0); } +/* prototype to help with merging */ +static void +fbCompositeSrcSrc_nxn (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +/* + * Apply a constant alpha value in an over computation + */ +static void +fbCompositeTrans_0565xnx0565(pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD16 *dstLine, *dst; + CARD16 *srcLine, *src; + FbStride dstStride, srcStride; + CARD16 w; + FbBits mask; + CARD8 maskAlpha; + CARD16 s_16, d_16; + CARD32 s_32, d_32; + + fbComposeGetSolid (pMask, mask); + maskAlpha = mask >> 27; + + if (!maskAlpha) + return; + if (maskAlpha == 0xff) + { + fbCompositeSrcSrc_nxn (PIXMAN_OPERATOR_SRC, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, yDst, + width, height); + return; + } + + fbComposeGetStart (pSrc, xSrc, ySrc, CARD16, srcStride, srcLine, 1); + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); + + while (height--) + { + CARD32 *isrc, *idst; + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + if(((int)src&1)==1) + { + s_16 = *src++; + d_16 = *dst; + inOver0565(maskAlpha, s_16, d_16, *dst++); + w--; + } + isrc=(CARD32 *)src; + if(((int)dst&1)==0) + { + idst=(CARD32 *)dst; + while (w>1) + { + s_32 = *isrc++; + d_32 = *idst; + inOver2x0565(maskAlpha,s_32,d_32,*idst++); + w-=2; + } + dst=(CARD16 *)idst; + } + else + { + while (w > 1) + { + s_32 = *isrc++; +#if IMAGE_BYTE_ORDER == LSBFirst + s_16=s_32&0xffff; +#else + s_16=s_32>>16; +#endif + d_16 = *dst; + inOver0565(maskAlpha, s_16, d_16, *dst++); +#if IMAGE_BYTE_ORDER == LSBFirst + s_16=s_32>>16; +#else + s_16=s_32&0xffff; +#endif + d_16 = *dst; + inOver0565(maskAlpha, s_16, d_16, *dst++); + w-=2; + } + } + src=(CARD16 *)isrc; + if(w!=0) + { + s_16 = *src; + d_16 = *dst; + inOver0565(maskAlpha, s_16, d_16, *dst); + } + } +} + + + +/* macros for "i can't believe it's not fast" packed pixel handling */ +#define alphamaskCombine24(a,b) genericCombine24(a,b,maskAlpha,maskiAlpha) +static void +fbCompositeTrans_0888xnx0888(pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD8 *dstLine, *dst,*idst; + CARD8 *srcLine, *src; + FbStride dstStride, srcStride; + CARD16 w; + FbBits mask; + CARD16 maskAlpha,maskiAlpha; + + fbComposeGetSolid (pMask, mask); + maskAlpha = mask >> 24; + maskiAlpha= 255-maskAlpha; + + if (!maskAlpha) + return; + /* + if (maskAlpha == 0xff) + { + fbCompositeSrc_0888x0888 (op, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, yDst, + width, height); + return; + } + */ + + fbComposeGetStart (pSrc, xSrc, ySrc, CARD8, srcStride, srcLine, 3); + fbComposeGetStart (pDst, xDst, yDst, CARD8, dstStride, dstLine, 3); + + { + unsigned int ws,wt; + CARD32 workingSource; + CARD32 *wsrc, *wdst, *widst; + CARD32 rs, rd, nd; + CARD8 *isrc; + + /* are xSrc and xDst at the same alignment? if not, we need to be complicated :)*/ + /* if(0==0) */ + if( (((xSrc*3)&3)!=((xDst*3)&3)) || ((srcStride&3)!=(dstStride&3))) + { + while (height--) + { + dst = dstLine; + dstLine += dstStride; + isrc = src = srcLine; + srcLine += srcStride; + w = width*3; + + setupPackedReader(ws,wt,isrc,wsrc,workingSource); + + /* get to word aligned */ + switch(!(int)dst&3) + { + case 1: + readPackedSource(rs); + /* *dst++=alphamaskCombine24(rs, *dst)>>8; */ + rd=*dst; /* make gcc happy. hope it doens't cost us too much performance*/ + *dst++=alphamaskCombine24(rs, rd)>>8; + w--; if(w==0) break; + case 2: + readPackedSource(rs); + rd=*dst; + *dst++=alphamaskCombine24(rs, rd)>>8; + w--; if(w==0) break; + case 3: + readPackedSource(rs); + rd=*dst; + *dst++=alphamaskCombine24(rs, rd)>>8; + w--; if(w==0) break; + } + wdst=(CARD32 *)dst; + while (w>3) + { + /* FIXME: write a special readPackedWord macro, which knows how to + * halfword combine + */ + +#if IMAGE_BYTE_ORDER == LSBFirst + rd=*wdst; + readPackedSource(nd); + readPackedSource(rs); + nd|=rs<<8; + readPackedSource(rs); + nd|=rs<<16; + readPackedSource(rs); + nd|=rs<<24; +#else + readPackedSource(nd); + nd<<=24; + readPackedSource(rs); + nd|=rs<<16; + readPackedSource(rs); + nd|=rs<<8; + readPackedSource(rs); + nd|=rs; +#endif + inOver0888(maskAlpha, nd, rd, *wdst++) + w-=4; + } + dst=(CARD8 *)wdst; + switch(w) + { + case 3: + readPackedSource(rs); + rd=*dst; + *dst++=alphamaskCombine24(rs, rd)>>8; + case 2: + readPackedSource(rs); + rd=*dst; + *dst++=alphamaskCombine24(rs, rd)>>8; + case 1: + readPackedSource(rs); + rd=*dst; + *dst++=alphamaskCombine24(rs, rd)>>8; + } + } + } + else + { + while (height--) + { + idst=dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width*3; + /* get to word aligned */ + switch(!(int)src&3) + { + case 1: + rd=alphamaskCombine24(*src++, *dst)>>8; + *dst++=rd; + w--; if(w==0) break; + case 2: + rd=alphamaskCombine24(*src++, *dst)>>8; + *dst++=rd; + w--; if(w==0) break; + case 3: + rd=alphamaskCombine24(*src++, *dst)>>8; + *dst++=rd; + w--; if(w==0) break; + } + wsrc=(CARD32 *)src; + widst=(CARD32 *)dst; + + while(w>3) + { + rs = *wsrc++; + rd = *widst; + inOver0888(maskAlpha, rs, rd, *widst++); + w-=4; + } + src=(CARD8 *)wsrc; + dst=(CARD8 *)widst; + switch(w) + { + case 3: + rd=alphamaskCombine24(*src++, *dst)>>8; + *dst++=rd; + case 2: + rd=alphamaskCombine24(*src++, *dst)>>8; + *dst++=rd; + case 1: + rd=alphamaskCombine24(*src++, *dst)>>8; + *dst++=rd; + } + } + } + } +} + +/* + * Simple bitblt + */ + +static void +fbCompositeSrcSrc_nxn (pixman_operator_t op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + FbBits *dst; + FbBits *src; + FbStride dstStride, srcStride; + int srcXoff, srcYoff; + int dstXoff, dstYoff; + int srcBpp; + int dstBpp; + Bool reverse = FALSE; + Bool upsidedown = FALSE; + + FbGetPixels(pSrc->pixels,src,srcStride,srcBpp,srcXoff,srcYoff); + FbGetPixels(pDst->pixels,dst,dstStride,dstBpp,dstXoff,dstYoff); + + fbBlt (src + (ySrc + srcYoff) * srcStride, + srcStride, + (xSrc + srcXoff) * srcBpp, + + dst + (yDst + dstYoff) * dstStride, + dstStride, + (xDst + dstXoff) * dstBpp, + + (width) * dstBpp, + (height), + + GXcopy, + FB_ALLONES, + dstBpp, + + reverse, + upsidedown); +} + +/* + * Solid fill +void +fbCompositeSolidSrc_nxn (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + +} + */ + void pixman_composite (pixman_operator_t op, - pixman_image_t *iSrc, - pixman_image_t *iMask, - pixman_image_t *iDst, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, int xSrc, int ySrc, int xMask, @@ -870,39 +1376,39 @@ pixman_composite (pixman_operator_t op, int n; pixman_box16_t *pbox; CompositeFunc func; - int srcRepeat = iSrc->repeat; - int maskRepeat = 0; - int srcAlphaMap = iSrc->alphaMap != 0; - int maskAlphaMap = 0; - int dstAlphaMap = iDst->alphaMap != 0; + int srcRepeat = pSrc->repeat; + int maskRepeat = FALSE; + int srcAlphaMap = pSrc->alphaMap != 0; + int maskAlphaMap = FALSE; + int dstAlphaMap = pDst->alphaMap != 0; int x_msk, y_msk, x_src, y_src, x_dst, y_dst; int w, h, w_this, h_this; - if (iSrc->pixels->width == 0 || - iSrc->pixels->height == 0) + if (pSrc->pixels->width == 0 || + pSrc->pixels->height == 0) { return; } - xDst += iDst->pixels->x; - yDst += iDst->pixels->y; - xSrc += iSrc->pixels->x; - ySrc += iSrc->pixels->y; - if (iMask) + xDst += pDst->pixels->x; + yDst += pDst->pixels->y; + xSrc += pSrc->pixels->x; + ySrc += pSrc->pixels->y; + if (pMask) { - xMask += iMask->pixels->x; - yMask += iMask->pixels->y; - maskRepeat = iMask->repeat; - maskAlphaMap = iMask->alphaMap != 0; + xMask += pMask->pixels->x; + yMask += pMask->pixels->y; + maskRepeat = pMask->repeat; + maskAlphaMap = pMask->alphaMap != 0; } region = pixman_region_create(); pixman_region_union_rect (region, region, xDst, yDst, width, height); - if (!IcComputeCompositeRegion (region, - iSrc, - iMask, - iDst, + if (!FbComputeCompositeRegion (region, + pSrc, + pMask, + pDst, xSrc, ySrc, xMask, @@ -914,65 +1420,80 @@ pixman_composite (pixman_operator_t op, return; func = pixman_compositeGeneral; - if (!iSrc->transform && !(iMask && iMask->transform)) + if (!pSrc->transform && !(pMask && pMask->transform)) if (!maskAlphaMap && !srcAlphaMap && !dstAlphaMap) switch (op) { case PIXMAN_OPERATOR_OVER: - if (iMask) + if (pMask) { if (srcRepeat && - iSrc->pixels->width == 1 && - iSrc->pixels->height == 1) + pSrc->pixels->width == 1 && + pSrc->pixels->height == 1) { - srcRepeat = 0; - if (PICT_FORMAT_COLOR(iSrc->format_code)) { - switch (iMask->format_code) { + if (PICT_FORMAT_COLOR(pSrc->format_code)) { + switch (pMask->format_code) { case PICT_a8: - switch (iDst->format_code) { + switch (pDst->format_code) { case PICT_r5g6b5: case PICT_b5g6r5: - func = pixman_compositeSolidMask_nx8x0565; + func = fbCompositeSolidMask_nx8x0565; break; case PICT_r8g8b8: case PICT_b8g8r8: - func = pixman_compositeSolidMask_nx8x0888; + func = fbCompositeSolidMask_nx8x0888; break; case PICT_a8r8g8b8: case PICT_x8r8g8b8: case PICT_a8b8g8r8: case PICT_x8b8g8r8: - func = pixman_compositeSolidMask_nx8x8888; + func = fbCompositeSolidMask_nx8x8888; break; } break; case PICT_a8r8g8b8: - if (iMask->componentAlpha) { - switch (iDst->format_code) { + if (pMask->componentAlpha) { + switch (pDst->format_code) { case PICT_a8r8g8b8: case PICT_x8r8g8b8: - func = pixman_compositeSolidMask_nx8888x8888C; + func = fbCompositeSolidMask_nx8888x8888C; break; case PICT_r5g6b5: - func = pixman_compositeSolidMask_nx8888x0565C; + func = fbCompositeSolidMask_nx8888x0565C; + break; + } + } + else + { + switch (pDst->format_code) { + case PICT_r5g6b5: + func = fbCompositeSolidMask_nx8888x0565; break; } } break; case PICT_a8b8g8r8: - if (iMask->componentAlpha) { - switch (iDst->format_code) { + if (pMask->componentAlpha) { + switch (pDst->format_code) { case PICT_a8b8g8r8: case PICT_x8b8g8r8: - func = pixman_compositeSolidMask_nx8888x8888C; + func = fbCompositeSolidMask_nx8888x8888C; break; case PICT_b5g6r5: - func = pixman_compositeSolidMask_nx8888x0565C; + func = fbCompositeSolidMask_nx8888x0565C; + break; + } + } + else + { + switch (pDst->format_code) { + case PICT_r5g6b5: + func = fbCompositeSolidMask_nx8888x0565; break; } } break; case PICT_a1: - switch (iDst->format_code) { + switch (pDst->format_code) { case PICT_r5g6b5: case PICT_b5g6r5: case PICT_r8g8b8: @@ -981,55 +1502,70 @@ pixman_composite (pixman_operator_t op, case PICT_x8r8g8b8: case PICT_a8b8g8r8: case PICT_x8b8g8r8: - func = pixman_compositeSolidMask_nx1xn; + func = fbCompositeSolidMask_nx1xn; break; } } } + if (func != pixman_compositeGeneral) + srcRepeat = FALSE; + } + else if (maskRepeat && + pMask->pDrawable->width == 1 && + pMask->pDrawable->height == 1) + { + switch (pSrc->format_code) { + case PICT_r5g6b5: + case PICT_b5g6r5: + if (pDst->format_code == pSrc->format_code) + func = fbCompositeTrans_0565xnx0565; + break; + case PICT_r8g8b8: + case PICT_b8g8r8: + if (pDst->format_code == pSrc->format_code) + func = fbCompositeTrans_0888xnx0888; + break; + } + + if (func != pixman_compositeGeneral) + maskRepeat = FALSE; } } else { - switch (iSrc->format_code) { + /* + * Formats without alpha bits are just Copy with Over + */ + if (pSrc->format_code == pDst->format_code && !PICT_FORMAT_A(pSrc->format_code)) + { + func = fbCompositeSrcSrc_nxn; + } + else switch (pSrc->format_code) { case PICT_a8r8g8b8: - switch (iDst->format_code) { + switch (pDst->format_code) { case PICT_a8r8g8b8: case PICT_x8r8g8b8: - func = pixman_compositeSrc_8888x8888; + func = fbCompositeSrc_8888x8888; break; case PICT_r8g8b8: - func = pixman_compositeSrc_8888x0888; + func = fbCompositeSrc_8888x0888; break; case PICT_r5g6b5: - func = pixman_compositeSrc_8888x0565; + func = fbCompositeSrc_8888x0565; break; } break; case PICT_a8b8g8r8: - switch (iDst->format_code) { + switch (pDst->format_code) { case PICT_a8b8g8r8: case PICT_x8b8g8r8: - func = pixman_compositeSrc_8888x8888; + func = fbCompositeSrc_8888x8888; break; case PICT_b8g8r8: - func = pixman_compositeSrc_8888x0888; + func = fbCompositeSrc_8888x0888; break; case PICT_b5g6r5: - func = pixman_compositeSrc_8888x0565; - break; - } - break; - case PICT_r5g6b5: - switch (iDst->format_code) { - case PICT_r5g6b5: - func = pixman_compositeSrc_0565x0565; - break; - } - break; - case PICT_b5g6r5: - switch (iDst->format_code) { - case PICT_b5g6r5: - func = pixman_compositeSrc_0565x0565; + func = fbCompositeSrc_8888x0565; break; } break; @@ -1037,50 +1573,56 @@ pixman_composite (pixman_operator_t op, } break; case PIXMAN_OPERATOR_ADD: - if (iMask == 0) + if (pMask == 0) { - switch (iSrc->format_code) { + switch (pSrc->format_code) { case PICT_a8r8g8b8: - switch (iDst->format_code) { + switch (pDst->format_code) { case PICT_a8r8g8b8: - func = pixman_compositeSrcAdd_8888x8888; + func = fbCompositeSrcAdd_8888x8888; break; } break; case PICT_a8b8g8r8: - switch (iDst->format_code) { + switch (pDst->format_code) { case PICT_a8b8g8r8: - func = pixman_compositeSrcAdd_8888x8888; + func = fbCompositeSrcAdd_8888x8888; break; } break; case PICT_a8: - switch (iDst->format_code) { + switch (pDst->format_code) { case PICT_a8: - func = pixman_compositeSrcAdd_8000x8000; + func = fbCompositeSrcAdd_8000x8000; break; } break; case PICT_a1: - switch (iDst->format_code) { + switch (pDst->format_code) { case PICT_a1: - func = pixman_compositeSrcAdd_1000x1000; + func = fbCompositeSrcAdd_1000x1000; break; } break; } } break; + case PIXMAN_OPERATOR_SRC: + if (pMask == 0) + { + if (pSrc->format_code == pDst->format_code) + func = fbCompositeSrcSrc_nxn; + } default: func = pixman_compositeGeneral; break; } /* if we are transforming, we handle repeats in - * IcFetch[a]_transform + * FbFetch[a]_transform */ - if (iSrc->transform) + if (pSrc->transform) srcRepeat = 0; - if (iMask && iMask->transform) + if (pMask && pMask->transform) maskRepeat = 0; n = pixman_region_num_rects (region); @@ -1100,32 +1642,32 @@ pixman_composite (pixman_operator_t op, x_dst = pbox->x1; if (maskRepeat) { - y_msk = MOD (y_msk, iMask->pixels->height); - if (h_this > iMask->pixels->height - y_msk) - h_this = iMask->pixels->height - y_msk; + y_msk = MOD (y_msk, pMask->pixels->height); + if (h_this > pMask->pixels->height - y_msk) + h_this = pMask->pixels->height - y_msk; } if (srcRepeat) { - y_src = MOD (y_src, iSrc->pixels->height); - if (h_this > iSrc->pixels->height - y_src) - h_this = iSrc->pixels->height - y_src; + y_src = MOD (y_src, pSrc->pixels->height); + if (h_this > pSrc->pixels->height - y_src) + h_this = pSrc->pixels->height - y_src; } while (w) { w_this = w; if (maskRepeat) { - x_msk = MOD (x_msk, iMask->pixels->width); - if (w_this > iMask->pixels->width - x_msk) - w_this = iMask->pixels->width - x_msk; + x_msk = MOD (x_msk, pMask->pixels->width); + if (w_this > pMask->pixels->width - x_msk) + w_this = pMask->pixels->width - x_msk; } if (srcRepeat) { - x_src = MOD (x_src, iSrc->pixels->width); - if (w_this > iSrc->pixels->width - x_src) - w_this = iSrc->pixels->width - x_src; + x_src = MOD (x_src, pSrc->pixels->width); + if (w_this > pSrc->pixels->width - x_src) + w_this = pSrc->pixels->width - x_src; } - (*func) (op, iSrc, iMask, iDst, + (*func) (op, pSrc, pMask, pDst, x_src, y_src, x_msk, y_msk, x_dst, y_dst, w_this, h_this); w -= w_this; diff --git a/gfx/cairo/libpixman/src/icblt.c b/gfx/cairo/libpixman/src/icblt.c index a48d1ef78336..ee92ba53d5bb 100644 --- a/gfx/cairo/libpixman/src/icblt.c +++ b/gfx/cairo/libpixman/src/icblt.c @@ -22,58 +22,82 @@ * PERFORMANCE OF THIS SOFTWARE. */ -#include "icint.h" +#include "pixman-xserver-compat.h" #define InitializeShifts(sx,dx,ls,rs) { \ if (sx != dx) { \ if (sx > dx) { \ ls = sx - dx; \ - rs = IC_UNIT - ls; \ + rs = FB_UNIT - ls; \ } else { \ rs = dx - sx; \ - ls = IC_UNIT - rs; \ + ls = FB_UNIT - rs; \ } \ } \ } void -IcBlt (pixman_bits_t *srcLine, - IcStride srcStride, +fbBlt (FbBits *srcLine, + FbStride srcStride, int srcX, - pixman_bits_t *dstLine, - IcStride dstStride, + FbBits *dstLine, + FbStride dstStride, int dstX, int width, int height, int alu, - pixman_bits_t pm, + FbBits pm, int bpp, - int reverse, - int upsidedown) + Bool reverse, + Bool upsidedown) { - pixman_bits_t *src, *dst; + FbBits *src, *dst; int leftShift, rightShift; - pixman_bits_t startmask, endmask; - pixman_bits_t bits, bits1; + FbBits startmask, endmask; + FbBits bits, bits1; int n, nmiddle; - int destInvarient; + Bool destInvarient; int startbyte, endbyte; - IcDeclareMergeRop (); - -#ifdef IC_24BIT - if (bpp == 24 && !IcCheck24Pix (pm)) + FbDeclareMergeRop (); + + /* are we just copying multiples of 8 bits? if so, run, forrest, run! + the memcpy()'s should be pluggable ala mplayer|xine - perhaps we can get + one of the above to give up their code for us. + */ + if((pm==FB_ALLONES) && (alu==GXcopy) && !reverse && (srcX&7)==0 && (dstX&7)==0 && (width&7)==0) { - IcBlt24 (srcLine, srcStride, srcX, dstLine, dstStride, dstX, + CARD8 *isrc=(CARD8 *)srcLine; + CARD8 *idst=(CARD8 *)dstLine; + int sstride=srcStride*sizeof(FbBits); + int dstride=dstStride*sizeof(FbBits); + int j; + width>>=3; + isrc+=(srcX>>3); + idst+=(dstX>>3); + if(!upsidedown) + for(j=0;j=0;j--) + memcpy(idst+j*dstride, isrc+j*sstride, width); + + return; + } + +#ifdef FB_24BIT + if (bpp == 24 && !FbCheck24Pix (pm)) + { + fbBlt24 (srcLine, srcStride, srcX, dstLine, dstStride, dstX, width, height, alu, pm, reverse, upsidedown); return; } #endif - IcInitializeMergeRop(alu, pm); - destInvarient = IcDestInvarientMergeRop(); + FbInitializeMergeRop(alu, pm); + destInvarient = FbDestInvarientMergeRop(); if (upsidedown) { srcLine += (height - 1) * (srcStride); @@ -81,21 +105,21 @@ IcBlt (pixman_bits_t *srcLine, srcStride = -srcStride; dstStride = -dstStride; } - IcMaskBitsBytes (dstX, width, destInvarient, startmask, startbyte, + FbMaskBitsBytes (dstX, width, destInvarient, startmask, startbyte, nmiddle, endmask, endbyte); if (reverse) { - srcLine += ((srcX + width - 1) >> IC_SHIFT) + 1; - dstLine += ((dstX + width - 1) >> IC_SHIFT) + 1; - srcX = (srcX + width - 1) & IC_MASK; - dstX = (dstX + width - 1) & IC_MASK; + srcLine += ((srcX + width - 1) >> FB_SHIFT) + 1; + dstLine += ((dstX + width - 1) >> FB_SHIFT) + 1; + srcX = (srcX + width - 1) & FB_MASK; + dstX = (dstX + width - 1) & FB_MASK; } else { - srcLine += srcX >> IC_SHIFT; - dstLine += dstX >> IC_SHIFT; - srcX &= IC_MASK; - dstX &= IC_MASK; + srcLine += srcX >> FB_SHIFT; + dstLine += dstX >> FB_SHIFT; + srcX &= FB_MASK; + dstX &= FB_MASK; } if (srcX == dstX) { @@ -111,13 +135,13 @@ IcBlt (pixman_bits_t *srcLine, { bits = *--src; --dst; - IcDoRightMaskByteMergeRop(dst, bits, endbyte, endmask); + FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask); } n = nmiddle; if (destInvarient) { while (n--) - *--dst = IcDoDestInvarientMergeRop(*--src); + *--dst = FbDoDestInvarientMergeRop(*--src); } else { @@ -125,14 +149,14 @@ IcBlt (pixman_bits_t *srcLine, { bits = *--src; --dst; - *dst = IcDoMergeRop (bits, *dst); + *dst = FbDoMergeRop (bits, *dst); } } if (startmask) { bits = *--src; --dst; - IcDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask); + FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask); } } else @@ -140,7 +164,7 @@ IcBlt (pixman_bits_t *srcLine, if (startmask) { bits = *src++; - IcDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask); + FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask); dst++; } n = nmiddle; @@ -149,12 +173,12 @@ IcBlt (pixman_bits_t *srcLine, #if 0 /* * This provides some speedup on screen->screen blts - * over the PCI bus, usually about 10%. But Ic + * over the PCI bus, usually about 10%. But fb * isn't usually used for this operation... */ if (_ca2 + 1 == 0 && _cx2 == 0) { - pixman_bits_t t1, t2, t3, t4; + FbBits t1, t2, t3, t4; while (n >= 4) { t1 = *src++; @@ -170,21 +194,21 @@ IcBlt (pixman_bits_t *srcLine, } #endif while (n--) - *dst++ = IcDoDestInvarientMergeRop(*src++); + *dst++ = FbDoDestInvarientMergeRop(*src++); } else { while (n--) { bits = *src++; - *dst = IcDoMergeRop (bits, *dst); + *dst = FbDoMergeRop (bits, *dst); dst++; } } if (endmask) { bits = *src; - IcDoRightMaskByteMergeRop(dst, bits, endbyte, endmask); + FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask); } } } @@ -194,12 +218,12 @@ IcBlt (pixman_bits_t *srcLine, if (srcX > dstX) { leftShift = srcX - dstX; - rightShift = IC_UNIT - leftShift; + rightShift = FB_UNIT - leftShift; } else { rightShift = dstX - srcX; - leftShift = IC_UNIT - rightShift; + leftShift = FB_UNIT - rightShift; } while (height--) { @@ -215,48 +239,48 @@ IcBlt (pixman_bits_t *srcLine, bits1 = *--src; if (endmask) { - bits = IcScrRight(bits1, rightShift); - if (IcScrRight(endmask, leftShift)) + bits = FbScrRight(bits1, rightShift); + if (FbScrRight(endmask, leftShift)) { bits1 = *--src; - bits |= IcScrLeft(bits1, leftShift); + bits |= FbScrLeft(bits1, leftShift); } --dst; - IcDoRightMaskByteMergeRop(dst, bits, endbyte, endmask); + FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask); } n = nmiddle; if (destInvarient) { while (n--) { - bits = IcScrRight(bits1, rightShift); + bits = FbScrRight(bits1, rightShift); bits1 = *--src; - bits |= IcScrLeft(bits1, leftShift); + bits |= FbScrLeft(bits1, leftShift); --dst; - *dst = IcDoDestInvarientMergeRop(bits); + *dst = FbDoDestInvarientMergeRop(bits); } } else { while (n--) { - bits = IcScrRight(bits1, rightShift); + bits = FbScrRight(bits1, rightShift); bits1 = *--src; - bits |= IcScrLeft(bits1, leftShift); + bits |= FbScrLeft(bits1, leftShift); --dst; - *dst = IcDoMergeRop(bits, *dst); + *dst = FbDoMergeRop(bits, *dst); } } if (startmask) { - bits = IcScrRight(bits1, rightShift); - if (IcScrRight(startmask, leftShift)) + bits = FbScrRight(bits1, rightShift); + if (FbScrRight(startmask, leftShift)) { bits1 = *--src; - bits |= IcScrLeft(bits1, leftShift); + bits |= FbScrLeft(bits1, leftShift); } --dst; - IcDoLeftMaskByteMergeRop (dst, bits, startbyte, startmask); + FbDoLeftMaskByteMergeRop (dst, bits, startbyte, startmask); } } else @@ -265,10 +289,10 @@ IcBlt (pixman_bits_t *srcLine, bits1 = *src++; if (startmask) { - bits = IcScrLeft(bits1, leftShift); + bits = FbScrLeft(bits1, leftShift); bits1 = *src++; - bits |= IcScrRight(bits1, rightShift); - IcDoLeftMaskByteMergeRop (dst, bits, startbyte, startmask); + bits |= FbScrRight(bits1, rightShift); + FbDoLeftMaskByteMergeRop (dst, bits, startbyte, startmask); dst++; } n = nmiddle; @@ -276,10 +300,10 @@ IcBlt (pixman_bits_t *srcLine, { while (n--) { - bits = IcScrLeft(bits1, leftShift); + bits = FbScrLeft(bits1, leftShift); bits1 = *src++; - bits |= IcScrRight(bits1, rightShift); - *dst = IcDoDestInvarientMergeRop(bits); + bits |= FbScrRight(bits1, rightShift); + *dst = FbDoDestInvarientMergeRop(bits); dst++; } } @@ -287,29 +311,29 @@ IcBlt (pixman_bits_t *srcLine, { while (n--) { - bits = IcScrLeft(bits1, leftShift); + bits = FbScrLeft(bits1, leftShift); bits1 = *src++; - bits |= IcScrRight(bits1, rightShift); - *dst = IcDoMergeRop(bits, *dst); + bits |= FbScrRight(bits1, rightShift); + *dst = FbDoMergeRop(bits, *dst); dst++; } } if (endmask) { - bits = IcScrLeft(bits1, leftShift); - if (IcScrLeft(endmask, rightShift)) + bits = FbScrLeft(bits1, leftShift); + if (FbScrLeft(endmask, rightShift)) { bits1 = *src; - bits |= IcScrRight(bits1, rightShift); + bits |= FbScrRight(bits1, rightShift); } - IcDoRightMaskByteMergeRop (dst, bits, endbyte, endmask); + FbDoRightMaskByteMergeRop (dst, bits, endbyte, endmask); } } } } } -#ifdef IC_24BIT +#ifdef FB_24BIT #undef DEBUG_BLT24 #ifdef DEBUG_BLT24 @@ -326,65 +350,65 @@ getPixel (char *src, int x) #endif static void -IcBlt24Line (pixman_bits_t *src, +fbBlt24Line (FbBits *src, int srcX, - pixman_bits_t *dst, + FbBits *dst, int dstX, int width, int alu, - pixman_bits_t pm, + FbBits pm, - int reverse) + Bool reverse) { #ifdef DEBUG_BLT24 char *origDst = (char *) dst; - pixman_bits_t *origLine = dst + ((dstX >> IC_SHIFT) - 1); - int origNlw = ((width + IC_MASK) >> IC_SHIFT) + 3; + FbBits *origLine = dst + ((dstX >> FB_SHIFT) - 1); + int origNlw = ((width + FB_MASK) >> FB_SHIFT) + 3; int origX = dstX / 24; #endif int leftShift, rightShift; - pixman_bits_t startmask, endmask; + FbBits startmask, endmask; int n; - pixman_bits_t bits, bits1; - pixman_bits_t mask; + FbBits bits, bits1; + FbBits mask; int rot; - IcDeclareMergeRop (); + FbDeclareMergeRop (); - IcInitializeMergeRop (alu, IC_ALLONES); - IcMaskBits(dstX, width, startmask, n, endmask); + FbInitializeMergeRop (alu, FB_ALLONES); + FbMaskBits(dstX, width, startmask, n, endmask); #ifdef DEBUG_BLT24 ErrorF ("dstX %d width %d reverse %d\n", dstX, width, reverse); #endif if (reverse) { - src += ((srcX + width - 1) >> IC_SHIFT) + 1; - dst += ((dstX + width - 1) >> IC_SHIFT) + 1; - rot = IcFirst24Rot (((dstX + width - 8) & IC_MASK)); - rot = IcPrev24Rot(rot); + src += ((srcX + width - 1) >> FB_SHIFT) + 1; + dst += ((dstX + width - 1) >> FB_SHIFT) + 1; + rot = FbFirst24Rot (((dstX + width - 8) & FB_MASK)); + rot = FbPrev24Rot(rot); #ifdef DEBUG_BLT24 - ErrorF ("dstX + width - 8: %d rot: %d\n", (dstX + width - 8) & IC_MASK, rot); + ErrorF ("dstX + width - 8: %d rot: %d\n", (dstX + width - 8) & FB_MASK, rot); #endif - srcX = (srcX + width - 1) & IC_MASK; - dstX = (dstX + width - 1) & IC_MASK; + srcX = (srcX + width - 1) & FB_MASK; + dstX = (dstX + width - 1) & FB_MASK; } else { - src += srcX >> IC_SHIFT; - dst += dstX >> IC_SHIFT; - srcX &= IC_MASK; - dstX &= IC_MASK; - rot = IcFirst24Rot (dstX); + src += srcX >> FB_SHIFT; + dst += dstX >> FB_SHIFT; + srcX &= FB_MASK; + dstX &= FB_MASK; + rot = FbFirst24Rot (dstX); #ifdef DEBUG_BLT24 ErrorF ("dstX: %d rot: %d\n", dstX, rot); #endif } - mask = IcRot24(pm,rot); + mask = FbRot24(pm,rot); #ifdef DEBUG_BLT24 ErrorF ("pm 0x%x mask 0x%x\n", pm, mask); #endif @@ -396,21 +420,21 @@ IcBlt24Line (pixman_bits_t *src, { bits = *--src; --dst; - *dst = IcDoMaskMergeRop (bits, *dst, mask & endmask); - mask = IcPrev24Pix (mask); + *dst = FbDoMaskMergeRop (bits, *dst, mask & endmask); + mask = FbPrev24Pix (mask); } while (n--) { bits = *--src; --dst; - *dst = IcDoMaskMergeRop (bits, *dst, mask); - mask = IcPrev24Pix (mask); + *dst = FbDoMaskMergeRop (bits, *dst, mask); + mask = FbPrev24Pix (mask); } if (startmask) { bits = *--src; --dst; - *dst = IcDoMaskMergeRop(bits, *dst, mask & startmask); + *dst = FbDoMaskMergeRop(bits, *dst, mask & startmask); } } else @@ -418,21 +442,21 @@ IcBlt24Line (pixman_bits_t *src, if (startmask) { bits = *src++; - *dst = IcDoMaskMergeRop (bits, *dst, mask & startmask); + *dst = FbDoMaskMergeRop (bits, *dst, mask & startmask); dst++; - mask = IcNext24Pix(mask); + mask = FbNext24Pix(mask); } while (n--) { bits = *src++; - *dst = IcDoMaskMergeRop (bits, *dst, mask); + *dst = FbDoMaskMergeRop (bits, *dst, mask); dst++; - mask = IcNext24Pix(mask); + mask = FbNext24Pix(mask); } if (endmask) { bits = *src; - *dst = IcDoMaskMergeRop(bits, *dst, mask & endmask); + *dst = FbDoMaskMergeRop(bits, *dst, mask & endmask); } } } @@ -441,12 +465,12 @@ IcBlt24Line (pixman_bits_t *src, if (srcX > dstX) { leftShift = srcX - dstX; - rightShift = IC_UNIT - leftShift; + rightShift = FB_UNIT - leftShift; } else { rightShift = dstX - srcX; - leftShift = IC_UNIT - rightShift; + leftShift = FB_UNIT - rightShift; } bits1 = 0; @@ -456,35 +480,35 @@ IcBlt24Line (pixman_bits_t *src, bits1 = *--src; if (endmask) { - bits = IcScrRight(bits1, rightShift); - if (IcScrRight(endmask, leftShift)) + bits = FbScrRight(bits1, rightShift); + if (FbScrRight(endmask, leftShift)) { bits1 = *--src; - bits |= IcScrLeft(bits1, leftShift); + bits |= FbScrLeft(bits1, leftShift); } --dst; - *dst = IcDoMaskMergeRop (bits, *dst, mask & endmask); - mask = IcPrev24Pix(mask); + *dst = FbDoMaskMergeRop (bits, *dst, mask & endmask); + mask = FbPrev24Pix(mask); } while (n--) { - bits = IcScrRight(bits1, rightShift); + bits = FbScrRight(bits1, rightShift); bits1 = *--src; - bits |= IcScrLeft(bits1, leftShift); + bits |= FbScrLeft(bits1, leftShift); --dst; - *dst = IcDoMaskMergeRop(bits, *dst, mask); - mask = IcPrev24Pix(mask); + *dst = FbDoMaskMergeRop(bits, *dst, mask); + mask = FbPrev24Pix(mask); } if (startmask) { - bits = IcScrRight(bits1, rightShift); - if (IcScrRight(startmask, leftShift)) + bits = FbScrRight(bits1, rightShift); + if (FbScrRight(startmask, leftShift)) { bits1 = *--src; - bits |= IcScrLeft(bits1, leftShift); + bits |= FbScrLeft(bits1, leftShift); } --dst; - *dst = IcDoMaskMergeRop (bits, *dst, mask & startmask); + *dst = FbDoMaskMergeRop (bits, *dst, mask & startmask); } } else @@ -493,31 +517,31 @@ IcBlt24Line (pixman_bits_t *src, bits1 = *src++; if (startmask) { - bits = IcScrLeft(bits1, leftShift); + bits = FbScrLeft(bits1, leftShift); bits1 = *src++; - bits |= IcScrRight(bits1, rightShift); - *dst = IcDoMaskMergeRop (bits, *dst, mask & startmask); + bits |= FbScrRight(bits1, rightShift); + *dst = FbDoMaskMergeRop (bits, *dst, mask & startmask); dst++; - mask = IcNext24Pix(mask); + mask = FbNext24Pix(mask); } while (n--) { - bits = IcScrLeft(bits1, leftShift); + bits = FbScrLeft(bits1, leftShift); bits1 = *src++; - bits |= IcScrRight(bits1, rightShift); - *dst = IcDoMaskMergeRop(bits, *dst, mask); + bits |= FbScrRight(bits1, rightShift); + *dst = FbDoMaskMergeRop(bits, *dst, mask); dst++; - mask = IcNext24Pix(mask); + mask = FbNext24Pix(mask); } if (endmask) { - bits = IcScrLeft(bits1, leftShift); - if (IcScrLeft(endmask, rightShift)) + bits = FbScrLeft(bits1, leftShift); + if (FbScrLeft(endmask, rightShift)) { bits1 = *src; - bits |= IcScrRight(bits1, rightShift); + bits |= FbScrRight(bits1, rightShift); } - *dst = IcDoMaskMergeRop (bits, *dst, mask & endmask); + *dst = FbDoMaskMergeRop (bits, *dst, mask & endmask); } } } @@ -540,22 +564,22 @@ IcBlt24Line (pixman_bits_t *src, } void -IcBlt24 (pixman_bits_t *srcLine, - IcStride srcStride, +fbBlt24 (FbBits *srcLine, + FbStride srcStride, int srcX, - pixman_bits_t *dstLine, - IcStride dstStride, + FbBits *dstLine, + FbStride dstStride, int dstX, int width, int height, int alu, - pixman_bits_t pm, + FbBits pm, - int reverse, - int upsidedown) + Bool reverse, + Bool upsidedown) { if (upsidedown) { @@ -566,7 +590,7 @@ IcBlt24 (pixman_bits_t *srcLine, } while (height--) { - IcBlt24Line (srcLine, srcX, dstLine, dstX, width, alu, pm, reverse); + fbBlt24Line (srcLine, srcX, dstLine, dstX, width, alu, pm, reverse); srcLine += srcStride; dstLine += dstStride; } @@ -574,25 +598,25 @@ IcBlt24 (pixman_bits_t *srcLine, ErrorF ("\n"); #endif } -#endif /* IC_24BIT */ +#endif /* FB_24BIT */ -#if IC_SHIFT == IC_STIP_SHIFT + 1 +#if FB_SHIFT == FB_STIP_SHIFT + 1 /* - * Could be generalized to IC_SHIFT > IC_STIP_SHIFT + 1 by + * Could be generalized to FB_SHIFT > FB_STIP_SHIFT + 1 by * creating an ring of values stepped through for each line */ void -IcBltOdd (pixman_bits_t *srcLine, - IcStride srcStrideEven, - IcStride srcStrideOdd, +fbBltOdd (FbBits *srcLine, + FbStride srcStrideEven, + FbStride srcStrideOdd, int srcXEven, int srcXOdd, - pixman_bits_t *dstLine, - IcStride dstStrideEven, - IcStride dstStrideOdd, + FbBits *dstLine, + FbStride dstStrideEven, + FbStride dstStrideOdd, int dstXEven, int dstXOdd, @@ -600,46 +624,46 @@ IcBltOdd (pixman_bits_t *srcLine, int height, int alu, - pixman_bits_t pm, + FbBits pm, int bpp) { - pixman_bits_t *src; + FbBits *src; int leftShiftEven, rightShiftEven; - pixman_bits_t startmaskEven, endmaskEven; + FbBits startmaskEven, endmaskEven; int nmiddleEven; - pixman_bits_t *dst; + FbBits *dst; int leftShiftOdd, rightShiftOdd; - pixman_bits_t startmaskOdd, endmaskOdd; + FbBits startmaskOdd, endmaskOdd; int nmiddleOdd; int leftShift, rightShift; - pixman_bits_t startmask, endmask; + FbBits startmask, endmask; int nmiddle; int srcX, dstX; - pixman_bits_t bits, bits1; + FbBits bits, bits1; int n; - int destInvarient; - int even; - IcDeclareMergeRop (); + Bool destInvarient; + Bool even; + FbDeclareMergeRop (); - IcInitializeMergeRop (alu, pm); - destInvarient = IcDestInvarientMergeRop(); + FbInitializeMergeRop (alu, pm); + destInvarient = FbDestInvarientMergeRop(); - srcLine += srcXEven >> IC_SHIFT; - dstLine += dstXEven >> IC_SHIFT; - srcXEven &= IC_MASK; - dstXEven &= IC_MASK; - srcXOdd &= IC_MASK; - dstXOdd &= IC_MASK; + srcLine += srcXEven >> FB_SHIFT; + dstLine += dstXEven >> FB_SHIFT; + srcXEven &= FB_MASK; + dstXEven &= FB_MASK; + srcXOdd &= FB_MASK; + dstXOdd &= FB_MASK; - IcMaskBits(dstXEven, width, startmaskEven, nmiddleEven, endmaskEven); - IcMaskBits(dstXOdd, width, startmaskOdd, nmiddleOdd, endmaskOdd); + FbMaskBits(dstXEven, width, startmaskEven, nmiddleEven, endmaskEven); + FbMaskBits(dstXOdd, width, startmaskOdd, nmiddleOdd, endmaskOdd); - even = 1; + even = TRUE; InitializeShifts(srcXEven, dstXEven, leftShiftEven, rightShiftEven); InitializeShifts(srcXOdd, dstXOdd, leftShiftOdd, rightShiftOdd); while (height--) @@ -657,7 +681,7 @@ IcBltOdd (pixman_bits_t *srcLine, rightShift = rightShiftEven; srcLine += srcStrideEven; dstLine += dstStrideEven; - even = 0; + even = FALSE; } else { @@ -670,14 +694,14 @@ IcBltOdd (pixman_bits_t *srcLine, rightShift = rightShiftOdd; srcLine += srcStrideOdd; dstLine += dstStrideOdd; - even = 1; + even = TRUE; } if (srcX == dstX) { if (startmask) { bits = *src++; - *dst = IcDoMaskMergeRop (bits, *dst, startmask); + *dst = FbDoMaskMergeRop (bits, *dst, startmask); dst++; } n = nmiddle; @@ -686,7 +710,7 @@ IcBltOdd (pixman_bits_t *srcLine, while (n--) { bits = *src++; - *dst = IcDoDestInvarientMergeRop(bits); + *dst = FbDoDestInvarientMergeRop(bits); dst++; } } @@ -695,14 +719,14 @@ IcBltOdd (pixman_bits_t *srcLine, while (n--) { bits = *src++; - *dst = IcDoMergeRop (bits, *dst); + *dst = FbDoMergeRop (bits, *dst); dst++; } } if (endmask) { bits = *src; - *dst = IcDoMaskMergeRop(bits, *dst, endmask); + *dst = FbDoMaskMergeRop(bits, *dst, endmask); } } else @@ -712,10 +736,10 @@ IcBltOdd (pixman_bits_t *srcLine, bits = *src++; if (startmask) { - bits1 = IcScrLeft(bits, leftShift); + bits1 = FbScrLeft(bits, leftShift); bits = *src++; - bits1 |= IcScrRight(bits, rightShift); - *dst = IcDoMaskMergeRop (bits1, *dst, startmask); + bits1 |= FbScrRight(bits, rightShift); + *dst = FbDoMaskMergeRop (bits1, *dst, startmask); dst++; } n = nmiddle; @@ -723,10 +747,10 @@ IcBltOdd (pixman_bits_t *srcLine, { while (n--) { - bits1 = IcScrLeft(bits, leftShift); + bits1 = FbScrLeft(bits, leftShift); bits = *src++; - bits1 |= IcScrRight(bits, rightShift); - *dst = IcDoDestInvarientMergeRop(bits1); + bits1 |= FbScrRight(bits, rightShift); + *dst = FbDoDestInvarientMergeRop(bits1); dst++; } } @@ -734,38 +758,38 @@ IcBltOdd (pixman_bits_t *srcLine, { while (n--) { - bits1 = IcScrLeft(bits, leftShift); + bits1 = FbScrLeft(bits, leftShift); bits = *src++; - bits1 |= IcScrRight(bits, rightShift); - *dst = IcDoMergeRop(bits1, *dst); + bits1 |= FbScrRight(bits, rightShift); + *dst = FbDoMergeRop(bits1, *dst); dst++; } } if (endmask) { - bits1 = IcScrLeft(bits, leftShift); - if (IcScrLeft(endmask, rightShift)) + bits1 = FbScrLeft(bits, leftShift); + if (FbScrLeft(endmask, rightShift)) { bits = *src; - bits1 |= IcScrRight(bits, rightShift); + bits1 |= FbScrRight(bits, rightShift); } - *dst = IcDoMaskMergeRop (bits1, *dst, endmask); + *dst = FbDoMaskMergeRop (bits1, *dst, endmask); } } } } -#ifdef IC_24BIT +#ifdef FB_24BIT void -IcBltOdd24 (pixman_bits_t *srcLine, - IcStride srcStrideEven, - IcStride srcStrideOdd, +fbBltOdd24 (FbBits *srcLine, + FbStride srcStrideEven, + FbStride srcStrideOdd, int srcXEven, int srcXOdd, - pixman_bits_t *dstLine, - IcStride dstStrideEven, - IcStride dstStrideOdd, + FbBits *dstLine, + FbStride dstStrideEven, + FbStride dstStrideOdd, int dstXEven, int dstXOdd, @@ -773,27 +797,27 @@ IcBltOdd24 (pixman_bits_t *srcLine, int height, int alu, - pixman_bits_t pm) + FbBits pm) { - int even = 1; + Bool even = TRUE; while (height--) { if (even) { - IcBlt24Line (srcLine, srcXEven, dstLine, dstXEven, - width, alu, pm, 0); + fbBlt24Line (srcLine, srcXEven, dstLine, dstXEven, + width, alu, pm, FALSE); srcLine += srcStrideEven; dstLine += dstStrideEven; - even = 0; + even = FALSE; } else { - IcBlt24Line (srcLine, srcXOdd, dstLine, dstXOdd, - width, alu, pm, 0); + fbBlt24Line (srcLine, srcXOdd, dstLine, dstXOdd, + width, alu, pm, FALSE); srcLine += srcStrideOdd; dstLine += dstStrideOdd; - even = 1; + even = TRUE; } } #if 0 @@ -804,14 +828,14 @@ IcBltOdd24 (pixman_bits_t *srcLine, #endif -#if IC_STIP_SHIFT != IC_SHIFT +#if FB_STIP_SHIFT != FB_SHIFT void -IcSetBltOdd (IcStip *stip, - IcStride stipStride, +fbSetBltOdd (FbStip *stip, + FbStride stipStride, int srcX, - pixman_bits_t **bits, - IcStride *strideEven, - IcStride *strideOdd, + FbBits **bits, + FbStride *strideEven, + FbStride *strideOdd, int *srcXEven, int *srcXOdd) { @@ -821,78 +845,78 @@ IcSetBltOdd (IcStip *stip, /* * bytes needed to align source */ - srcAdjust = (((int) stip) & (IC_MASK >> 3)); + srcAdjust = (((int) stip) & (FB_MASK >> 3)); /* - * IcStip units needed to align stride + * FbStip units needed to align stride */ - strideAdjust = stipStride & (IC_MASK >> IC_STIP_SHIFT); + strideAdjust = stipStride & (FB_MASK >> FB_STIP_SHIFT); - *bits = (pixman_bits_t *) ((char *) stip - srcAdjust); + *bits = (FbBits *) ((char *) stip - srcAdjust); if (srcAdjust) { - *strideEven = IcStipStrideToBitsStride (stipStride + 1); - *strideOdd = IcStipStrideToBitsStride (stipStride); + *strideEven = FbStipStrideToBitsStride (stipStride + 1); + *strideOdd = FbStipStrideToBitsStride (stipStride); *srcXEven = srcX + (srcAdjust << 3); - *srcXOdd = srcX + (srcAdjust << 3) - (strideAdjust << IC_STIP_SHIFT); + *srcXOdd = srcX + (srcAdjust << 3) - (strideAdjust << FB_STIP_SHIFT); } else { - *strideEven = IcStipStrideToBitsStride (stipStride); - *strideOdd = IcStipStrideToBitsStride (stipStride + 1); + *strideEven = FbStipStrideToBitsStride (stipStride); + *strideOdd = FbStipStrideToBitsStride (stipStride + 1); *srcXEven = srcX; - *srcXOdd = srcX + (strideAdjust << IC_STIP_SHIFT); + *srcXOdd = srcX + (strideAdjust << FB_STIP_SHIFT); } } #endif void -IcBltStip (IcStip *src, - IcStride srcStride, /* in IcStip units, not pixman_bits_t units */ +fbBltStip (FbStip *src, + FbStride srcStride, /* in FbStip units, not FbBits units */ int srcX, - IcStip *dst, - IcStride dstStride, /* in IcStip units, not pixman_bits_t units */ + FbStip *dst, + FbStride dstStride, /* in FbStip units, not FbBits units */ int dstX, int width, int height, int alu, - pixman_bits_t pm, + FbBits pm, int bpp) { -#if IC_STIP_SHIFT != IC_SHIFT - if (IC_STIP_ODDSTRIDE(srcStride) || IC_STIP_ODDPTR(src) || - IC_STIP_ODDSTRIDE(dstStride) || IC_STIP_ODDPTR(dst)) +#if FB_STIP_SHIFT != FB_SHIFT + if (FB_STIP_ODDSTRIDE(srcStride) || FB_STIP_ODDPTR(src) || + FB_STIP_ODDSTRIDE(dstStride) || FB_STIP_ODDPTR(dst)) { - IcStride srcStrideEven, srcStrideOdd; - IcStride dstStrideEven, dstStrideOdd; + FbStride srcStrideEven, srcStrideOdd; + FbStride dstStrideEven, dstStrideOdd; int srcXEven, srcXOdd; int dstXEven, dstXOdd; - pixman_bits_t *s, *d; + FbBits *s, *d; int sx, dx; - src += srcX >> IC_STIP_SHIFT; - srcX &= IC_STIP_MASK; - dst += dstX >> IC_STIP_SHIFT; - dstX &= IC_STIP_MASK; + src += srcX >> FB_STIP_SHIFT; + srcX &= FB_STIP_MASK; + dst += dstX >> FB_STIP_SHIFT; + dstX &= FB_STIP_MASK; - IcSetBltOdd (src, srcStride, srcX, + fbSetBltOdd (src, srcStride, srcX, &s, &srcStrideEven, &srcStrideOdd, &srcXEven, &srcXOdd); - IcSetBltOdd (dst, dstStride, dstX, + fbSetBltOdd (dst, dstStride, dstX, &d, &dstStrideEven, &dstStrideOdd, &dstXEven, &dstXOdd); -#ifdef IC_24BIT - if (bpp == 24 && !IcCheck24Pix (pm)) +#ifdef FB_24BIT + if (bpp == 24 && !FbCheck24Pix (pm)) { - IcBltOdd24 (s, srcStrideEven, srcStrideOdd, + fbBltOdd24 (s, srcStrideEven, srcStrideOdd, srcXEven, srcXOdd, d, dstStrideEven, dstStrideOdd, @@ -903,7 +927,7 @@ IcBltStip (IcStip *src, else #endif { - IcBltOdd (s, srcStrideEven, srcStrideOdd, + fbBltOdd (s, srcStrideEven, srcStrideOdd, srcXEven, srcXOdd, d, dstStrideEven, dstStrideOdd, @@ -915,11 +939,11 @@ IcBltStip (IcStip *src, else #endif { - IcBlt ((pixman_bits_t *) src, IcStipStrideToBitsStride (srcStride), + fbBlt ((FbBits *) src, FbStipStrideToBitsStride (srcStride), srcX, - (pixman_bits_t *) dst, IcStipStrideToBitsStride (dstStride), + (FbBits *) dst, FbStipStrideToBitsStride (dstStride), dstX, width, height, - alu, pm, bpp, 0, 0); + alu, pm, bpp, FALSE, FALSE); } } diff --git a/gfx/cairo/libpixman/src/icbltone.c b/gfx/cairo/libpixman/src/icbltone.c index 7d1fd5ff6eb3..58f6e19d8b67 100644 --- a/gfx/cairo/libpixman/src/icbltone.c +++ b/gfx/cairo/libpixman/src/icbltone.c @@ -22,10 +22,10 @@ * PERFORMANCE OF THIS SOFTWARE. */ -#include "icint.h" +#include "pixman-xserver-compat.h" /* - * Example: srcX = 13 dstX = 8 (IC unit 32 dstBpp 8) + * Example: srcX = 13 dstX = 8 (FB unit 32 dstBpp 8) * * **** **** **** **** **** **** **** **** * ^ @@ -34,7 +34,7 @@ * leftShift = 12 * rightShift = 20 * - * Example: srcX = 0 dstX = 8 (IC unit 32 dstBpp 8) + * Example: srcX = 0 dstX = 8 (FB unit 32 dstBpp 8) * * **** **** **** **** **** **** **** **** * ^ @@ -48,16 +48,16 @@ #define LoadBits {\ if (leftShift) { \ bitsRight = *src++; \ - bits = (IcStipLeft (bitsLeft, leftShift) | \ - IcStipRight(bitsRight, rightShift)); \ + bits = (FbStipLeft (bitsLeft, leftShift) | \ + FbStipRight(bitsRight, rightShift)); \ bitsLeft = bitsRight; \ } else \ bits = *src++; \ } -#ifndef ICNOPIXADDR +#ifndef FBNOPIXADDR -#define LaneCases1(n,a) case n: (void)IcLaneCase(n,a); break +#define LaneCases1(n,a) case n: (void)FbLaneCase(n,a); break #define LaneCases2(n,a) LaneCases1(n,a); LaneCases1(n+1,a) #define LaneCases4(n,a) LaneCases2(n,a); LaneCases2(n+2,a) #define LaneCases8(n,a) LaneCases4(n,a); LaneCases4(n+4,a) @@ -67,16 +67,16 @@ #define LaneCases128(n,a) LaneCases64(n,a); LaneCases64(n+64,a) #define LaneCases256(n,a) LaneCases128(n,a); LaneCases128(n+128,a) -#if IC_SHIFT == 6 +#if FB_SHIFT == 6 #define LaneCases(a) LaneCases256(0,a) #endif -#if IC_SHIFT == 5 +#if FB_SHIFT == 5 #define LaneCases(a) LaneCases16(0,a) #endif -#if IC_SHIFT == 6 -static uint8_t const Ic8Lane[256] = { +#if FB_SHIFT == 6 +static uint8_t const fb8Lane[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, @@ -93,89 +93,89 @@ static uint8_t const Ic8Lane[256] = { 242, 243, 244,245,246,247,248,249,250,251,252,253,254,255, }; -static uint8_t const Ic16Lane[256] = { +static uint8_t const fb16Lane[256] = { 0x00, 0x03, 0x0c, 0x0f, 0x30, 0x33, 0x3c, 0x3f, 0xc0, 0xc3, 0xcc, 0xcf, 0xf0, 0xf3, 0xfc, 0xff, }; -static uint8_t const Ic32Lane[16] = { +static uint8_t const fb32Lane[16] = { 0x00, 0x0f, 0xf0, 0xff, }; #endif -#if IC_SHIFT == 5 -static uint8_t const Ic8Lane[16] = { +#if FB_SHIFT == 5 +static uint8_t const fb8Lane[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; -static uint8_t const Ic16Lane[16] = { +static uint8_t const fb16Lane[16] = { 0, 3, 12, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static uint8_t const Ic32Lane[16] = { +static uint8_t const fb32Lane[16] = { 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; #endif static const uint8_t * -IcLaneTable(int bpp) +fbLaneTable(int bpp) { switch (bpp) { case 8: - return Ic8Lane; + return fb8Lane; case 16: - return Ic16Lane; + return fb16Lane; case 32: - return Ic32Lane; + return fb32Lane; } return 0; } #endif void -IcBltOne (IcStip *src, - IcStride srcStride, /* IcStip units per scanline */ +fbBltOne (FbStip *src, + FbStride srcStride, /* FbStip units per scanline */ int srcX, /* bit position of source */ - pixman_bits_t *dst, - IcStride dstStride, /* pixman_bits_t units per scanline */ + FbBits *dst, + FbStride dstStride, /* FbBits units per scanline */ int dstX, /* bit position of dest */ int dstBpp, /* bits per destination unit */ int width, /* width in bits of destination */ int height, /* height in scanlines */ - pixman_bits_t fgand, /* rrop values */ - pixman_bits_t fgxor, - pixman_bits_t bgand, - pixman_bits_t bgxor) + FbBits fgand, /* rrop values */ + FbBits fgxor, + FbBits bgand, + FbBits bgxor) { - const pixman_bits_t *icbits; - int pixelsPerDst; /* dst pixels per pixman_bits_t */ - int unitsPerSrc; /* src patterns per IcStip */ + const FbBits *fbBits; + int pixelsPerDst; /* dst pixels per FbBits */ + int unitsPerSrc; /* src patterns per FbStip */ int leftShift, rightShift; /* align source with dest */ - pixman_bits_t startmask, endmask; /* dest scanline masks */ - IcStip bits=0, bitsLeft, bitsRight;/* source bits */ - IcStip left; - pixman_bits_t mask; + FbBits startmask, endmask; /* dest scanline masks */ + FbStip bits=0, bitsLeft, bitsRight;/* source bits */ + FbStip left; + FbBits mask; int nDst; /* dest longwords (w.o. end) */ int w; int n, nmiddle; int dstS; /* stipple-relative dst X coordinate */ - int copy; /* accelerate dest-invariant */ - int transparent; /* accelerate 0 nop */ + Bool copy; /* accelerate dest-invariant */ + Bool transparent; /* accelerate 0 nop */ int srcinc; /* source units consumed */ - int endNeedsLoad = 0; /* need load for endmask */ -#ifndef ICNOPIXADDR - const uint8_t *IcLane; + Bool endNeedsLoad = FALSE; /* need load for endmask */ +#ifndef FBNOPIXADDR + const CARD8 *fbLane; #endif int startbyte, endbyte; -#ifdef IC_24BIT +#ifdef FB_24BIT if (dstBpp == 24) { - IcBltOne24 (src, srcStride, srcX, + fbBltOne24 (src, srcStride, srcX, dst, dstStride, dstX, dstBpp, width, height, fgand, fgxor, bgand, bgxor); @@ -184,32 +184,32 @@ IcBltOne (IcStip *src, #endif /* - * Number of destination units in pixman_bits_t == number of stipple pixels + * Number of destination units in FbBits == number of stipple pixels * used each time */ - pixelsPerDst = IC_UNIT / dstBpp; + pixelsPerDst = FB_UNIT / dstBpp; /* - * Number of source stipple patterns in IcStip + * Number of source stipple patterns in FbStip */ - unitsPerSrc = IC_STIP_UNIT / pixelsPerDst; + unitsPerSrc = FB_STIP_UNIT / pixelsPerDst; - copy = 0; - transparent = 0; + copy = FALSE; + transparent = FALSE; if (bgand == 0 && fgand == 0) - copy = 1; - else if (bgand == IC_ALLONES && bgxor == 0) - transparent = 1; + copy = TRUE; + else if (bgand == FB_ALLONES && bgxor == 0) + transparent = TRUE; /* - * Adjust source and dest to nearest pixman_bits_t boundary + * Adjust source and dest to nearest FbBits boundary */ - src += srcX >> IC_STIP_SHIFT; - dst += dstX >> IC_SHIFT; - srcX &= IC_STIP_MASK; - dstX &= IC_MASK; + src += srcX >> FB_STIP_SHIFT; + dst += dstX >> FB_SHIFT; + srcX &= FB_STIP_MASK; + dstX &= FB_MASK; - IcMaskBitsBytes(dstX, width, copy, + FbMaskBitsBytes(dstX, width, copy, startmask, startbyte, nmiddle, endmask, endbyte); /* @@ -223,23 +223,23 @@ IcBltOne (IcStip *src, if (srcX >= dstS) { leftShift = srcX - dstS; - rightShift = IC_STIP_UNIT - leftShift; + rightShift = FB_STIP_UNIT - leftShift; } else { rightShift = dstS - srcX; - leftShift = IC_STIP_UNIT - rightShift; + leftShift = FB_STIP_UNIT - rightShift; } /* * Get pointer to stipple mask array for this depth */ - icbits = 0; /* unused */ + fbBits = 0; /* unused */ if (pixelsPerDst <= 8) - icbits = IcStippleTable(pixelsPerDst); -#ifndef ICNOPIXADDR - IcLane = 0; + fbBits = fbStippleTable(pixelsPerDst); +#ifndef FBNOPIXADDR + fbLane = 0; if (transparent && fgand == 0 && dstBpp >= 8) - IcLane = IcLaneTable(dstBpp); + fbLane = fbLaneTable(dstBpp); #endif /* @@ -294,26 +294,26 @@ IcBltOne (IcStip *src, */ if (startmask) { -#if IC_UNIT > 32 +#if FB_UNIT > 32 if (pixelsPerDst == 16) - mask = IcStipple16Bits(IcLeftStipBits(bits,16)); + mask = FbStipple16Bits(FbLeftStipBits(bits,16)); else #endif - mask = icbits[IcLeftStipBits(bits,pixelsPerDst)]; -#ifndef ICNOPIXADDR - if (IcLane) + mask = fbBits[FbLeftStipBits(bits,pixelsPerDst)]; +#ifndef FBNOPIXADDR + if (fbLane) { - IcTransparentSpan (dst, mask & startmask, fgxor, 1); + fbTransparentSpan (dst, mask & startmask, fgxor, 1); } else #endif { if (mask || !transparent) - IcDoLeftMaskByteStippleRRop (dst, mask, + FbDoLeftMaskByteStippleRRop (dst, mask, fgand, fgxor, bgand, bgxor, startbyte, startmask); } - bits = IcStipLeft (bits, pixelsPerDst); + bits = FbStipLeft (bits, pixelsPerDst); dst++; n--; w--; @@ -328,28 +328,28 @@ IcBltOne (IcStip *src, { while (n--) { -#if IC_UNIT > 32 +#if FB_UNIT > 32 if (pixelsPerDst == 16) - mask = IcStipple16Bits(IcLeftStipBits(bits,16)); + mask = FbStipple16Bits(FbLeftStipBits(bits,16)); else #endif - mask = icbits[IcLeftStipBits(bits,pixelsPerDst)]; - *dst = IcOpaqueStipple (mask, fgxor, bgxor); + mask = fbBits[FbLeftStipBits(bits,pixelsPerDst)]; + *dst = FbOpaqueStipple (mask, fgxor, bgxor); dst++; - bits = IcStipLeft(bits, pixelsPerDst); + bits = FbStipLeft(bits, pixelsPerDst); } } else { -#ifndef ICNOPIXADDR - if (IcLane) +#ifndef FBNOPIXADDR + if (fbLane) { while (bits && n) { - switch (IcLane[IcLeftStipBits(bits,pixelsPerDst)]) { - LaneCases((uint8_t *) dst); + switch (fbLane[FbLeftStipBits(bits,pixelsPerDst)]) { + LaneCases((CARD8 *) dst); } - bits = IcStipLeft(bits,pixelsPerDst); + bits = FbStipLeft(bits,pixelsPerDst); dst++; n--; } @@ -360,15 +360,15 @@ IcBltOne (IcStip *src, { while (n--) { - left = IcLeftStipBits(bits,pixelsPerDst); + left = FbLeftStipBits(bits,pixelsPerDst); if (left || !transparent) { - mask = icbits[left]; - *dst = IcStippleRRop (*dst, mask, + mask = fbBits[left]; + *dst = FbStippleRRop (*dst, mask, fgand, fgxor, bgand, bgxor); } dst++; - bits = IcStipLeft(bits, pixelsPerDst); + bits = FbStipLeft(bits, pixelsPerDst); } } } @@ -392,22 +392,22 @@ IcBltOne (IcStip *src, { LoadBits; } -#if IC_UNIT > 32 +#if FB_UNIT > 32 if (pixelsPerDst == 16) - mask = IcStipple16Bits(IcLeftStipBits(bits,16)); + mask = FbStipple16Bits(FbLeftStipBits(bits,16)); else #endif - mask = icbits[IcLeftStipBits(bits,pixelsPerDst)]; -#ifndef ICNOPIXADDR - if (IcLane) + mask = fbBits[FbLeftStipBits(bits,pixelsPerDst)]; +#ifndef FBNOPIXADDR + if (fbLane) { - IcTransparentSpan (dst, mask & endmask, fgxor, 1); + fbTransparentSpan (dst, mask & endmask, fgxor, 1); } else #endif { if (mask || !transparent) - IcDoRightMaskByteStippleRRop (dst, mask, + FbDoRightMaskByteStippleRRop (dst, mask, fgand, fgxor, bgand, bgxor, endbyte, endmask); } @@ -417,7 +417,7 @@ IcBltOne (IcStip *src, } } -#ifdef IC_24BIT +#ifdef FB_24BIT /* * Crufty macros to initialize the mask array, most of this @@ -432,9 +432,9 @@ IcBltOne (IcStip *src, #define Mask24Neg(x,r) (Mask24Pos(x,r) < 0 ? -Mask24Pos(x,r) : 0) #define Mask24Check(x,r) (Mask24Pos(x,r) < 0 ? 0 : \ - Mask24Pos(x,r) >= IC_UNIT ? 0 : Mask24Pos(x,r)) + Mask24Pos(x,r) >= FB_UNIT ? 0 : Mask24Pos(x,r)) -#define Mask24(x,r) (Mask24Pos(x,r) < IC_UNIT ? \ +#define Mask24(x,r) (Mask24Pos(x,r) < FB_UNIT ? \ (Mask24Pos(x,r) < 0 ? \ 0xffffff >> Mask24Neg (x,r) : \ 0xffffff << Mask24Check(x,r)) : 0) @@ -442,20 +442,20 @@ IcBltOne (IcStip *src, #define SelMask24(b,n,r) ((((b) >> n) & 1) * Mask24(n,r)) /* - * Untested for MSBFirst or IC_UNIT == 32 + * Untested for MSBFirst or FB_UNIT == 32 */ -#if IC_UNIT == 64 +#if FB_UNIT == 64 #define C4_24(b,r) \ (SelMask24(b,0,r) | \ SelMask24(b,1,r) | \ SelMask24(b,2,r) | \ SelMask24(b,3,r)) -#define IcStip24New(rot) (2 + (rot != 0)) -#define IcStip24Len 4 +#define FbStip24New(rot) (2 + (rot != 0)) +#define FbStip24Len 4 -static const pixman_bits_t icStipple24Bits[3][1 << IcStip24Len] = { +static const FbBits fbStipple24Bits[3][1 << FbStip24Len] = { /* rotate 0 */ { C4_24( 0, 0), C4_24( 1, 0), C4_24( 2, 0), C4_24( 3, 0), @@ -481,19 +481,19 @@ static const pixman_bits_t icStipple24Bits[3][1 << IcStip24Len] = { #endif -#if IC_UNIT == 32 +#if FB_UNIT == 32 #define C2_24(b,r) \ (SelMask24(b,0,r) | \ SelMask24(b,1,r)) -#define IcStip24Len 2 +#define FbStip24Len 2 #if BITMAP_BIT_ORDER == MSBFirst -#define IcStip24New(rot) (1 + (rot == 0)) +#define FbStip24New(rot) (1 + (rot == 0)) #else -#define IcStip24New(rot) (1 + (rot == 8)) +#define FbStip24New(rot) (1 + (rot == 8)) #endif -static const pixman_bits_t icStipple24Bits[3][1 << IcStip24Len] = { +static const FbBits fbStipple24Bits[3][1 << FbStip24Len] = { /* rotate 0 */ { C2_24( 0, 0), C2_24 ( 1, 0), C2_24 ( 2, 0), C2_24 ( 3, 0), @@ -511,51 +511,51 @@ static const pixman_bits_t icStipple24Bits[3][1 << IcStip24Len] = { #if BITMAP_BIT_ORDER == LSBFirst -#define IcMergeStip24Bits(left, right, new) \ - (IcStipLeft (left, new) | IcStipRight ((right), (IcStip24Len - (new)))) +#define FbMergeStip24Bits(left, right, new) \ + (FbStipLeft (left, new) | FbStipRight ((right), (FbStip24Len - (new)))) -#define IcMergePartStip24Bits(left, right, llen, rlen) \ - (left | IcStipRight(right, llen)) +#define FbMergePartStip24Bits(left, right, llen, rlen) \ + (left | FbStipRight(right, llen)) #else -#define IcMergeStip24Bits(left, right, new) \ - ((IcStipLeft (left, new) & ((1 << IcStip24Len) - 1)) | right) +#define FbMergeStip24Bits(left, right, new) \ + ((FbStipLeft (left, new) & ((1 << FbStip24Len) - 1)) | right) -#define IcMergePartStip24Bits(left, right, llen, rlen) \ - (IcStipLeft(left, rlen) | right) +#define FbMergePartStip24Bits(left, right, llen, rlen) \ + (FbStipLeft(left, rlen) | right) #endif -#define IcFirstStipBits(len,stip) {\ +#define fbFirstStipBits(len,stip) {\ int __len = (len); \ if (len <= remain) { \ - stip = IcLeftStipBits(bits, len); \ + stip = FbLeftStipBits(bits, len); \ } else { \ - stip = IcLeftStipBits(bits, remain); \ + stip = FbLeftStipBits(bits, remain); \ bits = *src++; \ __len = (len) - remain; \ - stip = IcMergePartStip24Bits(stip, IcLeftStipBits(bits, __len), \ + stip = FbMergePartStip24Bits(stip, FbLeftStipBits(bits, __len), \ remain, __len); \ - remain = IC_STIP_UNIT; \ + remain = FB_STIP_UNIT; \ } \ - bits = IcStipLeft (bits, __len); \ + bits = FbStipLeft (bits, __len); \ remain -= __len; \ } -#define IcInitStipBits(offset,len,stip) {\ - bits = IcStipLeft (*src++,offset); \ - remain = IC_STIP_UNIT - offset; \ - IcFirstStipBits(len,stip); \ - stip = IcMergeStip24Bits (0, stip, len); \ +#define fbInitStipBits(offset,len,stip) {\ + bits = FbStipLeft (*src++,offset); \ + remain = FB_STIP_UNIT - offset; \ + fbFirstStipBits(len,stip); \ + stip = FbMergeStip24Bits (0, stip, len); \ } -#define IcNextStipBits(rot,stip) {\ - int __new = IcStip24New(rot); \ - IcStip __right; \ - IcFirstStipBits(__new, __right); \ - stip = IcMergeStip24Bits (stip, __right, __new); \ - rot = IcNext24Rot (rot); \ +#define fbNextStipBits(rot,stip) {\ + int __new = FbStip24New(rot); \ + FbStip __right; \ + fbFirstStipBits(__new, __right); \ + stip = FbMergeStip24Bits (stip, __right, __new); \ + rot = FbNext24Rot (rot); \ } /* @@ -568,42 +568,42 @@ static const pixman_bits_t icStipple24Bits[3][1 << IcStip24Len] = { * and text */ void -IcBltOne24 (IcStip *srcLine, - IcStride srcStride, /* IcStip units per scanline */ +fbBltOne24 (FbStip *srcLine, + FbStride srcStride, /* FbStip units per scanline */ int srcX, /* bit position of source */ - pixman_bits_t *dst, - IcStride dstStride, /* pixman_bits_t units per scanline */ + FbBits *dst, + FbStride dstStride, /* FbBits units per scanline */ int dstX, /* bit position of dest */ int dstBpp, /* bits per destination unit */ int width, /* width in bits of destination */ int height, /* height in scanlines */ - pixman_bits_t fgand, /* rrop values */ - pixman_bits_t fgxor, - pixman_bits_t bgand, - pixman_bits_t bgxor) + FbBits fgand, /* rrop values */ + FbBits fgxor, + FbBits bgand, + FbBits bgxor) { - IcStip *src; - pixman_bits_t leftMask, rightMask, mask; + FbStip *src; + FbBits leftMask, rightMask, mask; int nlMiddle, nl; - IcStip stip, bits; + FbStip stip, bits; int remain; int dstS; int firstlen; int rot0, rot; int nDst; - srcLine += srcX >> IC_STIP_SHIFT; - dst += dstX >> IC_SHIFT; - srcX &= IC_STIP_MASK; - dstX &= IC_MASK; - rot0 = IcFirst24Rot (dstX); + srcLine += srcX >> FB_STIP_SHIFT; + dst += dstX >> FB_SHIFT; + srcX &= FB_STIP_MASK; + dstX &= FB_MASK; + rot0 = FbFirst24Rot (dstX); - IcMaskBits (dstX, width, leftMask, nlMiddle, rightMask); + FbMaskBits (dstX, width, leftMask, nlMiddle, rightMask); dstS = (dstX + 23) / 24; - firstlen = IcStip24Len - dstS; + firstlen = FbStip24Len - dstS; nDst = nlMiddle; if (leftMask) @@ -618,33 +618,33 @@ IcBltOne24 (IcStip *srcLine, rot = rot0; src = srcLine; srcLine += srcStride; - IcInitStipBits (srcX,firstlen, stip); + fbInitStipBits (srcX,firstlen, stip); if (leftMask) { - mask = icStipple24Bits[rot >> 3][stip]; - *dst = (*dst & ~leftMask) | (IcOpaqueStipple (mask, - IcRot24(fgxor, rot), - IcRot24(bgxor, rot)) + mask = fbStipple24Bits[rot >> 3][stip]; + *dst = (*dst & ~leftMask) | (FbOpaqueStipple (mask, + FbRot24(fgxor, rot), + FbRot24(bgxor, rot)) & leftMask); dst++; - IcNextStipBits(rot,stip); + fbNextStipBits(rot,stip); } nl = nlMiddle; while (nl--) { - mask = icStipple24Bits[rot>>3][stip]; - *dst = IcOpaqueStipple (mask, - IcRot24(fgxor, rot), - IcRot24(bgxor, rot)); + mask = fbStipple24Bits[rot>>3][stip]; + *dst = FbOpaqueStipple (mask, + FbRot24(fgxor, rot), + FbRot24(bgxor, rot)); dst++; - IcNextStipBits(rot,stip); + fbNextStipBits(rot,stip); } if (rightMask) { - mask = icStipple24Bits[rot >> 3][stip]; - *dst = (*dst & ~rightMask) | (IcOpaqueStipple (mask, - IcRot24(fgxor, rot), - IcRot24(bgxor, rot)) + mask = fbStipple24Bits[rot >> 3][stip]; + *dst = (*dst & ~rightMask) | (FbOpaqueStipple (mask, + FbRot24(fgxor, rot), + FbRot24(bgxor, rot)) & rightMask); } dst += dstStride; @@ -652,41 +652,41 @@ IcBltOne24 (IcStip *srcLine, } } /* transparent copy */ - else if (bgand == IC_ALLONES && bgxor == 0 && fgand == 0) + else if (bgand == FB_ALLONES && bgxor == 0 && fgand == 0) { while (height--) { rot = rot0; src = srcLine; srcLine += srcStride; - IcInitStipBits (srcX, firstlen, stip); + fbInitStipBits (srcX, firstlen, stip); if (leftMask) { if (stip) { - mask = icStipple24Bits[rot >> 3][stip] & leftMask; - *dst = (*dst & ~mask) | (IcRot24(fgxor, rot) & mask); + mask = fbStipple24Bits[rot >> 3][stip] & leftMask; + *dst = (*dst & ~mask) | (FbRot24(fgxor, rot) & mask); } dst++; - IcNextStipBits (rot, stip); + fbNextStipBits (rot, stip); } nl = nlMiddle; while (nl--) { if (stip) { - mask = icStipple24Bits[rot>>3][stip]; - *dst = (*dst & ~mask) | (IcRot24(fgxor,rot) & mask); + mask = fbStipple24Bits[rot>>3][stip]; + *dst = (*dst & ~mask) | (FbRot24(fgxor,rot) & mask); } dst++; - IcNextStipBits (rot, stip); + fbNextStipBits (rot, stip); } if (rightMask) { if (stip) { - mask = icStipple24Bits[rot >> 3][stip] & rightMask; - *dst = (*dst & ~mask) | (IcRot24(fgxor, rot) & mask); + mask = fbStipple24Bits[rot >> 3][stip] & rightMask; + *dst = (*dst & ~mask) | (FbRot24(fgxor, rot) & mask); } } dst += dstStride; @@ -699,39 +699,39 @@ IcBltOne24 (IcStip *srcLine, rot = rot0; src = srcLine; srcLine += srcStride; - IcInitStipBits (srcX, firstlen, stip); + fbInitStipBits (srcX, firstlen, stip); if (leftMask) { - mask = icStipple24Bits[rot >> 3][stip]; - *dst = IcStippleRRopMask (*dst, mask, - IcRot24(fgand, rot), - IcRot24(fgxor, rot), - IcRot24(bgand, rot), - IcRot24(bgxor, rot), + mask = fbStipple24Bits[rot >> 3][stip]; + *dst = FbStippleRRopMask (*dst, mask, + FbRot24(fgand, rot), + FbRot24(fgxor, rot), + FbRot24(bgand, rot), + FbRot24(bgxor, rot), leftMask); dst++; - IcNextStipBits(rot,stip); + fbNextStipBits(rot,stip); } nl = nlMiddle; while (nl--) { - mask = icStipple24Bits[rot >> 3][stip]; - *dst = IcStippleRRop (*dst, mask, - IcRot24(fgand, rot), - IcRot24(fgxor, rot), - IcRot24(bgand, rot), - IcRot24(bgxor, rot)); + mask = fbStipple24Bits[rot >> 3][stip]; + *dst = FbStippleRRop (*dst, mask, + FbRot24(fgand, rot), + FbRot24(fgxor, rot), + FbRot24(bgand, rot), + FbRot24(bgxor, rot)); dst++; - IcNextStipBits(rot,stip); + fbNextStipBits(rot,stip); } if (rightMask) { - mask = icStipple24Bits[rot >> 3][stip]; - *dst = IcStippleRRopMask (*dst, mask, - IcRot24(fgand, rot), - IcRot24(fgxor, rot), - IcRot24(bgand, rot), - IcRot24(bgxor, rot), + mask = fbStipple24Bits[rot >> 3][stip]; + *dst = FbStippleRRopMask (*dst, mask, + FbRot24(fgand, rot), + FbRot24(fgxor, rot), + FbRot24(bgand, rot), + FbRot24(bgxor, rot), rightMask); } dst += dstStride; diff --git a/gfx/cairo/libpixman/src/iccolor.c b/gfx/cairo/libpixman/src/iccolor.c index afa52f7e2c41..e3e2a30b03c2 100644 --- a/gfx/cairo/libpixman/src/iccolor.c +++ b/gfx/cairo/libpixman/src/iccolor.c @@ -26,7 +26,7 @@ #ifdef ICINT_NEED_IC_ONES /* Fall back on HACKMEM 169. */ int -_IcOnes (unsigned long mask) +_FbOnes (unsigned long mask) { register unsigned long y; @@ -43,10 +43,10 @@ pixman_color_to_pixel (const pixman_format_t *format, { uint32_t r, g, b, a; - r = color->red >> (16 - _IcOnes (format->redMask)); - g = color->green >> (16 - _IcOnes (format->greenMask)); - b = color->blue >> (16 - _IcOnes (format->blueMask)); - a = color->alpha >> (16 - _IcOnes (format->alphaMask)); + r = color->red >> (16 - _FbOnes (format->redMask)); + g = color->green >> (16 - _FbOnes (format->greenMask)); + b = color->blue >> (16 - _FbOnes (format->blueMask)); + a = color->alpha >> (16 - _FbOnes (format->alphaMask)); r = r << format->red; g = g << format->green; b = b << format->blue; @@ -56,7 +56,7 @@ pixman_color_to_pixel (const pixman_format_t *format, slim_hidden_def(pixman_color_to_pixel); static uint16_t -IcFillColor (uint32_t pixel, int bits) +FbFillColor (uint32_t pixel, int bits) { while (bits < 16) { @@ -77,8 +77,8 @@ pixman_pixel_to_color (const pixman_format_t *format, g = (pixel >> format->green) & format->greenMask; b = (pixel >> format->blue) & format->blueMask; a = (pixel >> format->alpha) & format->alphaMask; - color->red = IcFillColor (r, _IcOnes (format->redMask)); - color->green = IcFillColor (r, _IcOnes (format->greenMask)); - color->blue = IcFillColor (r, _IcOnes (format->blueMask)); - color->alpha = IcFillColor (r, _IcOnes (format->alphaMask)); + color->red = FbFillColor (r, _FbOnes (format->redMask)); + color->green = FbFillColor (r, _FbOnes (format->greenMask)); + color->blue = FbFillColor (r, _FbOnes (format->blueMask)); + color->alpha = FbFillColor (r, _FbOnes (format->alphaMask)); } diff --git a/gfx/cairo/libpixman/src/iccompose.c b/gfx/cairo/libpixman/src/iccompose.c deleted file mode 100644 index 96d23b76be49..000000000000 --- a/gfx/cairo/libpixman/src/iccompose.c +++ /dev/null @@ -1,2745 +0,0 @@ -/* - * Copyright © 2000 Keith Packard - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - - -#include "icint.h" - -/* - * General purpose compositing code optimized for minimal memory - * references - * - * All work is done on canonical ARGB values, functions for fetching - * and storing these exist for each format. - */ - -/* - * Combine src and mask using IN - */ - -static uint32_t -IcCombineMaskU (pixman_compositeOperand *src, - pixman_compositeOperand *msk) -{ - uint32_t x; - uint16_t a; - uint16_t t; - uint32_t m,n,o,p; - - if (!msk) - return (*src->fetch) (src); - - a = (*msk->fetch) (msk) >> 24; - if (!a) - return 0; - - x = (*src->fetch) (src); - if (a == 0xff) - return x; - - m = IcInU(x,0,a,t); - n = IcInU(x,8,a,t); - o = IcInU(x,16,a,t); - p = IcInU(x,24,a,t); - return m|n|o|p; -} - -static IcCompSrc -IcCombineMaskC (pixman_compositeOperand *src, - pixman_compositeOperand *msk) -{ - IcCompSrc s; - uint32_t x; - uint32_t a; - uint16_t xa; - uint16_t t; - uint32_t m,n,o,p; - - if (!msk) - { - x = (*src->fetch) (src); - s.value = x; - x = x >> 24; - x |= x << 8; - x |= x << 16; - s.alpha = x; - return s; - } - - a = (*msk->fetcha) (msk); - if (!a) - { - s.value = 0; - s.alpha = 0; - return s; - } - - x = (*src->fetch) (src); - if (a == 0xffffffff) - { - s.value = x; - x = x >> 24; - x |= x << 8; - x |= x << 16; - s.alpha = x; - return s; - } - - m = IcInC(x,0,a,t); - n = IcInC(x,8,a,t); - o = IcInC(x,16,a,t); - p = IcInC(x,24,a,t); - s.value = m|n|o|p; - xa = x >> 24; - m = IcInU(a,0,xa,t); - n = IcInU(a,8,xa,t); - o = IcInU(a,16,xa,t); - p = IcInU(a,24,xa,t); - s.alpha = m|n|o|p; - return s; -} - -static uint32_t -IcCombineMaskValueC (pixman_compositeOperand *src, - pixman_compositeOperand *msk) -{ - uint32_t x; - uint32_t a; - uint16_t t; - uint32_t m,n,o,p; - - if (!msk) - { - return (*src->fetch) (src); - } - - a = (*msk->fetcha) (msk); - if (!a) - return a; - - x = (*src->fetch) (src); - if (a == 0xffffffff) - return x; - - m = IcInC(x,0,a,t); - n = IcInC(x,8,a,t); - o = IcInC(x,16,a,t); - p = IcInC(x,24,a,t); - return m|n|o|p; -} - -/* - * Combine src and mask using IN, generating only the alpha component - */ -static uint32_t -IcCombineMaskAlphaU (pixman_compositeOperand *src, - pixman_compositeOperand *msk) -{ - uint32_t x; - uint16_t a; - uint16_t t; - - if (!msk) - return (*src->fetch) (src); - - a = (*msk->fetch) (msk) >> 24; - if (!a) - return 0; - - x = (*src->fetch) (src); - if (a == 0xff) - return x; - - return IcInU(x,24,a,t); -} - -static uint32_t -IcCombineMaskAlphaC (pixman_compositeOperand *src, - pixman_compositeOperand *msk) -{ - uint32_t x; - uint32_t a; - uint16_t t; - uint32_t m,n,o,p; - - if (!msk) - return (*src->fetch) (src); - - a = (*msk->fetcha) (msk); - if (!a) - return 0; - - x = (*src->fetcha) (src); - if (a == 0xffffffff) - return x; - - m = IcInC(x,0,a,t); - n = IcInC(x,8,a,t); - o = IcInC(x,16,a,t); - p = IcInC(x,24,a,t); - return m|n|o|p; -} - -/* - * All of the composing functions - */ -static void -IcCombineClear (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - (*dst->store) (dst, 0); -} - -static void -IcCombineSrcU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - (*dst->store) (dst, IcCombineMaskU (src, msk)); -} - -static void -IcCombineSrcC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - (*dst->store) (dst, IcCombineMaskValueC (src, msk)); -} - -static void -IcCombineDst (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - /* noop */ -} - -static void -IcCombineOverU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - uint32_t s, d; - uint16_t a; - uint16_t t; - uint32_t m,n,o,p; - - s = IcCombineMaskU (src, msk); - a = ~s >> 24; - if (a != 0xff) - { - if (a) - { - d = (*dst->fetch) (dst); - m = IcOverU(s,d,0,a,t); - n = IcOverU(s,d,8,a,t); - o = IcOverU(s,d,16,a,t); - p = IcOverU(s,d,24,a,t); - s = m|n|o|p; - } - (*dst->store) (dst, s); - } -} - -static void -IcCombineOverC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCompSrc cs; - uint32_t s, d; - uint32_t a; - uint16_t t; - uint32_t m,n,o,p; - - cs = IcCombineMaskC (src, msk); - s = cs.value; - a = ~cs.alpha; - if (a != 0xffffffff) - { - if (a) - { - d = (*dst->fetch) (dst); - m = IcOverC(s,d,0,a,t); - n = IcOverC(s,d,8,a,t); - o = IcOverC(s,d,16,a,t); - p = IcOverC(s,d,24,a,t); - s = m|n|o|p; - } - (*dst->store) (dst, s); - } -} - -static void -IcCombineOverReverseU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - uint32_t s, d; - uint16_t a; - uint16_t t; - uint32_t m,n,o,p; - - d = (*dst->fetch) (dst); - a = ~d >> 24; - if (a) - { - s = IcCombineMaskU (src, msk); - if (a != 0xff) - { - m = IcOverU(d,s,0,a,t); - n = IcOverU(d,s,8,a,t); - o = IcOverU(d,s,16,a,t); - p = IcOverU(d,s,24,a,t); - s = m|n|o|p; - } - (*dst->store) (dst, s); - } -} - -static void -IcCombineOverReverseC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - uint32_t s, d; - uint32_t a; - uint16_t t; - uint32_t m,n,o,p; - - d = (*dst->fetch) (dst); - a = ~d >> 24; - if (a) - { - s = IcCombineMaskValueC (src, msk); - if (a != 0xff) - { - m = IcOverU(d,s,0,a,t); - n = IcOverU(d,s,8,a,t); - o = IcOverU(d,s,16,a,t); - p = IcOverU(d,s,24,a,t); - s = m|n|o|p; - } - (*dst->store) (dst, s); - } -} - -static void -IcCombineInU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - uint32_t s, d; - uint16_t a; - uint16_t t; - uint32_t m,n,o,p; - - d = (*dst->fetch) (dst); - a = d >> 24; - s = 0; - if (a) - { - s = IcCombineMaskU (src, msk); - if (a != 0xff) - { - m = IcInU(s,0,a,t); - n = IcInU(s,8,a,t); - o = IcInU(s,16,a,t); - p = IcInU(s,24,a,t); - s = m|n|o|p; - } - } - (*dst->store) (dst, s); -} - -static void -IcCombineInC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - uint32_t s, d; - uint16_t a; - uint16_t t; - uint32_t m,n,o,p; - - d = (*dst->fetch) (dst); - a = d >> 24; - s = 0; - if (a) - { - s = IcCombineMaskValueC (src, msk); - if (a != 0xff) - { - m = IcInU(s,0,a,t); - n = IcInU(s,8,a,t); - o = IcInU(s,16,a,t); - p = IcInU(s,24,a,t); - s = m|n|o|p; - } - } - (*dst->store) (dst, s); -} - -static void -IcCombineInReverseU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - uint32_t s, d; - uint16_t a; - uint16_t t; - uint32_t m,n,o,p; - - s = IcCombineMaskAlphaU (src, msk); - a = s >> 24; - if (a != 0xff) - { - d = 0; - if (a) - { - d = (*dst->fetch) (dst); - m = IcInU(d,0,a,t); - n = IcInU(d,8,a,t); - o = IcInU(d,16,a,t); - p = IcInU(d,24,a,t); - d = m|n|o|p; - } - (*dst->store) (dst, d); - } -} - -static void -IcCombineInReverseC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - uint32_t s, d; - uint32_t a; - uint16_t t; - uint32_t m,n,o,p; - - s = IcCombineMaskAlphaC (src, msk); - a = s; - if (a != 0xffffffff) - { - d = 0; - if (a) - { - d = (*dst->fetch) (dst); - m = IcInC(d,0,a,t); - n = IcInC(d,8,a,t); - o = IcInC(d,16,a,t); - p = IcInC(d,24,a,t); - d = m|n|o|p; - } - (*dst->store) (dst, d); - } -} - -static void -IcCombineOutU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - uint32_t s, d; - uint16_t a; - uint16_t t; - uint32_t m,n,o,p; - - d = (*dst->fetch) (dst); - a = ~d >> 24; - s = 0; - if (a) - { - s = IcCombineMaskU (src, msk); - if (a != 0xff) - { - m = IcInU(s,0,a,t); - n = IcInU(s,8,a,t); - o = IcInU(s,16,a,t); - p = IcInU(s,24,a,t); - s = m|n|o|p; - } - } - (*dst->store) (dst, s); -} - -static void -IcCombineOutC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - uint32_t s, d; - uint16_t a; - uint16_t t; - uint32_t m,n,o,p; - - d = (*dst->fetch) (dst); - a = ~d >> 24; - s = 0; - if (a) - { - s = IcCombineMaskValueC (src, msk); - if (a != 0xff) - { - m = IcInU(s,0,a,t); - n = IcInU(s,8,a,t); - o = IcInU(s,16,a,t); - p = IcInU(s,24,a,t); - s = m|n|o|p; - } - } - (*dst->store) (dst, s); -} - -static void -IcCombineOutReverseU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - uint32_t s, d; - uint16_t a; - uint16_t t; - uint32_t m,n,o,p; - - s = IcCombineMaskAlphaU (src, msk); - a = ~s >> 24; - if (a != 0xff) - { - d = 0; - if (a) - { - d = (*dst->fetch) (dst); - m = IcInU(d,0,a,t); - n = IcInU(d,8,a,t); - o = IcInU(d,16,a,t); - p = IcInU(d,24,a,t); - d = m|n|o|p; - } - (*dst->store) (dst, d); - } -} - -static void -IcCombineOutReverseC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - uint32_t s, d; - uint32_t a; - uint16_t t; - uint32_t m,n,o,p; - - s = IcCombineMaskAlphaC (src, msk); - a = ~s; - if (a != 0xffffffff) - { - d = 0; - if (a) - { - d = (*dst->fetch) (dst); - m = IcInC(d,0,a,t); - n = IcInC(d,8,a,t); - o = IcInC(d,16,a,t); - p = IcInC(d,24,a,t); - d = m|n|o|p; - } - (*dst->store) (dst, d); - } -} - -static void -IcCombineAtopU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - uint32_t s, d; - uint16_t ad, as; - uint16_t t,u,v; - uint32_t m,n,o,p; - - s = IcCombineMaskU (src, msk); - d = (*dst->fetch) (dst); - ad = ~s >> 24; - as = d >> 24; - m = IcGen(s,d,0,as,ad,t,u,v); - n = IcGen(s,d,8,as,ad,t,u,v); - o = IcGen(s,d,16,as,ad,t,u,v); - p = IcGen(s,d,24,as,ad,t,u,v); - (*dst->store) (dst, m|n|o|p); -} - -static void -IcCombineAtopC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCompSrc cs; - uint32_t s, d; - uint32_t ad; - uint16_t as; - uint16_t t, u, v; - uint32_t m,n,o,p; - - cs = IcCombineMaskC (src, msk); - d = (*dst->fetch) (dst); - s = cs.value; - ad = cs.alpha; - as = d >> 24; - m = IcGen(s,d,0,as,IcGet8(ad,0),t,u,v); - n = IcGen(s,d,8,as,IcGet8(ad,8),t,u,v); - o = IcGen(s,d,16,as,IcGet8(ad,16),t,u,v); - p = IcGen(s,d,24,as,IcGet8(ad,24),t,u,v); - (*dst->store) (dst, m|n|o|p); -} - -static void -IcCombineAtopReverseU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - uint32_t s, d; - uint16_t ad, as; - uint16_t t, u, v; - uint32_t m,n,o,p; - - s = IcCombineMaskU (src, msk); - d = (*dst->fetch) (dst); - ad = s >> 24; - as = ~d >> 24; - m = IcGen(s,d,0,as,ad,t,u,v); - n = IcGen(s,d,8,as,ad,t,u,v); - o = IcGen(s,d,16,as,ad,t,u,v); - p = IcGen(s,d,24,as,ad,t,u,v); - (*dst->store) (dst, m|n|o|p); -} - -static void -IcCombineAtopReverseC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCompSrc cs; - uint32_t s, d, ad; - uint16_t as; - uint16_t t, u, v; - uint32_t m,n,o,p; - - cs = IcCombineMaskC (src, msk); - d = (*dst->fetch) (dst); - s = cs.value; - ad = cs.alpha; - as = ~d >> 24; - m = IcGen(s,d,0,as,IcGet8(ad,0),t,u,v); - n = IcGen(s,d,8,as,IcGet8(ad,8),t,u,v); - o = IcGen(s,d,16,as,IcGet8(ad,16),t,u,v); - p = IcGen(s,d,24,as,IcGet8(ad,24),t,u,v); - (*dst->store) (dst, m|n|o|p); -} - -static void -IcCombineXorU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - uint32_t s, d; - uint16_t ad, as; - uint16_t t, u, v; - uint32_t m,n,o,p; - - s = IcCombineMaskU (src, msk); - d = (*dst->fetch) (dst); - ad = ~s >> 24; - as = ~d >> 24; - m = IcGen(s,d,0,as,ad,t,u,v); - n = IcGen(s,d,8,as,ad,t,u,v); - o = IcGen(s,d,16,as,ad,t,u,v); - p = IcGen(s,d,24,as,ad,t,u,v); - (*dst->store) (dst, m|n|o|p); -} - -static void -IcCombineXorC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCompSrc cs; - uint32_t s, d, ad; - uint16_t as; - uint16_t t, u, v; - uint32_t m,n,o,p; - - cs = IcCombineMaskC (src, msk); - d = (*dst->fetch) (dst); - s = cs.value; - ad = ~cs.alpha; - as = ~d >> 24; - m = IcGen(s,d,0,as,ad,t,u,v); - n = IcGen(s,d,8,as,ad,t,u,v); - o = IcGen(s,d,16,as,ad,t,u,v); - p = IcGen(s,d,24,as,ad,t,u,v); - (*dst->store) (dst, m|n|o|p); -} - -static void -IcCombineAddU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - uint32_t s, d; - uint16_t t; - uint32_t m,n,o,p; - - s = IcCombineMaskU (src, msk); - if (s == ~0) - (*dst->store) (dst, s); - else - { - d = (*dst->fetch) (dst); - if (s && d != ~0) - { - m = IcAdd(s,d,0,t); - n = IcAdd(s,d,8,t); - o = IcAdd(s,d,16,t); - p = IcAdd(s,d,24,t); - (*dst->store) (dst, m|n|o|p); - } - } -} - -static void -IcCombineAddC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - uint32_t s, d; - uint16_t t; - uint32_t m,n,o,p; - - s = IcCombineMaskValueC (src, msk); - if (s == ~0) - (*dst->store) (dst, s); - else - { - d = (*dst->fetch) (dst); - if (s && d != ~0) - { - m = IcAdd(s,d,0,t); - n = IcAdd(s,d,8,t); - o = IcAdd(s,d,16,t); - p = IcAdd(s,d,24,t); - (*dst->store) (dst, m|n|o|p); - } - } -} - -/* - * All of the disjoint composing functions - - The four entries in the first column indicate what source contributions - come from each of the four areas of the picture -- areas covered by neither - A nor B, areas covered only by A, areas covered only by B and finally - areas covered by both A and B. - - Disjoint Conjoint - Fa Fb Fa Fb -(0,0,0,0) 0 0 0 0 -(0,A,0,A) 1 0 1 0 -(0,0,B,B) 0 1 0 1 -(0,A,B,A) 1 min((1-a)/b,1) 1 max(1-a/b,0) -(0,A,B,B) min((1-b)/a,1) 1 max(1-b/a,0) 1 -(0,0,0,A) max(1-(1-b)/a,0) 0 min(1,b/a) 0 -(0,0,0,B) 0 max(1-(1-a)/b,0) 0 min(a/b,1) -(0,A,0,0) min(1,(1-b)/a) 0 max(1-b/a,0) 0 -(0,0,B,0) 0 min(1,(1-a)/b) 0 max(1-a/b,0) -(0,0,B,A) max(1-(1-b)/a,0) min(1,(1-a)/b) min(1,b/a) max(1-a/b,0) -(0,A,0,B) min(1,(1-b)/a) max(1-(1-a)/b,0) max(1-b/a,0) min(1,a/b) -(0,A,B,0) min(1,(1-b)/a) min(1,(1-a)/b) max(1-b/a,0) max(1-a/b,0) - - */ - -#define CombineAOut 1 -#define CombineAIn 2 -#define CombineBOut 4 -#define CombineBIn 8 - -#define CombineClear 0 -#define CombineA (CombineAOut|CombineAIn) -#define CombineB (CombineBOut|CombineBIn) -#define CombineAOver (CombineAOut|CombineBOut|CombineAIn) -#define CombineBOver (CombineAOut|CombineBOut|CombineBIn) -#define CombineAAtop (CombineBOut|CombineAIn) -#define CombineBAtop (CombineAOut|CombineBIn) -#define CombineXor (CombineAOut|CombineBOut) - -/* portion covered by a but not b */ -static uint8_t -IcCombineDisjointOutPart (uint8_t a, uint8_t b) -{ - /* min (1, (1-b) / a) */ - - b = ~b; /* 1 - b */ - if (b >= a) /* 1 - b >= a -> (1-b)/a >= 1 */ - return 0xff; /* 1 */ - return IcIntDiv(b,a); /* (1-b) / a */ -} - -/* portion covered by both a and b */ -static uint8_t -IcCombineDisjointInPart (uint8_t a, uint8_t b) -{ - /* max (1-(1-b)/a,0) */ - /* = - min ((1-b)/a - 1, 0) */ - /* = 1 - min (1, (1-b)/a) */ - - b = ~b; /* 1 - b */ - if (b >= a) /* 1 - b >= a -> (1-b)/a >= 1 */ - return 0; /* 1 - 1 */ - return ~IcIntDiv(b,a); /* 1 - (1-b) / a */ -} - -static void -IcCombineDisjointGeneralU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst, - uint8_t combine) -{ - uint32_t s, d; - uint32_t m,n,o,p; - uint16_t Fa, Fb, t, u, v; - uint8_t sa, da; - - s = IcCombineMaskU (src, msk); - sa = s >> 24; - - d = (*dst->fetch) (dst); - da = d >> 24; - - switch (combine & CombineA) { - default: - Fa = 0; - break; - case CombineAOut: - Fa = IcCombineDisjointOutPart (sa, da); - break; - case CombineAIn: - Fa = IcCombineDisjointInPart (sa, da); - break; - case CombineA: - Fa = 0xff; - break; - } - - switch (combine & CombineB) { - default: - Fb = 0; - break; - case CombineBOut: - Fb = IcCombineDisjointOutPart (da, sa); - break; - case CombineBIn: - Fb = IcCombineDisjointInPart (da, sa); - break; - case CombineB: - Fb = 0xff; - break; - } - m = IcGen (s,d,0,Fa,Fb,t,u,v); - n = IcGen (s,d,8,Fa,Fb,t,u,v); - o = IcGen (s,d,16,Fa,Fb,t,u,v); - p = IcGen (s,d,24,Fa,Fb,t,u,v); - s = m|n|o|p; - (*dst->store) (dst, s); -} - -static void -IcCombineDisjointGeneralC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst, - uint8_t combine) -{ - IcCompSrc cs; - uint32_t s, d; - uint32_t m,n,o,p; - uint32_t Fa; - uint16_t Fb, t, u, v; - uint32_t sa; - uint8_t da; - - cs = IcCombineMaskC (src, msk); - s = cs.value; - sa = cs.alpha; - - d = (*dst->fetch) (dst); - da = d >> 24; - - switch (combine & CombineA) { - default: - Fa = 0; - break; - case CombineAOut: - m = IcCombineDisjointOutPart ((uint8_t) (sa >> 0), da); - n = IcCombineDisjointOutPart ((uint8_t) (sa >> 8), da) << 8; - o = IcCombineDisjointOutPart ((uint8_t) (sa >> 16), da) << 16; - p = IcCombineDisjointOutPart ((uint8_t) (sa >> 24), da) << 24; - Fa = m|n|o|p; - break; - case CombineAIn: - m = IcCombineDisjointOutPart ((uint8_t) (sa >> 0), da); - n = IcCombineDisjointOutPart ((uint8_t) (sa >> 8), da) << 8; - o = IcCombineDisjointOutPart ((uint8_t) (sa >> 16), da) << 16; - p = IcCombineDisjointOutPart ((uint8_t) (sa >> 24), da) << 24; - Fa = m|n|o|p; - break; - case CombineA: - Fa = 0xffffffff; - break; - } - - switch (combine & CombineB) { - default: - Fb = 0; - break; - case CombineBOut: - Fb = IcCombineDisjointOutPart (da, sa); - break; - case CombineBIn: - Fb = IcCombineDisjointInPart (da, sa); - break; - case CombineB: - Fb = 0xff; - break; - } - m = IcGen (s,d,0,IcGet8(Fa,0),Fb,t,u,v); - n = IcGen (s,d,8,IcGet8(Fa,8),Fb,t,u,v); - o = IcGen (s,d,16,IcGet8(Fa,16),Fb,t,u,v); - p = IcGen (s,d,24,IcGet8(Fa,24),Fb,t,u,v); - s = m|n|o|p; - (*dst->store) (dst, s); -} - -static void -IcCombineDisjointOverU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - uint32_t s, d; - uint16_t a; - uint16_t t; - uint32_t m,n,o,p; - - s = IcCombineMaskU (src, msk); - a = s >> 24; - if (a != 0x00) - { - if (a != 0xff) - { - d = (*dst->fetch) (dst); - a = IcCombineDisjointOutPart (d >> 24, a); - m = IcOverU(s,d,0,a,t); - n = IcOverU(s,d,8,a,t); - o = IcOverU(s,d,16,a,t); - p = IcOverU(s,d,24,a,t); - s = m|n|o|p; - } - (*dst->store) (dst, s); - } -} - -static void -IcCombineDisjointOverC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineDisjointGeneralC (src, msk, dst, CombineAOver); -} - -static void -IcCombineDisjointOverReverseU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineDisjointGeneralU (src, msk, dst, CombineBOver); -} - -static void -IcCombineDisjointOverReverseC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineDisjointGeneralC (src, msk, dst, CombineBOver); -} - -static void -IcCombineDisjointInU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineDisjointGeneralU (src, msk, dst, CombineAIn); -} - -static void -IcCombineDisjointInC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineDisjointGeneralC (src, msk, dst, CombineAIn); -} - -static void -IcCombineDisjointInReverseU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineDisjointGeneralU (src, msk, dst, CombineBIn); -} - -static void -IcCombineDisjointInReverseC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineDisjointGeneralC (src, msk, dst, CombineBIn); -} - -static void -IcCombineDisjointOutU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineDisjointGeneralU (src, msk, dst, CombineAOut); -} - -static void -IcCombineDisjointOutC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineDisjointGeneralC (src, msk, dst, CombineAOut); -} - -static void -IcCombineDisjointOutReverseU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineDisjointGeneralU (src, msk, dst, CombineBOut); -} - -static void -IcCombineDisjointOutReverseC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineDisjointGeneralC (src, msk, dst, CombineBOut); -} - -static void -IcCombineDisjointAtopU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineDisjointGeneralU (src, msk, dst, CombineAAtop); -} - -static void -IcCombineDisjointAtopC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineDisjointGeneralC (src, msk, dst, CombineAAtop); -} - -static void -IcCombineDisjointAtopReverseU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineDisjointGeneralU (src, msk, dst, CombineBAtop); -} - -static void -IcCombineDisjointAtopReverseC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineDisjointGeneralC (src, msk, dst, CombineBAtop); -} - -static void -IcCombineDisjointXorU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineDisjointGeneralU (src, msk, dst, CombineXor); -} - -static void -IcCombineDisjointXorC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineDisjointGeneralC (src, msk, dst, CombineXor); -} - -/* portion covered by a but not b */ -static uint8_t -IcCombineConjointOutPart (uint8_t a, uint8_t b) -{ - /* max (1-b/a,0) */ - /* = 1-min(b/a,1) */ - - /* min (1, (1-b) / a) */ - - if (b >= a) /* b >= a -> b/a >= 1 */ - return 0x00; /* 0 */ - return ~IcIntDiv(b,a); /* 1 - b/a */ -} - -/* portion covered by both a and b */ -static uint8_t -IcCombineConjointInPart (uint8_t a, uint8_t b) -{ - /* min (1,b/a) */ - - if (b >= a) /* b >= a -> b/a >= 1 */ - return 0xff; /* 1 */ - return IcIntDiv(b,a); /* b/a */ -} - -static void -IcCombineConjointGeneralU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst, - uint8_t combine) -{ - uint32_t s, d; - uint32_t m,n,o,p; - uint16_t Fa, Fb, t, u, v; - uint8_t sa, da; - - s = IcCombineMaskU (src, msk); - sa = s >> 24; - - d = (*dst->fetch) (dst); - da = d >> 24; - - switch (combine & CombineA) { - default: - Fa = 0; - break; - case CombineAOut: - Fa = IcCombineConjointOutPart (sa, da); - break; - case CombineAIn: - Fa = IcCombineConjointInPart (sa, da); - break; - case CombineA: - Fa = 0xff; - break; - } - - switch (combine & CombineB) { - default: - Fb = 0; - break; - case CombineBOut: - Fb = IcCombineConjointOutPart (da, sa); - break; - case CombineBIn: - Fb = IcCombineConjointInPart (da, sa); - break; - case CombineB: - Fb = 0xff; - break; - } - m = IcGen (s,d,0,Fa,Fb,t,u,v); - n = IcGen (s,d,8,Fa,Fb,t,u,v); - o = IcGen (s,d,16,Fa,Fb,t,u,v); - p = IcGen (s,d,24,Fa,Fb,t,u,v); - s = m|n|o|p; - (*dst->store) (dst, s); -} - -static void -IcCombineConjointGeneralC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst, - uint8_t combine) -{ - IcCompSrc cs; - uint32_t s, d; - uint32_t m,n,o,p; - uint32_t Fa; - uint16_t Fb, t, u, v; - uint32_t sa; - uint8_t da; - - cs = IcCombineMaskC (src, msk); - s = cs.value; - sa = cs.alpha; - - d = (*dst->fetch) (dst); - da = d >> 24; - - switch (combine & CombineA) { - default: - Fa = 0; - break; - case CombineAOut: - m = IcCombineConjointOutPart ((uint8_t) (sa >> 0), da); - n = IcCombineConjointOutPart ((uint8_t) (sa >> 8), da) << 8; - o = IcCombineConjointOutPart ((uint8_t) (sa >> 16), da) << 16; - p = IcCombineConjointOutPart ((uint8_t) (sa >> 24), da) << 24; - Fa = m|n|o|p; - break; - case CombineAIn: - m = IcCombineConjointOutPart ((uint8_t) (sa >> 0), da); - n = IcCombineConjointOutPart ((uint8_t) (sa >> 8), da) << 8; - o = IcCombineConjointOutPart ((uint8_t) (sa >> 16), da) << 16; - p = IcCombineConjointOutPart ((uint8_t) (sa >> 24), da) << 24; - Fa = m|n|o|p; - break; - case CombineA: - Fa = 0xffffffff; - break; - } - - switch (combine & CombineB) { - default: - Fb = 0; - break; - case CombineBOut: - Fb = IcCombineConjointOutPart (da, sa); - break; - case CombineBIn: - Fb = IcCombineConjointInPart (da, sa); - break; - case CombineB: - Fb = 0xff; - break; - } - m = IcGen (s,d,0,IcGet8(Fa,0),Fb,t,u,v); - n = IcGen (s,d,8,IcGet8(Fa,8),Fb,t,u,v); - o = IcGen (s,d,16,IcGet8(Fa,16),Fb,t,u,v); - p = IcGen (s,d,24,IcGet8(Fa,24),Fb,t,u,v); - s = m|n|o|p; - (*dst->store) (dst, s); -} - -static void -IcCombineConjointOverU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralU (src, msk, dst, CombineAOver); -/* - uint32_t s, d; - uint16_t a; - uint16_t t; - uint32_t m,n,o,p; - - s = IcCombineMaskU (src, msk); - a = s >> 24; - if (a != 0x00) - { - if (a != 0xff) - { - d = (*dst->fetch) (dst); - a = IcCombineConjointOutPart (d >> 24, a); - m = IcOverU(s,d,0,a,t); - n = IcOverU(s,d,8,a,t); - o = IcOverU(s,d,16,a,t); - p = IcOverU(s,d,24,a,t); - s = m|n|o|p; - } - (*dst->store) (dst, s); - } - */ -} - -static void -IcCombineConjointOverC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralC (src, msk, dst, CombineAOver); -} - -static void -IcCombineConjointOverReverseU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralU (src, msk, dst, CombineBOver); -} - -static void -IcCombineConjointOverReverseC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralC (src, msk, dst, CombineBOver); -} - -static void -IcCombineConjointInU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralU (src, msk, dst, CombineAIn); -} - -static void -IcCombineConjointInC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralC (src, msk, dst, CombineAIn); -} - -static void -IcCombineConjointInReverseU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralU (src, msk, dst, CombineBIn); -} - -static void -IcCombineConjointInReverseC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralC (src, msk, dst, CombineBIn); -} - -static void -IcCombineConjointOutU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralU (src, msk, dst, CombineAOut); -} - -static void -IcCombineConjointOutC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralC (src, msk, dst, CombineAOut); -} - -static void -IcCombineConjointOutReverseU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralU (src, msk, dst, CombineBOut); -} - -static void -IcCombineConjointOutReverseC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralC (src, msk, dst, CombineBOut); -} - -static void -IcCombineConjointAtopU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralU (src, msk, dst, CombineAAtop); -} - -static void -IcCombineConjointAtopC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralC (src, msk, dst, CombineAAtop); -} - -static void -IcCombineConjointAtopReverseU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralU (src, msk, dst, CombineBAtop); -} - -static void -IcCombineConjointAtopReverseC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralC (src, msk, dst, CombineBAtop); -} - -static void -IcCombineConjointXorU (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralU (src, msk, dst, CombineXor); -} - -static void -IcCombineConjointXorC (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst) -{ - IcCombineConjointGeneralC (src, msk, dst, CombineXor); -} - -static IcCombineFunc const IcCombineFuncU[] = { - IcCombineClear, - IcCombineSrcU, - IcCombineDst, - IcCombineOverU, - IcCombineOverReverseU, - IcCombineInU, - IcCombineInReverseU, - IcCombineOutU, - IcCombineOutReverseU, - IcCombineAtopU, - IcCombineAtopReverseU, - IcCombineXorU, - IcCombineAddU, - IcCombineDisjointOverU, /* Saturate */ - 0, - 0, - IcCombineClear, - IcCombineSrcU, - IcCombineDst, - IcCombineDisjointOverU, - IcCombineDisjointOverReverseU, - IcCombineDisjointInU, - IcCombineDisjointInReverseU, - IcCombineDisjointOutU, - IcCombineDisjointOutReverseU, - IcCombineDisjointAtopU, - IcCombineDisjointAtopReverseU, - IcCombineDisjointXorU, - 0, - 0, - 0, - 0, - IcCombineClear, - IcCombineSrcU, - IcCombineDst, - IcCombineConjointOverU, - IcCombineConjointOverReverseU, - IcCombineConjointInU, - IcCombineConjointInReverseU, - IcCombineConjointOutU, - IcCombineConjointOutReverseU, - IcCombineConjointAtopU, - IcCombineConjointAtopReverseU, - IcCombineConjointXorU, -}; - -static IcCombineFunc const IcCombineFuncC[] = { - IcCombineClear, - IcCombineSrcC, - IcCombineDst, - IcCombineOverC, - IcCombineOverReverseC, - IcCombineInC, - IcCombineInReverseC, - IcCombineOutC, - IcCombineOutReverseC, - IcCombineAtopC, - IcCombineAtopReverseC, - IcCombineXorC, - IcCombineAddC, - IcCombineDisjointOverC, /* Saturate */ - 0, - 0, - IcCombineClear, /* 0x10 */ - IcCombineSrcC, - IcCombineDst, - IcCombineDisjointOverC, - IcCombineDisjointOverReverseC, - IcCombineDisjointInC, - IcCombineDisjointInReverseC, - IcCombineDisjointOutC, - IcCombineDisjointOutReverseC, - IcCombineDisjointAtopC, - IcCombineDisjointAtopReverseC, - IcCombineDisjointXorC, /* 0x1b */ - 0, - 0, - 0, - 0, - IcCombineClear, - IcCombineSrcC, - IcCombineDst, - IcCombineConjointOverC, - IcCombineConjointOverReverseC, - IcCombineConjointInC, - IcCombineConjointInReverseC, - IcCombineConjointOutC, - IcCombineConjointOutReverseC, - IcCombineConjointAtopC, - IcCombineConjointAtopReverseC, - IcCombineConjointXorC, -}; - -/* - * All of the fetch functions - */ - -static uint32_t -IcFetch_a8r8g8b8 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - return ((uint32_t *)line)[offset >> 5]; -} - -static uint32_t -IcFetch_x8r8g8b8 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - return ((uint32_t *)line)[offset >> 5] | 0xff000000; -} - -static uint32_t -IcFetch_a8b8g8r8 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint32_t *)line)[offset >> 5]; - - return ((pixel & 0xff000000) | - ((pixel >> 16) & 0xff) | - (pixel & 0x0000ff00) | - ((pixel & 0xff) << 16)); -} - -static uint32_t -IcFetch_x8b8g8r8 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint32_t *)line)[offset >> 5]; - - return ((0xff000000) | - ((pixel >> 16) & 0xff) | - (pixel & 0x0000ff00) | - ((pixel & 0xff) << 16)); -} - -static uint32_t -IcFetch_r8g8b8 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint8_t *pixel = ((uint8_t *) line) + (offset >> 3); -#if IMAGE_BYTE_ORDER == MSBFirst - return (0xff000000 | - (pixel[0] << 16) | - (pixel[1] << 8) | - (pixel[2])); -#else - return (0xff000000 | - (pixel[2] << 16) | - (pixel[1] << 8) | - (pixel[0])); -#endif -} - -static uint32_t -IcFetch_b8g8r8 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint8_t *pixel = ((uint8_t *) line) + (offset >> 3); -#if IMAGE_BYTE_ORDER == MSBFirst - return (0xff000000 | - (pixel[2] << 16) | - (pixel[1] << 8) | - (pixel[0])); -#else - return (0xff000000 | - (pixel[0] << 16) | - (pixel[1] << 8) | - (pixel[2])); -#endif -} - -static uint32_t -IcFetch_r5g6b5 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint16_t *) line)[offset >> 4]; - uint32_t r,g,b; - - r = ((pixel & 0xf800) | ((pixel & 0xe000) >> 5)) << 8; - g = ((pixel & 0x07e0) | ((pixel & 0x0600) >> 6)) << 5; - b = ((pixel & 0x001c) | ((pixel & 0x001f) << 5)) >> 2; - return (0xff000000 | r | g | b); -} - -static uint32_t -IcFetch_b5g6r5 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint16_t *) line)[offset >> 4]; - uint32_t r,g,b; - - b = ((pixel & 0xf800) | ((pixel & 0xe000) >> 5)) >> 8; - g = ((pixel & 0x07e0) | ((pixel & 0x0600) >> 6)) << 5; - r = ((pixel & 0x001c) | ((pixel & 0x001f) << 5)) << 14; - return (0xff000000 | r | g | b); -} - -static uint32_t -IcFetch_a1r5g5b5 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint16_t *) line)[offset >> 4]; - uint32_t a,r,g,b; - - a = (uint32_t) ((uint8_t) (0 - ((pixel & 0x8000) >> 15))) << 24; - r = ((pixel & 0x7c00) | ((pixel & 0x7000) >> 5)) << 9; - g = ((pixel & 0x03e0) | ((pixel & 0x0380) >> 5)) << 6; - b = ((pixel & 0x001c) | ((pixel & 0x001f) << 5)) >> 2; - return (a | r | g | b); -} - -static uint32_t -IcFetch_x1r5g5b5 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint16_t *) line)[offset >> 4]; - uint32_t r,g,b; - - r = ((pixel & 0x7c00) | ((pixel & 0x7000) >> 5)) << 9; - g = ((pixel & 0x03e0) | ((pixel & 0x0380) >> 5)) << 6; - b = ((pixel & 0x001c) | ((pixel & 0x001f) << 5)) >> 2; - return (0xff000000 | r | g | b); -} - -static uint32_t -IcFetch_a1b5g5r5 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint16_t *) line)[offset >> 4]; - uint32_t a,r,g,b; - - a = (uint32_t) ((uint8_t) (0 - ((pixel & 0x8000) >> 15))) << 24; - b = ((pixel & 0x7c00) | ((pixel & 0x7000) >> 5)) >> 7; - g = ((pixel & 0x03e0) | ((pixel & 0x0380) >> 5)) << 6; - r = ((pixel & 0x001c) | ((pixel & 0x001f) << 5)) << 14; - return (a | r | g | b); -} - -static uint32_t -IcFetch_x1b5g5r5 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint16_t *) line)[offset >> 4]; - uint32_t r,g,b; - - b = ((pixel & 0x7c00) | ((pixel & 0x7000) >> 5)) >> 7; - g = ((pixel & 0x03e0) | ((pixel & 0x0380) >> 5)) << 6; - r = ((pixel & 0x001c) | ((pixel & 0x001f) << 5)) << 14; - return (0xff000000 | r | g | b); -} - -static uint32_t -IcFetch_a4r4g4b4 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint16_t *) line)[offset >> 4]; - uint32_t a,r,g,b; - - a = ((pixel & 0xf000) | ((pixel & 0xf000) >> 4)) << 16; - r = ((pixel & 0x0f00) | ((pixel & 0x0f00) >> 4)) << 12; - g = ((pixel & 0x00f0) | ((pixel & 0x00f0) >> 4)) << 8; - b = ((pixel & 0x000f) | ((pixel & 0x000f) << 4)); - return (a | r | g | b); -} - -static uint32_t -IcFetch_x4r4g4b4 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint16_t *) line)[offset >> 4]; - uint32_t r,g,b; - - r = ((pixel & 0x0f00) | ((pixel & 0x0f00) >> 4)) << 12; - g = ((pixel & 0x00f0) | ((pixel & 0x00f0) >> 4)) << 8; - b = ((pixel & 0x000f) | ((pixel & 0x000f) << 4)); - return (0xff000000 | r | g | b); -} - -static uint32_t -IcFetch_a4b4g4r4 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint16_t *) line)[offset >> 4]; - uint32_t a,r,g,b; - - a = ((pixel & 0xf000) | ((pixel & 0xf000) >> 4)) << 16; - b = ((pixel & 0x0f00) | ((pixel & 0x0f00) >> 4)) << 12; - g = ((pixel & 0x00f0) | ((pixel & 0x00f0) >> 4)) << 8; - r = ((pixel & 0x000f) | ((pixel & 0x000f) << 4)); - return (a | r | g | b); -} - -static uint32_t -IcFetch_x4b4g4r4 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint16_t *) line)[offset >> 4]; - uint32_t r,g,b; - - b = ((pixel & 0x0f00) | ((pixel & 0x0f00) >> 4)) << 12; - g = ((pixel & 0x00f0) | ((pixel & 0x00f0) >> 4)) << 8; - r = ((pixel & 0x000f) | ((pixel & 0x000f) << 4)); - return (0xff000000 | r | g | b); -} - -static uint32_t -IcFetch_a8 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint8_t *) line)[offset>>3]; - - return pixel << 24; -} - -static uint32_t -IcFetcha_a8 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint8_t *) line)[offset>>3]; - - pixel |= pixel << 8; - pixel |= pixel << 16; - return pixel; -} - -static uint32_t -IcFetch_r3g3b2 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint8_t *) line)[offset>>3]; - uint32_t r,g,b; - - r = ((pixel & 0xe0) | ((pixel & 0xe0) >> 3) | ((pixel & 0xc0) >> 6)) << 16; - g = ((pixel & 0x1c) | ((pixel & 0x18) >> 3) | ((pixel & 0x1c) << 3)) << 8; - b = (((pixel & 0x03) ) | - ((pixel & 0x03) << 2) | - ((pixel & 0x03) << 4) | - ((pixel & 0x03) << 6)); - return (0xff000000 | r | g | b); -} - -static uint32_t -IcFetch_b2g3r3 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint8_t *) line)[offset>>3]; - uint32_t r,g,b; - - b = (((pixel & 0xc0) ) | - ((pixel & 0xc0) >> 2) | - ((pixel & 0xc0) >> 4) | - ((pixel & 0xc0) >> 6)); - g = ((pixel & 0x38) | ((pixel & 0x38) >> 3) | ((pixel & 0x30) << 2)) << 8; - r = (((pixel & 0x07) ) | - ((pixel & 0x07) << 3) | - ((pixel & 0x06) << 6)) << 16; - return (0xff000000 | r | g | b); -} - -static uint32_t -IcFetch_a2r2g2b2 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint8_t *) line)[offset>>3]; - uint32_t a,r,g,b; - - a = ((pixel & 0xc0) * 0x55) << 18; - r = ((pixel & 0x30) * 0x55) << 12; - g = ((pixel & 0x0c) * 0x55) << 6; - b = ((pixel & 0x03) * 0x55); - return a|r|g|b; -} - -#define Fetch8(l,o) (((uint8_t *) (l))[(o) >> 3]) -#if IMAGE_BYTE_ORDER == MSBFirst -#define Fetch4(l,o) ((o) & 2 ? Fetch8(l,o) & 0xf : Fetch8(l,o) >> 4) -#else -#define Fetch4(l,o) ((o) & 2 ? Fetch8(l,o) >> 4 : Fetch8(l,o) & 0xf) -#endif - -static uint32_t -IcFetch_a4 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = Fetch4(line, offset); - - pixel |= pixel << 4; - return pixel << 24; -} - -static uint32_t -IcFetcha_a4 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = Fetch4(line, offset); - - pixel |= pixel << 4; - pixel |= pixel << 8; - pixel |= pixel << 16; - return pixel; -} - -static uint32_t -IcFetch_r1g2b1 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = Fetch4(line, offset); - uint32_t r,g,b; - - r = ((pixel & 0x8) * 0xff) << 13; - g = ((pixel & 0x6) * 0x55) << 7; - b = ((pixel & 0x1) * 0xff); - return 0xff000000|r|g|b; -} - -static uint32_t -IcFetch_b1g2r1 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = Fetch4(line, offset); - uint32_t r,g,b; - - b = ((pixel & 0x8) * 0xff) >> 3; - g = ((pixel & 0x6) * 0x55) << 7; - r = ((pixel & 0x1) * 0xff) << 16; - return 0xff000000|r|g|b; -} - -static uint32_t -IcFetch_a1r1g1b1 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = Fetch4(line, offset); - uint32_t a,r,g,b; - - a = ((pixel & 0x8) * 0xff) << 21; - r = ((pixel & 0x4) * 0xff) << 14; - g = ((pixel & 0x2) * 0xff) << 7; - b = ((pixel & 0x1) * 0xff); - return a|r|g|b; -} - -static uint32_t -IcFetch_a1b1g1r1 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = Fetch4(line, offset); - uint32_t a,r,g,b; - - a = ((pixel & 0x8) * 0xff) << 21; - r = ((pixel & 0x4) * 0xff) >> 3; - g = ((pixel & 0x2) * 0xff) << 7; - b = ((pixel & 0x1) * 0xff) << 16; - return a|r|g|b; -} - -static uint32_t -IcFetcha_a1 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint32_t *)line)[offset >> 5]; - uint32_t a; -#if BITMAP_BIT_ORDER == MSBFirst - a = pixel >> (0x1f - (offset & 0x1f)); -#else - a = pixel >> (offset & 0x1f); -#endif - a = a & 1; - a |= a << 1; - a |= a << 2; - a |= a << 4; - a |= a << 8; - a |= a << 16; - return a; -} - -static uint32_t -IcFetch_a1 (pixman_compositeOperand *op) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel = ((uint32_t *)line)[offset >> 5]; - uint32_t a; -#if BITMAP_BIT_ORDER == MSBFirst - a = pixel >> (0x1f - (offset & 0x1f)); -#else - a = pixel >> (offset & 0x1f); -#endif - a = a & 1; - a |= a << 1; - a |= a << 2; - a |= a << 4; - return a << 24; -} - -/* - * All the store functions - */ - -#define Splita(v) uint32_t a = ((v) >> 24), r = ((v) >> 16) & 0xff, g = ((v) >> 8) & 0xff, b = (v) & 0xff -#define Split(v) uint32_t r = ((v) >> 16) & 0xff, g = ((v) >> 8) & 0xff, b = (v) & 0xff - -static void -IcStore_a8r8g8b8 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - ((uint32_t *)line)[offset >> 5] = value; -} - -static void -IcStore_x8r8g8b8 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - ((uint32_t *)line)[offset >> 5] = value & 0xffffff; -} - -static void -IcStore_a8b8g8r8 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - Splita(value); - ((uint32_t *)line)[offset >> 5] = a << 24 | b << 16 | g << 8 | r; -} - -static void -IcStore_x8b8g8r8 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - Split(value); - ((uint32_t *)line)[offset >> 5] = b << 16 | g << 8 | r; -} - -static void -IcStore_r8g8b8 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint8_t *pixel = ((uint8_t *) line) + (offset >> 3); - Split(value); -#if IMAGE_BYTE_ORDER == MSBFirst - pixel[0] = r; - pixel[1] = g; - pixel[2] = b; -#else - pixel[0] = b; - pixel[1] = g; - pixel[2] = r; -#endif -} - -static void -IcStore_b8g8r8 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint8_t *pixel = ((uint8_t *) line) + (offset >> 3); - Split(value); -#if IMAGE_BYTE_ORDER == MSBFirst - pixel[0] = b; - pixel[1] = g; - pixel[2] = r; -#else - pixel[0] = r; - pixel[1] = g; - pixel[2] = b; -#endif -} - -static void -IcStore_r5g6b5 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint16_t *pixel = ((uint16_t *) line) + (offset >> 4); - Split(value); - *pixel = (((r << 8) & 0xf800) | - ((g << 3) & 0x07e0) | - ((b >> 3) )); -} - -static void -IcStore_b5g6r5 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint16_t *pixel = ((uint16_t *) line) + (offset >> 4); - Split(value); - *pixel = (((b << 8) & 0xf800) | - ((g << 3) & 0x07e0) | - ((r >> 3) )); -} - -static void -IcStore_a1r5g5b5 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint16_t *pixel = ((uint16_t *) line) + (offset >> 4); - Splita(value); - *pixel = (((a << 8) & 0x8000) | - ((r << 7) & 0x7c00) | - ((g << 2) & 0x03e0) | - ((b >> 3) )); -} - -static void -IcStore_x1r5g5b5 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint16_t *pixel = ((uint16_t *) line) + (offset >> 4); - Split(value); - *pixel = (((r << 7) & 0x7c00) | - ((g << 2) & 0x03e0) | - ((b >> 3) )); -} - -static void -IcStore_a1b5g5r5 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint16_t *pixel = ((uint16_t *) line) + (offset >> 4); - Splita(value); - *pixel = (((a << 8) & 0x8000) | - ((b << 7) & 0x7c00) | - ((g << 2) & 0x03e0) | - ((r >> 3) )); -} - -static void -IcStore_x1b5g5r5 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint16_t *pixel = ((uint16_t *) line) + (offset >> 4); - Split(value); - *pixel = (((b << 7) & 0x7c00) | - ((g << 2) & 0x03e0) | - ((r >> 3) )); -} - -static void -IcStore_a4r4g4b4 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint16_t *pixel = ((uint16_t *) line) + (offset >> 4); - Splita(value); - *pixel = (((a << 8) & 0xf000) | - ((r << 4) & 0x0f00) | - ((g ) & 0x00f0) | - ((b >> 4) )); -} - -static void -IcStore_x4r4g4b4 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint16_t *pixel = ((uint16_t *) line) + (offset >> 4); - Split(value); - *pixel = (((r << 4) & 0x0f00) | - ((g ) & 0x00f0) | - ((b >> 4) )); -} - -static void -IcStore_a4b4g4r4 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint16_t *pixel = ((uint16_t *) line) + (offset >> 4); - Splita(value); - *pixel = (((a << 8) & 0xf000) | - ((b << 4) & 0x0f00) | - ((g ) & 0x00f0) | - ((r >> 4) )); -} - -static void -IcStore_x4b4g4r4 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint16_t *pixel = ((uint16_t *) line) + (offset >> 4); - Split(value); - *pixel = (((b << 4) & 0x0f00) | - ((g ) & 0x00f0) | - ((r >> 4) )); -} - -static void -IcStore_a8 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint8_t *pixel = ((uint8_t *) line) + (offset >> 3); - *pixel = value >> 24; -} - -static void -IcStore_r3g3b2 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint8_t *pixel = ((uint8_t *) line) + (offset >> 3); - Split(value); - *pixel = (((r ) & 0xe0) | - ((g >> 3) & 0x1c) | - ((b >> 6) )); -} - -static void -IcStore_b2g3r3 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint8_t *pixel = ((uint8_t *) line) + (offset >> 3); - Split(value); - *pixel = (((b ) & 0xe0) | - ((g >> 3) & 0x1c) | - ((r >> 6) )); -} - -static void -IcStore_a2r2g2b2 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint8_t *pixel = ((uint8_t *) line) + (offset >> 3); - Splita(value); - *pixel = (((a ) & 0xc0) | - ((r >> 2) & 0x30) | - ((g >> 4) & 0x0c) | - ((b >> 6) )); -} - -#define Store8(l,o,v) (((uint8_t *) l)[(o) >> 3] = (v)) -#if IMAGE_BYTE_ORDER == MSBFirst -#define Store4(l,o,v) Store8(l,o,((o) & 4 ? \ - (Fetch8(l,o) & 0xf0) | (v) : \ - (Fetch8(l,o) & 0x0f) | ((v) << 4))) -#else -#define Store4(l,o,v) Store8(l,o,((o) & 4 ? \ - (Fetch8(l,o) & 0x0f) | ((v) << 4) : \ - (Fetch8(l,o) & 0xf0) | (v))) -#endif - -static void -IcStore_a4 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - Store4(line,offset,value>>28); -} - -static void -IcStore_r1g2b1 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel; - - Split(value); - pixel = (((r >> 4) & 0x8) | - ((g >> 5) & 0x6) | - ((b >> 7) )); - Store4(line,offset,pixel); -} - -static void -IcStore_b1g2r1 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel; - - Split(value); - pixel = (((b >> 4) & 0x8) | - ((g >> 5) & 0x6) | - ((r >> 7) )); - Store4(line,offset,pixel); -} - -static void -IcStore_a1r1g1b1 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel; - Splita(value); - pixel = (((a >> 4) & 0x8) | - ((r >> 5) & 0x4) | - ((g >> 6) & 0x2) | - ((b >> 7) )); - Store4(line,offset,pixel); -} - -static void -IcStore_a1b1g1r1 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t pixel; - Splita(value); - pixel = (((a >> 4) & 0x8) | - ((b >> 5) & 0x4) | - ((g >> 6) & 0x2) | - ((r >> 7) )); - Store4(line,offset,pixel); -} - -static void -IcStore_a1 (pixman_compositeOperand *op, uint32_t value) -{ - pixman_bits_t *line = op->u.drawable.line; uint32_t offset = op->u.drawable.offset; - uint32_t *pixel = ((uint32_t *) line) + (offset >> 5); - uint32_t mask = IcStipMask(offset & 0x1f, 1); - - value = value & 0x80000000 ? mask : 0; - *pixel = (*pixel & ~mask) | value; -} - -static uint32_t -IcFetch_external (pixman_compositeOperand *op) -{ - uint32_t rgb = (*op[1].fetch) (&op[1]); - uint32_t a = (*op[2].fetch) (&op[2]); - - return (rgb & 0xffffff) | (a & 0xff000000); -} - - -static uint32_t -IcFetcha_external (pixman_compositeOperand *op) -{ - return (*op[2].fetch) (&op[2]); -} - -static void -IcStore_external (pixman_compositeOperand *op, uint32_t value) -{ - (*op[1].store) (&op[1], value | 0xff000000); - (*op[2].store) (&op[2], value & 0xff000000); -} - -static uint32_t -IcFetch_transform (pixman_compositeOperand *op) -{ - pixman_vector_t v; - int x, y; - int minx, maxx, miny, maxy; - uint32_t rtot, gtot, btot, atot; - uint32_t xerr, yerr; - uint32_t bits; - pixman_box16_t box; - - v.vector[0] = IntToxFixed(op->u.transform.x); - v.vector[1] = IntToxFixed(op->u.transform.y); - v.vector[2] = xFixed1; - if (!pixman_transform_point (op->u.transform.transform, &v)) - return 0; - switch (op->u.transform.filter) { - case PIXMAN_FILTER_FAST: - case PIXMAN_FILTER_NEAREST: - y = xFixedToInt (v.vector[1]) + op->u.transform.top_y; - x = xFixedToInt (v.vector[0]) + op->u.transform.left_x; - if (op->u.transform.repeat) - { - y = MOD (y, op->u.transform.height); - x = MOD (x, op->u.transform.width); - } - if (pixman_region_contains_point (op->clip, x, y, &box)) - { - (*op[1].set) (&op[1], x, y); - bits = (*op[1].fetch) (&op[1]); - } - else - bits = 0; - break; - case PIXMAN_FILTER_GOOD: - case PIXMAN_FILTER_BEST: - case PIXMAN_FILTER_BILINEAR: - rtot = gtot = btot = atot = 0; - miny = xFixedToInt (v.vector[1]) + op->u.transform.top_y; - maxy = xFixedToInt (xFixedCeil (v.vector[1])) + op->u.transform.top_y; - - minx = xFixedToInt (v.vector[0]) + op->u.transform.left_x; - maxx = xFixedToInt (xFixedCeil (v.vector[0])) + op->u.transform.left_x; - - yerr = xFixed1 - xFixedFrac (v.vector[1]); - for (y = miny; y <= maxy; y++) - { - uint32_t lrtot = 0, lgtot = 0, lbtot = 0, latot = 0; - int tx, ty; - - if (op->u.transform.repeat) - ty = MOD (y, op->u.transform.height); - else - ty = y; - - xerr = xFixed1 - xFixedFrac (v.vector[0]); - for (x = minx; x <= maxx; x++) - { - if (op->u.transform.repeat) - tx = MOD (x, op->u.transform.width); - else - tx = x; - - if (pixman_region_contains_point (op->clip, tx, ty, &box)) - { - (*op[1].set) (&op[1], tx, ty); - bits = (*op[1].fetch) (&op[1]); - { - Splita(bits); - lrtot += r * xerr; - lgtot += g * xerr; - lbtot += b * xerr; - latot += a * xerr; - } - } - xerr = xFixed1 - xerr; - } - rtot += (lrtot >> 10) * yerr; - gtot += (lgtot >> 10) * yerr; - btot += (lbtot >> 10) * yerr; - atot += (latot >> 10) * yerr; - yerr = xFixed1 - yerr; - } - if ((atot >>= 22) > 0xff) atot = 0xff; - if ((rtot >>= 22) > 0xff) rtot = 0xff; - if ((gtot >>= 22) > 0xff) gtot = 0xff; - if ((btot >>= 22) > 0xff) btot = 0xff; - bits = ((atot << 24) | - (rtot << 16) | - (gtot << 8) | - (btot )); - break; - default: - bits = 0; - break; - } - return bits; -} - -static uint32_t -IcFetcha_transform (pixman_compositeOperand *op) -{ - pixman_vector_t v; - int x, y; - int minx, maxx, miny, maxy; - uint32_t rtot, gtot, btot, atot; - uint32_t xerr, yerr; - uint32_t bits; - pixman_box16_t box; - - v.vector[0] = IntToxFixed(op->u.transform.x); - v.vector[1] = IntToxFixed(op->u.transform.y); - v.vector[2] = xFixed1; - if (!pixman_transform_point (op->u.transform.transform, &v)) - return 0; - switch (op->u.transform.filter) { - case PIXMAN_FILTER_FAST: - case PIXMAN_FILTER_NEAREST: - y = xFixedToInt (v.vector[1]) + op->u.transform.left_x; - x = xFixedToInt (v.vector[0]) + op->u.transform.top_y; - if (op->u.transform.repeat) - { - y = MOD (y, op->u.transform.height); - x = MOD (x, op->u.transform.width); - } - if (pixman_region_contains_point (op->clip, x, y, &box)) - { - (*op[1].set) (&op[1], x, y); - bits = (*op[1].fetcha) (&op[1]); - } - else - bits = 0; - break; - case PIXMAN_FILTER_GOOD: - case PIXMAN_FILTER_BEST: - case PIXMAN_FILTER_BILINEAR: - rtot = gtot = btot = atot = 0; - - miny = xFixedToInt (v.vector[1]) + op->u.transform.top_y; - maxy = xFixedToInt (xFixedCeil (v.vector[1])) + op->u.transform.top_y; - - minx = xFixedToInt (v.vector[0]) + op->u.transform.left_x; - maxx = xFixedToInt (xFixedCeil (v.vector[0])) + op->u.transform.left_x; - - yerr = xFixed1 - xFixedFrac (v.vector[1]); - for (y = miny; y <= maxy; y++) - { - uint32_t lrtot = 0, lgtot = 0, lbtot = 0, latot = 0; - int tx, ty; - - if (op->u.transform.repeat) - ty = MOD (y, op->u.transform.height); - else - ty = y; - - xerr = xFixed1 - xFixedFrac (v.vector[0]); - for (x = minx; x <= maxx; x++) - { - if (op->u.transform.repeat) - tx = MOD (x, op->u.transform.width); - else - tx = x; - - if (pixman_region_contains_point (op->clip, tx, ty, &box)) - { - (*op[1].set) (&op[1], tx, ty); - bits = (*op[1].fetcha) (&op[1]); - { - Splita(bits); - lrtot += r * xerr; - lgtot += g * xerr; - lbtot += b * xerr; - latot += a * xerr; - } - } - x++; - xerr = xFixed1 - xerr; - } - rtot += (lrtot >> 10) * yerr; - gtot += (lgtot >> 10) * yerr; - btot += (lbtot >> 10) * yerr; - atot += (latot >> 10) * yerr; - y++; - yerr = xFixed1 - yerr; - } - if ((atot >>= 22) > 0xff) atot = 0xff; - if ((rtot >>= 22) > 0xff) rtot = 0xff; - if ((gtot >>= 22) > 0xff) gtot = 0xff; - if ((btot >>= 22) > 0xff) btot = 0xff; - bits = ((atot << 24) | - (rtot << 16) | - (gtot << 8) | - (btot )); - break; - default: - bits = 0; - break; - } - return bits; -} - -static IcAccessMap const icAccessMap[] = { - /* 32bpp formats */ - { PICT_a8r8g8b8, IcFetch_a8r8g8b8, IcFetch_a8r8g8b8, IcStore_a8r8g8b8 }, - { PICT_x8r8g8b8, IcFetch_x8r8g8b8, IcFetch_x8r8g8b8, IcStore_x8r8g8b8 }, - { PICT_a8b8g8r8, IcFetch_a8b8g8r8, IcFetch_a8b8g8r8, IcStore_a8b8g8r8 }, - { PICT_x8b8g8r8, IcFetch_x8b8g8r8, IcFetch_x8b8g8r8, IcStore_x8b8g8r8 }, - - /* 24bpp formats */ - { PICT_r8g8b8, IcFetch_r8g8b8, IcFetch_r8g8b8, IcStore_r8g8b8 }, - { PICT_b8g8r8, IcFetch_b8g8r8, IcFetch_b8g8r8, IcStore_b8g8r8 }, - - /* 16bpp formats */ - { PICT_r5g6b5, IcFetch_r5g6b5, IcFetch_r5g6b5, IcStore_r5g6b5 }, - { PICT_b5g6r5, IcFetch_b5g6r5, IcFetch_b5g6r5, IcStore_b5g6r5 }, - - { PICT_a1r5g5b5, IcFetch_a1r5g5b5, IcFetch_a1r5g5b5, IcStore_a1r5g5b5 }, - { PICT_x1r5g5b5, IcFetch_x1r5g5b5, IcFetch_x1r5g5b5, IcStore_x1r5g5b5 }, - { PICT_a1b5g5r5, IcFetch_a1b5g5r5, IcFetch_a1b5g5r5, IcStore_a1b5g5r5 }, - { PICT_x1b5g5r5, IcFetch_x1b5g5r5, IcFetch_x1b5g5r5, IcStore_x1b5g5r5 }, - { PICT_a4r4g4b4, IcFetch_a4r4g4b4, IcFetch_a4r4g4b4, IcStore_a4r4g4b4 }, - { PICT_x4r4g4b4, IcFetch_x4r4g4b4, IcFetch_x4r4g4b4, IcStore_x4r4g4b4 }, - { PICT_a4b4g4r4, IcFetch_a4b4g4r4, IcFetch_a4b4g4r4, IcStore_a4b4g4r4 }, - { PICT_x4b4g4r4, IcFetch_x4b4g4r4, IcFetch_x4b4g4r4, IcStore_x4b4g4r4 }, - - /* 8bpp formats */ - { PICT_a8, IcFetch_a8, IcFetcha_a8, IcStore_a8 }, - { PICT_r3g3b2, IcFetch_r3g3b2, IcFetch_r3g3b2, IcStore_r3g3b2 }, - { PICT_b2g3r3, IcFetch_b2g3r3, IcFetch_b2g3r3, IcStore_b2g3r3 }, - { PICT_a2r2g2b2, IcFetch_a2r2g2b2, IcFetch_a2r2g2b2, IcStore_a2r2g2b2 }, - - /* 4bpp formats */ - { PICT_a4, IcFetch_a4, IcFetcha_a4, IcStore_a4 }, - { PICT_r1g2b1, IcFetch_r1g2b1, IcFetch_r1g2b1, IcStore_r1g2b1 }, - { PICT_b1g2r1, IcFetch_b1g2r1, IcFetch_b1g2r1, IcStore_b1g2r1 }, - { PICT_a1r1g1b1, IcFetch_a1r1g1b1, IcFetch_a1r1g1b1, IcStore_a1r1g1b1 }, - { PICT_a1b1g1r1, IcFetch_a1b1g1r1, IcFetch_a1b1g1r1, IcStore_a1b1g1r1 }, - - /* 1bpp formats */ - { PICT_a1, IcFetch_a1, IcFetcha_a1, IcStore_a1 }, -}; -#define NumAccessMap (sizeof icAccessMap / sizeof icAccessMap[0]) - -static void -IcStepOver (pixman_compositeOperand *op) -{ - op->u.drawable.offset += op->u.drawable.bpp; -} - -static void -IcStepDown (pixman_compositeOperand *op) -{ - op->u.drawable.line += op->u.drawable.stride; - op->u.drawable.offset = op->u.drawable.start_offset; -} - -static void -IcSet (pixman_compositeOperand *op, int x, int y) -{ - op->u.drawable.line = op->u.drawable.top_line + y * op->u.drawable.stride; - op->u.drawable.offset = op->u.drawable.left_offset + x * op->u.drawable.bpp; -} - -static void -IcStepOver_external (pixman_compositeOperand *op) -{ - (*op[1].over) (&op[1]); - (*op[2].over) (&op[2]); -} - -static void -IcStepDown_external (pixman_compositeOperand *op) -{ - (*op[1].down) (&op[1]); - (*op[2].down) (&op[2]); -} - -static void -IcSet_external (pixman_compositeOperand *op, int x, int y) -{ - (*op[1].set) (&op[1], x, y); - (*op[2].set) (&op[2], - x - op->u.external.alpha_dx, - y - op->u.external.alpha_dy); -} - -static void -IcStepOver_transform (pixman_compositeOperand *op) -{ - op->u.transform.x++; -} - -static void -IcStepDown_transform (pixman_compositeOperand *op) -{ - op->u.transform.y++; - op->u.transform.x = op->u.transform.start_x; -} - -static void -IcSet_transform (pixman_compositeOperand *op, int x, int y) -{ - op->u.transform.x = x - op->u.transform.left_x; - op->u.transform.y = y - op->u.transform.top_y; -} - - -int -IcBuildCompositeOperand (pixman_image_t *image, - pixman_compositeOperand op[4], - int16_t x, - int16_t y, - int transform, - int alpha) -{ - /* Check for transform */ - if (transform && image->transform) - { - if (!IcBuildCompositeOperand (image, &op[1], 0, 0, 0, alpha)) - return 0; - - op->u.transform.top_y = image->pixels->y; - op->u.transform.left_x = image->pixels->x; - - op->u.transform.start_x = x - op->u.transform.left_x; - op->u.transform.x = op->u.transform.start_x; - op->u.transform.y = y - op->u.transform.top_y; - op->u.transform.transform = image->transform; - op->u.transform.filter = image->filter; - op->u.transform.repeat = image->repeat; - op->u.transform.width = image->pixels->width; - op->u.transform.height = image->pixels->height; - - op->fetch = IcFetch_transform; - op->fetcha = IcFetcha_transform; - op->store = 0; - op->over = IcStepOver_transform; - op->down = IcStepDown_transform; - op->set = IcSet_transform; - - op->clip = op[1].clip; - - return 1; - } - /* Check for external alpha */ - else if (alpha && image->alphaMap) - { - if (!IcBuildCompositeOperand (image, &op[1], x, y, 0, 0)) - return 0; - if (!IcBuildCompositeOperand (image->alphaMap, &op[2], - x - image->alphaOrigin.x, - y - image->alphaOrigin.y, - 0, 0)) - return 0; - op->u.external.alpha_dx = image->alphaOrigin.x; - op->u.external.alpha_dy = image->alphaOrigin.y; - - op->fetch = IcFetch_external; - op->fetcha = IcFetcha_external; - op->store = IcStore_external; - op->over = IcStepOver_external; - op->down = IcStepDown_external; - op->set = IcSet_external; - - op->clip = op[1].clip; - - return 1; - } - /* Build simple operand */ - else - { - int i; - int xoff, yoff; - - for (i = 0; i < NumAccessMap; i++) - if (icAccessMap[i].format_code == image->format_code) - { - pixman_bits_t *bits; - IcStride stride; - int bpp; - - op->fetch = icAccessMap[i].fetch; - op->fetcha = icAccessMap[i].fetcha; - op->store = icAccessMap[i].store; - op->over = IcStepOver; - op->down = IcStepDown; - op->set = IcSet; - - op->clip = image->pCompositeClip; - - IcGetPixels (image->pixels, bits, stride, bpp, - xoff, yoff); - if (image->repeat && image->pixels->width == 1 && - image->pixels->height == 1) - { - bpp = 0; - stride = 0; - } - /* - * Coordinates of upper left corner of drawable - */ - op->u.drawable.top_line = bits + yoff * stride; - op->u.drawable.left_offset = xoff * bpp; - - /* - * Starting position within drawable - */ - op->u.drawable.start_offset = op->u.drawable.left_offset + x * bpp; - op->u.drawable.line = op->u.drawable.top_line + y * stride; - op->u.drawable.offset = op->u.drawable.start_offset; - - op->u.drawable.stride = stride; - op->u.drawable.bpp = bpp; - return 1; - } - return 0; - } -} - -void -pixman_compositeGeneral (pixman_operator_t op, - pixman_image_t *iSrc, - pixman_image_t *iMask, - pixman_image_t *iDst, - int16_t xSrc, - int16_t ySrc, - int16_t xMask, - int16_t yMask, - int16_t xDst, - int16_t yDst, - uint16_t width, - uint16_t height) -{ - pixman_compositeOperand src[4],msk[4],dst[4],*pmsk; - pixman_compositeOperand *srcPict, *srcAlpha; - pixman_compositeOperand *dstPict, *dstAlpha; - pixman_compositeOperand *mskPict = 0, *mskAlpha = 0; - IcCombineFunc f; - int w; - - if (!IcBuildCompositeOperand (iSrc, src, xSrc, ySrc, 1, 1)) - return; - if (!IcBuildCompositeOperand (iDst, dst, xDst, yDst, 0, 1)) - return; - if (iSrc->alphaMap) - { - srcPict = &src[1]; - srcAlpha = &src[2]; - } - else - { - srcPict = &src[0]; - srcAlpha = 0; - } - if (iDst->alphaMap) - { - dstPict = &dst[1]; - dstAlpha = &dst[2]; - } - else - { - dstPict = &dst[0]; - dstAlpha = 0; - } - f = IcCombineFuncU[op]; - if (iMask) - { - if (!IcBuildCompositeOperand (iMask, msk, xMask, yMask, 1, 1)) - return; - pmsk = msk; - if (iMask->componentAlpha) - f = IcCombineFuncC[op]; - if (iMask->alphaMap) - { - mskPict = &msk[1]; - mskAlpha = &msk[2]; - } - else - { - mskPict = &msk[0]; - mskAlpha = 0; - } - } - else - pmsk = 0; - while (height--) - { - w = width; - - while (w--) - { - (*f) (src, pmsk, dst); - (*src->over) (src); - (*dst->over) (dst); - if (pmsk) - (*pmsk->over) (pmsk); - } - (*src->down) (src); - (*dst->down) (dst); - if (pmsk) - (*pmsk->down) (pmsk); - } -} - diff --git a/gfx/cairo/libpixman/src/icformat.c b/gfx/cairo/libpixman/src/icformat.c index 8e93ca0b42e7..37d9bc549670 100644 --- a/gfx/cairo/libpixman/src/icformat.c +++ b/gfx/cairo/libpixman/src/icformat.c @@ -76,10 +76,10 @@ pixman_format_create_masks (int bpp, type = PICT_TYPE_ABGR; format_code = PICT_FORMAT (bpp, type, - _IcOnes (alpha_mask), - _IcOnes (red_mask), - _IcOnes (green_mask), - _IcOnes (blue_mask)); + _FbOnes (alpha_mask), + _FbOnes (red_mask), + _FbOnes (green_mask), + _FbOnes (blue_mask)); format = malloc (sizeof (pixman_format_t)); if (format == NULL) @@ -148,7 +148,7 @@ pixman_format_init (pixman_format_t *format, int format_code) break; } - format->depth = _IcOnes ((format->alphaMask << format->alpha) | + format->depth = _FbOnes ((format->alphaMask << format->alpha) | (format->redMask << format->red) | (format->blueMask << format->blue) | (format->greenMask << format->green)); diff --git a/gfx/cairo/libpixman/src/icimage.c b/gfx/cairo/libpixman/src/icimage.c index aefd5ba4b5ea..86db4416b0c4 100644 --- a/gfx/cairo/libpixman/src/icimage.c +++ b/gfx/cairo/libpixman/src/icimage.c @@ -21,7 +21,7 @@ * Author: Keith Packard, SuSE, Inc. */ -#include "icint.h" +#include "pixman-xserver-compat.h" pixman_image_t * pixman_image_create (pixman_format_t *format, @@ -29,15 +29,15 @@ pixman_image_create (pixman_format_t *format, int height) { pixman_image_t *image; - IcPixels *pixels; + FbPixels *pixels; - pixels = IcPixelsCreate (width, height, format->depth); + pixels = FbPixelsCreate (width, height, format->depth); if (pixels == NULL) return NULL; image = pixman_image_createForPixels (pixels, format); if (image == NULL) { - IcPixelsDestroy (pixels); + FbPixelsDestroy (pixels); return NULL; } @@ -48,18 +48,18 @@ pixman_image_create (pixman_format_t *format, slim_hidden_def(pixman_image_create); pixman_image_t * -pixman_image_create_for_data (pixman_bits_t *data, pixman_format_t *format, int width, int height, int bpp, int stride) +pixman_image_create_for_data (FbBits *data, pixman_format_t *format, int width, int height, int bpp, int stride) { pixman_image_t *image; - IcPixels *pixels; + FbPixels *pixels; - pixels = IcPixelsCreateForData (data, width, height, format->depth, bpp, stride); + pixels = FbPixelsCreateForData (data, width, height, format->depth, bpp, stride); if (pixels == NULL) return NULL; image = pixman_image_createForPixels (pixels, format); if (image == NULL) { - IcPixelsDestroy (pixels); + FbPixelsDestroy (pixels); return NULL; } @@ -69,7 +69,7 @@ pixman_image_create_for_data (pixman_bits_t *data, pixman_format_t *format, int } pixman_image_t * -pixman_image_createForPixels (IcPixels *pixels, +pixman_image_createForPixels (FbPixels *pixels, pixman_format_t *format) { pixman_image_t *image; @@ -110,10 +110,15 @@ pixman_image_init (pixman_image_t *image) image->subWindowMode = ClipByChildren; image->polyEdge = PolyEdgeSharp; image->polyMode = PolyModePrecise; - /* XXX: In the server this was 0. Why? */ - image->freeCompClip = 1; + /* + * In the server this was 0 because the composite clip list + * can be referenced from a window (and often is) + */ + image->freeCompClip = 0; + image->freeSourceClip = 0; image->clientClipType = CT_NONE; image->componentAlpha = 0; + image->compositeClipSource = 0; image->alphaMap = 0; image->alphaOrigin.x = 0; @@ -133,7 +138,13 @@ pixman_image_init (pixman_image_t *image) image->pCompositeClip = pixman_region_create(); pixman_region_union_rect (image->pCompositeClip, image->pCompositeClip, 0, 0, image->pixels->width, image->pixels->height); + image->freeCompClip = 1; + image->pSourceClip = pixman_region_create (); + pixman_region_union_rect (image->pSourceClip, image->pSourceClip, + 0, 0, image->pixels->width, image->pixels->height); + image->freeSourceClip = 1; + image->transform = NULL; image->filter = PIXMAN_FILTER_NEAREST; @@ -146,7 +157,7 @@ pixman_image_init (pixman_image_t *image) void pixman_image_set_component_alpha (pixman_image_t *image, - int component_alpha) + int component_alpha) { if (image) image->componentAlpha = component_alpha; @@ -234,7 +245,7 @@ pixman_image_get_format (pixman_image_t *image) return &image->image_format; } -pixman_bits_t * +FbBits * pixman_image_get_data (pixman_image_t *image) { return image->pixels->data; @@ -243,13 +254,20 @@ pixman_image_get_data (pixman_image_t *image) void pixman_image_destroy (pixman_image_t *image) { + pixman_image_destroyClip (image); + if (image->freeCompClip) { pixman_region_destroy (image->pCompositeClip); image->pCompositeClip = NULL; } + + if (image->freeSourceClip) { + pixman_region_destroy (image->pSourceClip); + image->pSourceClip = NULL; + } if (image->owns_pixels) { - IcPixelsDestroy (image->pixels); + FbPixelsDestroy (image->pixels); image->pixels = NULL; } @@ -281,7 +299,7 @@ pixman_image_destroyClip (pixman_image_t *image) int pixman_image_set_clip_region (pixman_image_t *image, - pixman_region16_t *region) + pixman_region16_t *region) { pixman_image_destroyClip (image); if (region) { @@ -290,9 +308,12 @@ pixman_image_set_clip_region (pixman_image_t *image, image->clientClipType = CT_REGION; } + if (image->freeCompClip) + pixman_region_destroy (image->pCompositeClip); image->pCompositeClip = pixman_region_create(); pixman_region_union_rect (image->pCompositeClip, image->pCompositeClip, 0, 0, image->pixels->width, image->pixels->height); + image->freeCompClip = 1; if (region) { pixman_region_translate (image->pCompositeClip, - image->clipOrigin.x, @@ -312,7 +333,7 @@ pixman_image_set_clip_region (pixman_image_t *image, #define BOUND(v) (int16_t) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v)) static __inline int -IcClipImageReg (pixman_region16_t *region, +FbClipImageReg (pixman_region16_t *region, pixman_region16_t *clip, int dx, int dy) @@ -348,7 +369,7 @@ IcClipImageReg (pixman_region16_t *region, } static __inline int -IcClipImageSrc (pixman_region16_t *region, +FbClipImageSrc (pixman_region16_t *region, pixman_image_t *image, int dx, int dy) @@ -358,7 +379,9 @@ IcClipImageSrc (pixman_region16_t *region, return 1; if (image->repeat) { - if (image->clientClipType != CT_NONE) + /* XXX no source clipping */ + if (image->compositeClipSource && + image->clientClipType != CT_NONE) { pixman_region_translate (region, dx - image->clipOrigin.x, @@ -372,8 +395,14 @@ IcClipImageSrc (pixman_region16_t *region, } else { - return IcClipImageReg (region, - image->pCompositeClip, + pixman_region16_t *clip; + + if (image->compositeClipSource) + clip = image->pCompositeClip; + else + clip = image->pSourceClip; + return FbClipImageReg (region, + clip, dx, dy); } @@ -567,7 +596,7 @@ SetPictureClipRects (PicturePtr pPicture, */ int -IcComputeCompositeRegion (pixman_region16_t *region, +FbComputeCompositeRegion (pixman_region16_t *region, pixman_image_t *iSrc, pixman_image_t *iMask, pixman_image_t *iDst, @@ -602,14 +631,14 @@ IcComputeCompositeRegion (pixman_region16_t *region, return 1; } /* clip against src */ - if (!IcClipImageSrc (region, iSrc, xDst - xSrc, yDst - ySrc)) + if (!FbClipImageSrc (region, iSrc, xDst - xSrc, yDst - ySrc)) { pixman_region_destroy (region); return 0; } if (iSrc->alphaMap) { - if (!IcClipImageSrc (region, iSrc->alphaMap, + if (!FbClipImageSrc (region, iSrc->alphaMap, xDst - (xSrc + iSrc->alphaOrigin.x), yDst - (ySrc + iSrc->alphaOrigin.y))) { @@ -620,14 +649,14 @@ IcComputeCompositeRegion (pixman_region16_t *region, /* clip against mask */ if (iMask) { - if (!IcClipImageSrc (region, iMask, xDst - xMask, yDst - yMask)) + if (!FbClipImageSrc (region, iMask, xDst - xMask, yDst - yMask)) { pixman_region_destroy (region); return 0; } if (iMask->alphaMap) { - if (!IcClipImageSrc (region, iMask->alphaMap, + if (!FbClipImageSrc (region, iMask->alphaMap, xDst - (xMask + iMask->alphaOrigin.x), yDst - (yMask + iMask->alphaOrigin.y))) { @@ -636,14 +665,14 @@ IcComputeCompositeRegion (pixman_region16_t *region, } } } - if (!IcClipImageReg (region, iDst->pCompositeClip, 0, 0)) + if (!FbClipImageReg (region, iDst->pCompositeClip, 0, 0)) { pixman_region_destroy (region); return 0; } if (iDst->alphaMap) { - if (!IcClipImageReg (region, iDst->alphaMap->pCompositeClip, + if (!FbClipImageReg (region, iDst->alphaMap->pCompositeClip, -iDst->alphaOrigin.x, -iDst->alphaOrigin.y)) { diff --git a/gfx/cairo/libpixman/src/icimage.h b/gfx/cairo/libpixman/src/icimage.h index becc7b09a97c..b3e012f9dac6 100644 --- a/gfx/cairo/libpixman/src/icimage.h +++ b/gfx/cairo/libpixman/src/icimage.h @@ -33,38 +33,6 @@ #include "resource.h" */ - -#define IcIntMult(a,b,t) ( (t) = (a) * (b) + 0x80, ( ( ( (t)>>8 ) + (t) )>>8 ) ) -#define IcIntDiv(a,b) (((uint16_t) (a) * 255) / (b)) - -#define IcGet8(v,i) ((uint16_t) (uint8_t) ((v) >> i)) - -/* - * There are two ways of handling alpha -- either as a single unified value or - * a separate value for each component, hence each macro must have two - * versions. The unified alpha version has a 'U' at the end of the name, - * the component version has a 'C'. Similarly, functions which deal with - * this difference will have two versions using the same convention. - */ - -#define IcOverU(x,y,i,a,t) ((t) = IcIntMult(IcGet8(y,i),(a),(t)) + IcGet8(x,i),\ - (uint32_t) ((uint8_t) ((t) | (0 - ((t) >> 8)))) << (i)) - -#define IcOverC(x,y,i,a,t) ((t) = IcIntMult(IcGet8(y,i),IcGet8(a,i),(t)) + IcGet8(x,i),\ - (uint32_t) ((uint8_t) ((t) | (0 - ((t) >> 8)))) << (i)) - -#define IcInU(x,i,a,t) ((uint32_t) IcIntMult(IcGet8(x,i),(a),(t)) << (i)) - -#define IcInC(x,i,a,t) ((uint32_t) IcIntMult(IcGet8(x,i),IcGet8(a,i),(t)) << (i)) - -#define IcGen(x,y,i,ax,ay,t,u,v) ((t) = (IcIntMult(IcGet8(y,i),ay,(u)) + \ - IcIntMult(IcGet8(x,i),ax,(v))),\ - (uint32_t) ((uint8_t) ((t) | \ - (0 - ((t) >> 8)))) << (i)) - -#define IcAdd(x,y,i,t) ((t) = IcGet8(x,i) + IcGet8(y,i), \ - (uint32_t) ((uint8_t) ((t) | (0 - ((t) >> 8)))) << (i)) - /* typedef struct _IndexFormat { VisualPtr pVisual; @@ -87,7 +55,7 @@ typedef struct pixman_format { */ struct pixman_image { - IcPixels *pixels; + FbPixels *pixels; pixman_format_t image_format; int format_code; int refcnt; @@ -97,16 +65,17 @@ struct pixman_image { unsigned int subWindowMode : 1; unsigned int polyEdge : 1; unsigned int polyMode : 1; - /* XXX: Do we need this field */ unsigned int freeCompClip : 1; + unsigned int freeSourceClip : 1; unsigned int clientClipType : 2; unsigned int componentAlpha : 1; - unsigned int unused : 23; + unsigned int compositeClipSource : 1; + unsigned int unused : 21; struct pixman_image *alphaMap; - IcPoint alphaOrigin; + FbPoint alphaOrigin; - IcPoint clipOrigin; + FbPoint clipOrigin; void *clientClip; unsigned long dither; @@ -115,6 +84,7 @@ struct pixman_image { unsigned long serialNumber; pixman_region16_t *pCompositeClip; + pixman_region16_t *pSourceClip; pixman_transform_t *transform; @@ -133,28 +103,27 @@ struct pixman_image { #define IC_MAX_INDEXED 256 /* XXX depth must be <= 8 */ #if IC_MAX_INDEXED <= 256 -typedef uint8_t IcIndexType; +typedef uint8_t FbIndexType; #endif -/* XXX: We're not supporting indexed operations, right? -typedef struct _IcIndexed { +/* XXX: We're not supporting indexed operations, right? */ +typedef struct _FbIndexed { int color; uint32_t rgba[IC_MAX_INDEXED]; - IcIndexType ent[32768]; -} IcIndexedRec, *IcIndexedPtr; -*/ + FbIndexType ent[32768]; +} FbIndexedRec, *FbIndexedPtr; -#define IcCvtR8G8B8to15(s) ((((s) >> 3) & 0x001f) | \ +#define FbCvtR8G8B8to15(s) ((((s) >> 3) & 0x001f) | \ (((s) >> 6) & 0x03e0) | \ (((s) >> 9) & 0x7c00)) -#define IcIndexToEnt15(icf,rgb15) ((icf)->ent[rgb15]) -#define IcIndexToEnt24(icf,rgb24) IcIndexToEnt15(icf,IcCvtR8G8B8to15(rgb24)) +#define FbIndexToEnt15(icf,rgb15) ((icf)->ent[rgb15]) +#define FbIndexToEnt24(icf,rgb24) FbIndexToEnt15(icf,FbCvtR8G8B8to15(rgb24)) -#define IcIndexToEntY24(icf,rgb24) ((icf)->ent[CvtR8G8B8toY15(rgb24)]) +#define FbIndexToEntY24(icf,rgb24) ((icf)->ent[CvtR8G8B8toY15(rgb24)]) /* pixman_private int -IcCreatePicture (PicturePtr pPicture); +FbCreatePicture (PicturePtr pPicture); */ pixman_private void @@ -165,14 +134,14 @@ pixman_image_destroyClip (pixman_image_t *image); /* pixman_private void -IcValidatePicture (PicturePtr pPicture, +FbValidatePicture (PicturePtr pPicture, Mask mask); */ /* XXX: What should this be? pixman_private int -IcClipPicture (pixman_region16_t *region, +FbClipPicture (pixman_region16_t *region, pixman_image_t *image, int16_t xReg, int16_t yReg, @@ -181,7 +150,7 @@ IcClipPicture (pixman_region16_t *region, */ pixman_private int -IcComputeCompositeRegion (pixman_region16_t *region, +FbComputeCompositeRegion (pixman_region16_t *region, pixman_image_t *iSrc, pixman_image_t *iMask, pixman_image_t *iDst, @@ -199,12 +168,12 @@ miIsSolidAlpha (pixman_image_t *src); /* pixman_private int -IcPictureInit (ScreenPtr pScreen, PictFormatPtr formats, int nformats); +FbPictureInit (ScreenPtr pScreen, PictFormatPtr formats, int nformats); */ /* pixman_private void -IcGlyphs (pixman_operator_t op, +FbGlyphs (pixman_operator_t op, PicturePtr pSrc, PicturePtr pDst, PictFormatPtr maskFormat, @@ -225,7 +194,7 @@ pixman_compositeRects (pixman_operator_t op, */ pixman_private pixman_image_t * -IcCreateAlphaPicture (pixman_image_t *dst, +FbCreateAlphaPicture (pixman_image_t *dst, pixman_format_t *format, uint16_t width, uint16_t height); @@ -243,15 +212,15 @@ typedef void (*CompositeFunc) (pixman_operator_t op, uint16_t width, uint16_t height); -typedef struct _pixman_compositeOperand pixman_compositeOperand; +typedef struct _FbCompositeOperand FbCompositeOperand; -typedef uint32_t (*pixman_compositeFetch)(pixman_compositeOperand *op); -typedef void (*pixman_compositeStore) (pixman_compositeOperand *op, uint32_t value); +typedef uint32_t (*pixman_compositeFetch)(FbCompositeOperand *op); +typedef void (*pixman_compositeStore) (FbCompositeOperand *op, uint32_t value); -typedef void (*pixman_compositeStep) (pixman_compositeOperand *op); -typedef void (*pixman_compositeSet) (pixman_compositeOperand *op, int x, int y); +typedef void (*pixman_compositeStep) (FbCompositeOperand *op); +typedef void (*pixman_compositeSet) (FbCompositeOperand *op, int x, int y); -struct _pixman_compositeOperand { +struct _FbCompositeOperand { union { struct { pixman_bits_t *top_line; @@ -260,7 +229,7 @@ struct _pixman_compositeOperand { int start_offset; pixman_bits_t *line; uint32_t offset; - IcStride stride; + FbStride stride; int bpp; } drawable; struct { @@ -287,32 +256,33 @@ struct _pixman_compositeOperand { pixman_compositeStep down; pixman_compositeSet set; /* XXX: We're not supporting indexed operations, right? - IcIndexedPtr indexed; + FbIndexedPtr indexed; */ - pixman_region16_t *clip; + pixman_region16_t *dst_clip; + pixman_region16_t *src_clip; }; -typedef void (*IcCombineFunc) (pixman_compositeOperand *src, - pixman_compositeOperand *msk, - pixman_compositeOperand *dst); +typedef void (*FbCombineFunc) (FbCompositeOperand *src, + FbCompositeOperand *msk, + FbCompositeOperand *dst); -typedef struct _IcAccessMap { +typedef struct _FbAccessMap { uint32_t format_code; pixman_compositeFetch fetch; pixman_compositeFetch fetcha; pixman_compositeStore store; -} IcAccessMap; +} FbAccessMap; /* iccompose.c */ -typedef struct _IcCompSrc { +typedef struct _FbCompSrc { uint32_t value; uint32_t alpha; -} IcCompSrc; +} FbCompSrc; pixman_private int -IcBuildCompositeOperand (pixman_image_t *image, - pixman_compositeOperand op[4], +fbBuildCompositeOperand (pixman_image_t *image, + FbCompositeOperand op[4], int16_t x, int16_t y, int transform, diff --git a/gfx/cairo/libpixman/src/icint.h b/gfx/cairo/libpixman/src/icint.h index a31ddf444012..5e6367e8f829 100644 --- a/gfx/cairo/libpixman/src/icint.h +++ b/gfx/cairo/libpixman/src/icint.h @@ -24,7 +24,7 @@ #define _ICINT_H_ #ifdef HAVE_CONFIG_H -# include "../config.h" +# include "config.h" #endif #include "pixman.h" @@ -39,6 +39,12 @@ #define __inline #endif +#if defined(__GNUC__) +#define INLINE __inline__ +#else +#define INLINE +#endif + #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) @@ -54,13 +60,14 @@ */ #define MOD(a, b) ((b) == 1 ? 0 : (a) >= 0 ? (a) % (b) : (b) - (-(a) - 1) % (b) - 1) -typedef struct _IcPoint { +typedef struct _FbPoint { int16_t x,y ; -} IcPoint; +} FbPoint; typedef unsigned int Mask; +#define GXcopy 0x3 #define GXor 0x7 #define ClipByChildren 0 #define PolyEdgeSharp 0 @@ -69,7 +76,27 @@ typedef unsigned int Mask; #define CPLastBit 11 +/* Define any names that the server code will be expecting in + * terms of libpixman names. */ +typedef uint8_t CARD8; +typedef uint16_t CARD16; +typedef uint32_t CARD32; +typedef int16_t INT16; + +typedef int Bool; +#define FALSE 0 +#define TRUE 1 + +typedef pixman_bits_t FbBits; +typedef pixman_image_t* PicturePtr; +typedef pixman_box16_t BoxRec; +typedef pixman_box16_t* BoxPtr; + +typedef pixman_point_fixed_t xPointFixed; +typedef pixman_line_fixed_t xLineFixed; +typedef pixman_trapezoid_t xTrapezoid; +typedef pixman_triangle_t xTriangle; /* These few definitions avoid me needing to include servermd.h and misc.h from Xserver/include */ #ifndef BITMAP_SCANLINE_PAD @@ -105,14 +132,14 @@ typedef unsigned int Mask; drop quite a bit of it. Once the real ic code starts to come together I can probably figure out what is not needed here. */ -#define IC_UNIT (1 << IC_SHIFT) -#define IC_HALFUNIT (1 << (IC_SHIFT-1)) -#define IC_MASK (IC_UNIT - 1) -#define IC_ALLONES ((pixman_bits_t) -1) +#define FB_UNIT (1 << FB_SHIFT) +#define FB_HALFUNIT (1 << (FB_SHIFT-1)) +#define FB_MASK (FB_UNIT - 1) +#define FB_ALLONES ((pixman_bits_t) -1) /* whether to bother to include 24bpp support */ #ifndef ICNO24BIT -#define IC_24BIT +#define FB_24BIT #endif /* @@ -120,149 +147,149 @@ typedef unsigned int Mask; * windows with 32bpp image format for application compatibility */ -#ifdef IC_24BIT +#ifdef FB_24BIT #ifndef ICNO24_32 -#define IC_24_32BIT +#define FB_24_32BIT #endif #endif -#define IC_STIP_SHIFT LOG2_BITMAP_PAD -#define IC_STIP_UNIT (1 << IC_STIP_SHIFT) -#define IC_STIP_MASK (IC_STIP_UNIT - 1) -#define IC_STIP_ALLONES ((IcStip) -1) +#define FB_STIP_SHIFT LOG2_BITMAP_PAD +#define FB_STIP_UNIT (1 << FB_STIP_SHIFT) +#define FB_STIP_MASK (FB_STIP_UNIT - 1) +#define FB_STIP_ALLONES ((FbStip) -1) -#define IC_STIP_ODDSTRIDE(s) (((s) & (IC_MASK >> IC_STIP_SHIFT)) != 0) -#define IC_STIP_ODDPTR(p) ((((long) (p)) & (IC_MASK >> 3)) != 0) +#define FB_STIP_ODDSTRIDE(s) (((s) & (FB_MASK >> FB_STIP_SHIFT)) != 0) +#define FB_STIP_ODDPTR(p) ((((long) (p)) & (FB_MASK >> 3)) != 0) -#define IcStipStrideToBitsStride(s) (((s) >> (IC_SHIFT - IC_STIP_SHIFT))) -#define IcBitsStrideToStipStride(s) (((s) << (IC_SHIFT - IC_STIP_SHIFT))) +#define FbStipStrideToBitsStride(s) (((s) >> (FB_SHIFT - FB_STIP_SHIFT))) +#define FbBitsStrideToStipStride(s) (((s) << (FB_SHIFT - FB_STIP_SHIFT))) -#define IcFullMask(n) ((n) == IC_UNIT ? IC_ALLONES : ((((pixman_bits_t) 1) << n) - 1)) +#define FbFullMask(n) ((n) == FB_UNIT ? FB_ALLONES : ((((FbBits) 1) << n) - 1)) -typedef uint32_t IcStip; -typedef int IcStride; +typedef uint32_t FbStip; +typedef int FbStride; -#ifdef IC_DEBUG -extern void IcValidateDrawable(DrawablePtr d); -extern void IcInitializeDrawable(DrawablePtr d); -extern void IcSetBits (IcStip *bits, int stride, IcStip data); -#define IC_HEAD_BITS (IcStip) (0xbaadf00d) -#define IC_TAIL_BITS (IcStip) (0xbaddf0ad) +#ifdef FB_DEBUG +extern void fbValidateDrawable(DrawablePtr d); +extern void fbInitializeDrawable(DrawablePtr d); +extern void fbSetBits (FbStip *bits, int stride, FbStip data); +#define FB_HEAD_BITS (FbStip) (0xbaadf00d) +#define FB_TAIL_BITS (FbStip) (0xbaddf0ad) #else -#define IcValidateDrawable(d) +#define fbValidateDrawable(d) #define fdInitializeDrawable(d) #endif #if BITMAP_BIT_ORDER == LSBFirst -#define IcScrLeft(x,n) ((x) >> (n)) -#define IcScrRight(x,n) ((x) << (n)) -/* #define IcLeftBits(x,n) ((x) & ((((pixman_bits_t) 1) << (n)) - 1)) */ -#define IcLeftStipBits(x,n) ((x) & ((((IcStip) 1) << (n)) - 1)) -#define IcStipMoveLsb(x,s,n) (IcStipRight (x,(s)-(n))) -#define IcPatternOffsetBits 0 +#define FbScrLeft(x,n) ((x) >> (n)) +#define FbScrRight(x,n) ((x) << (n)) +/* #define FbLeftBits(x,n) ((x) & ((((FbBits) 1) << (n)) - 1)) */ +#define FbLeftStipBits(x,n) ((x) & ((((FbStip) 1) << (n)) - 1)) +#define FbStipMoveLsb(x,s,n) (FbStipRight (x,(s)-(n))) +#define FbPatternOffsetBits 0 #else -#define IcScrLeft(x,n) ((x) << (n)) -#define IcScrRight(x,n) ((x) >> (n)) -/* #define IcLeftBits(x,n) ((x) >> (IC_UNIT - (n))) */ -#define IcLeftStipBits(x,n) ((x) >> (IC_STIP_UNIT - (n))) -#define IcStipMoveLsb(x,s,n) (x) -#define IcPatternOffsetBits (sizeof (pixman_bits_t) - 1) +#define FbScrLeft(x,n) ((x) << (n)) +#define FbScrRight(x,n) ((x) >> (n)) +/* #define FbLeftBits(x,n) ((x) >> (FB_UNIT - (n))) */ +#define FbLeftStipBits(x,n) ((x) >> (FB_STIP_UNIT - (n))) +#define FbStipMoveLsb(x,s,n) (x) +#define FbPatternOffsetBits (sizeof (FbBits) - 1) #endif -#define IcStipLeft(x,n) IcScrLeft(x,n) -#define IcStipRight(x,n) IcScrRight(x,n) +#define FbStipLeft(x,n) FbScrLeft(x,n) +#define FbStipRight(x,n) FbScrRight(x,n) -#define IcRotLeft(x,n) IcScrLeft(x,n) | (n ? IcScrRight(x,IC_UNIT-n) : 0) -#define IcRotRight(x,n) IcScrRight(x,n) | (n ? IcScrLeft(x,IC_UNIT-n) : 0) +#define FbRotLeft(x,n) FbScrLeft(x,n) | (n ? FbScrRight(x,FB_UNIT-n) : 0) +#define FbRotRight(x,n) FbScrRight(x,n) | (n ? FbScrLeft(x,FB_UNIT-n) : 0) -#define IcRotStipLeft(x,n) IcStipLeft(x,n) | (n ? IcStipRight(x,IC_STIP_UNIT-n) : 0) -#define IcRotStipRight(x,n) IcStipRight(x,n) | (n ? IcStipLeft(x,IC_STIP_UNIT-n) : 0) +#define FbRotStipLeft(x,n) FbStipLeft(x,n) | (n ? FbStipRight(x,FB_STIP_UNIT-n) : 0) +#define FbRotStipRight(x,n) FbStipRight(x,n) | (n ? FbStipLeft(x,FB_STIP_UNIT-n) : 0) -#define IcLeftMask(x) ( ((x) & IC_MASK) ? \ - IcScrRight(IC_ALLONES,(x) & IC_MASK) : 0) -#define IcRightMask(x) ( ((IC_UNIT - (x)) & IC_MASK) ? \ - IcScrLeft(IC_ALLONES,(IC_UNIT - (x)) & IC_MASK) : 0) +#define FbLeftMask(x) ( ((x) & FB_MASK) ? \ + FbScrRight(FB_ALLONES,(x) & FB_MASK) : 0) +#define FbRightMask(x) ( ((FB_UNIT - (x)) & FB_MASK) ? \ + FbScrLeft(FB_ALLONES,(FB_UNIT - (x)) & FB_MASK) : 0) -#define IcLeftStipMask(x) ( ((x) & IC_STIP_MASK) ? \ - IcStipRight(IC_STIP_ALLONES,(x) & IC_STIP_MASK) : 0) -#define IcRightStipMask(x) ( ((IC_STIP_UNIT - (x)) & IC_STIP_MASK) ? \ - IcScrLeft(IC_STIP_ALLONES,(IC_STIP_UNIT - (x)) & IC_STIP_MASK) : 0) +#define FbLeftStipMask(x) ( ((x) & FB_STIP_MASK) ? \ + FbStipRight(FB_STIP_ALLONES,(x) & FB_STIP_MASK) : 0) +#define FbRightStipMask(x) ( ((FB_STIP_UNIT - (x)) & FB_STIP_MASK) ? \ + FbScrLeft(FB_STIP_ALLONES,(FB_STIP_UNIT - (x)) & FB_STIP_MASK) : 0) -#define IcBitsMask(x,w) (IcScrRight(IC_ALLONES,(x) & IC_MASK) & \ - IcScrLeft(IC_ALLONES,(IC_UNIT - ((x) + (w))) & IC_MASK)) +#define FbBitsMask(x,w) (FbScrRight(FB_ALLONES,(x) & FB_MASK) & \ + FbScrLeft(FB_ALLONES,(FB_UNIT - ((x) + (w))) & FB_MASK)) -#define IcStipMask(x,w) (IcStipRight(IC_STIP_ALLONES,(x) & IC_STIP_MASK) & \ - IcStipLeft(IC_STIP_ALLONES,(IC_STIP_UNIT - ((x)+(w))) & IC_STIP_MASK)) +#define FbStipMask(x,w) (FbStipRight(FB_STIP_ALLONES,(x) & FB_STIP_MASK) & \ + FbStipLeft(FB_STIP_ALLONES,(FB_STIP_UNIT - ((x)+(w))) & FB_STIP_MASK)) -#define IcMaskBits(x,w,l,n,r) { \ +#define FbMaskBits(x,w,l,n,r) { \ n = (w); \ - r = IcRightMask((x)+n); \ - l = IcLeftMask(x); \ + r = FbRightMask((x)+n); \ + l = FbLeftMask(x); \ if (l) { \ - n -= IC_UNIT - ((x) & IC_MASK); \ + n -= FB_UNIT - ((x) & FB_MASK); \ if (n < 0) { \ n = 0; \ l &= r; \ r = 0; \ } \ } \ - n >>= IC_SHIFT; \ + n >>= FB_SHIFT; \ } #ifdef ICNOPIXADDR -#define IcMaskBitsBytes(x,w,copy,l,lb,n,r,rb) IcMaskBits(x,w,l,n,r) -#define IcDoLeftMaskByteRRop(dst,lb,l,and,xor) { \ - *dst = IcDoMaskRRop(*dst,and,xor,l); \ +#define FbMaskBitsBytes(x,w,copy,l,lb,n,r,rb) FbMaskBits(x,w,l,n,r) +#define FbDoLeftMaskByteRRop(dst,lb,l,and,xor) { \ + *dst = FbDoMaskRRop(*dst,and,xor,l); \ } -#define IcDoRightMaskByteRRop(dst,rb,r,and,xor) { \ - *dst = IcDoMaskRRop(*dst,and,xor,r); \ +#define FbDoRightMaskByteRRop(dst,rb,r,and,xor) { \ + *dst = FbDoMaskRRop(*dst,and,xor,r); \ } #else -#define IcByteMaskInvalid 0x10 +#define FbByteMaskInvalid 0x10 -#define IcPatternOffset(o,t) ((o) ^ (IcPatternOffsetBits & ~(sizeof (t) - 1))) +#define FbPatternOffset(o,t) ((o) ^ (FbPatternOffsetBits & ~(sizeof (t) - 1))) -#define IcPtrOffset(p,o,t) ((t *) ((uint8_t *) (p) + (o))) -#define IcSelectPatternPart(xor,o,t) ((xor) >> (IcPatternOffset (o,t) << 3)) -#define IcStorePart(dst,off,t,xor) (*IcPtrOffset(dst,off,t) = \ - IcSelectPart(xor,off,t)) -#ifndef IcSelectPart -#define IcSelectPart(x,o,t) IcSelectPatternPart(x,o,t) +#define FbPtrOffset(p,o,t) ((t *) ((CARD8 *) (p) + (o))) +#define FbSelectPatternPart(xor,o,t) ((xor) >> (FbPatternOffset (o,t) << 3)) +#define FbStorePart(dst,off,t,xor) (*FbPtrOffset(dst,off,t) = \ + FbSelectPart(xor,off,t)) +#ifndef FbSelectPart +#define FbSelectPart(x,o,t) FbSelectPatternPart(x,o,t) #endif -#define IcMaskBitsBytes(x,w,copy,l,lb,n,r,rb) { \ +#define FbMaskBitsBytes(x,w,copy,l,lb,n,r,rb) { \ n = (w); \ lb = 0; \ rb = 0; \ - r = IcRightMask((x)+n); \ + r = FbRightMask((x)+n); \ if (r) { \ /* compute right byte length */ \ if ((copy) && (((x) + n) & 7) == 0) { \ - rb = (((x) + n) & IC_MASK) >> 3; \ + rb = (((x) + n) & FB_MASK) >> 3; \ } else { \ - rb = IcByteMaskInvalid; \ + rb = FbByteMaskInvalid; \ } \ } \ - l = IcLeftMask(x); \ + l = FbLeftMask(x); \ if (l) { \ /* compute left byte length */ \ if ((copy) && ((x) & 7) == 0) { \ - lb = ((x) & IC_MASK) >> 3; \ + lb = ((x) & FB_MASK) >> 3; \ } else { \ - lb = IcByteMaskInvalid; \ + lb = FbByteMaskInvalid; \ } \ /* subtract out the portion painted by leftMask */ \ - n -= IC_UNIT - ((x) & IC_MASK); \ + n -= FB_UNIT - ((x) & FB_MASK); \ if (n < 0) { \ - if (lb != IcByteMaskInvalid) { \ - if (rb == IcByteMaskInvalid) { \ - lb = IcByteMaskInvalid; \ + if (lb != FbByteMaskInvalid) { \ + if (rb == FbByteMaskInvalid) { \ + lb = FbByteMaskInvalid; \ } else if (rb) { \ - lb |= (rb - lb) << (IC_SHIFT - 3); \ + lb |= (rb - lb) << (FB_SHIFT - 3); \ rb = 0; \ } \ } \ @@ -271,182 +298,182 @@ extern void IcSetBits (IcStip *bits, int stride, IcStip data); r = 0; \ }\ } \ - n >>= IC_SHIFT; \ + n >>= FB_SHIFT; \ } -#if IC_SHIFT == 6 -#define IcDoLeftMaskByteRRop6Cases(dst,xor) \ - case (sizeof (pixman_bits_t) - 7) | (1 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 7,uint8_t,xor); \ +#if FB_SHIFT == 6 +#define FbDoLeftMaskByteRRop6Cases(dst,xor) \ + case (sizeof (FbBits) - 7) | (1 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 7,CARD8,xor); \ break; \ - case (sizeof (pixman_bits_t) - 7) | (2 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 7,uint8_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 6,uint8_t,xor); \ + case (sizeof (FbBits) - 7) | (2 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 7,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD8,xor); \ break; \ - case (sizeof (pixman_bits_t) - 7) | (3 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 7,uint8_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 6,uint16_t,xor); \ + case (sizeof (FbBits) - 7) | (3 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 7,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ break; \ - case (sizeof (pixman_bits_t) - 7) | (4 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 7,uint8_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 6,uint16_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 4,uint8_t,xor); \ + case (sizeof (FbBits) - 7) | (4 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 7,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD8,xor); \ break; \ - case (sizeof (pixman_bits_t) - 7) | (5 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 7,uint8_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 6,uint16_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 4,uint16_t,xor); \ + case (sizeof (FbBits) - 7) | (5 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 7,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD16,xor); \ break; \ - case (sizeof (pixman_bits_t) - 7) | (6 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 7,uint8_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 6,uint16_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 4,uint16_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 2,uint8_t,xor); \ + case (sizeof (FbBits) - 7) | (6 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 7,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 2,CARD8,xor); \ break; \ - case (sizeof (pixman_bits_t) - 7): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 7,uint8_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 6,uint16_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 4,uint32_t,xor); \ + case (sizeof (FbBits) - 7): \ + FbStorePart(dst,sizeof (FbBits) - 7,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD32,xor); \ break; \ - case (sizeof (pixman_bits_t) - 6) | (1 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 6,uint8_t,xor); \ + case (sizeof (FbBits) - 6) | (1 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD8,xor); \ break; \ - case (sizeof (pixman_bits_t) - 6) | (2 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 6,uint16_t,xor); \ + case (sizeof (FbBits) - 6) | (2 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ break; \ - case (sizeof (pixman_bits_t) - 6) | (3 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 6,uint16_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 4,uint8_t,xor); \ + case (sizeof (FbBits) - 6) | (3 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD8,xor); \ break; \ - case (sizeof (pixman_bits_t) - 6) | (4 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 6,uint16_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 4,uint16_t,xor); \ + case (sizeof (FbBits) - 6) | (4 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD16,xor); \ break; \ - case (sizeof (pixman_bits_t) - 6) | (5 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 6,uint16_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 4,uint16_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 2,uint8_t,xor); \ + case (sizeof (FbBits) - 6) | (5 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 2,CARD8,xor); \ break; \ - case (sizeof (pixman_bits_t) - 6): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 6,uint16_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 4,uint32_t,xor); \ + case (sizeof (FbBits) - 6): \ + FbStorePart(dst,sizeof (FbBits) - 6,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD32,xor); \ break; \ - case (sizeof (pixman_bits_t) - 5) | (1 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 5,uint8_t,xor); \ + case (sizeof (FbBits) - 5) | (1 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 5,CARD8,xor); \ break; \ - case (sizeof (pixman_bits_t) - 5) | (2 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 5,uint8_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 4,uint8_t,xor); \ + case (sizeof (FbBits) - 5) | (2 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 5,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD8,xor); \ break; \ - case (sizeof (pixman_bits_t) - 5) | (3 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 5,uint8_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 4,uint16_t,xor); \ + case (sizeof (FbBits) - 5) | (3 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 5,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD16,xor); \ break; \ - case (sizeof (pixman_bits_t) - 5) | (4 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 5,uint8_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 4,uint16_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 2,uint8_t,xor); \ + case (sizeof (FbBits) - 5) | (4 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 5,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 2,CARD8,xor); \ break; \ - case (sizeof (pixman_bits_t) - 5): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 5,uint8_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 4,uint32_t,xor); \ + case (sizeof (FbBits) - 5): \ + FbStorePart(dst,sizeof (FbBits) - 5,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD32,xor); \ break; \ - case (sizeof (pixman_bits_t) - 4) | (1 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 4,uint8_t,xor); \ + case (sizeof (FbBits) - 4) | (1 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD8,xor); \ break; \ - case (sizeof (pixman_bits_t) - 4) | (2 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 4,uint16_t,xor); \ + case (sizeof (FbBits) - 4) | (2 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD16,xor); \ break; \ - case (sizeof (pixman_bits_t) - 4) | (3 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 4,uint16_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 2,uint8_t,xor); \ + case (sizeof (FbBits) - 4) | (3 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD16,xor); \ + FbStorePart(dst,sizeof (FbBits) - 2,CARD8,xor); \ break; \ - case (sizeof (pixman_bits_t) - 4): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 4,uint32_t,xor); \ + case (sizeof (FbBits) - 4): \ + FbStorePart(dst,sizeof (FbBits) - 4,CARD32,xor); \ break; -#define IcDoRightMaskByteRRop6Cases(dst,xor) \ +#define FbDoRightMaskByteRRop6Cases(dst,xor) \ case 4: \ - IcStorePart(dst,0,uint32_t,xor); \ + FbStorePart(dst,0,CARD32,xor); \ break; \ case 5: \ - IcStorePart(dst,0,uint32_t,xor); \ - IcStorePart(dst,4,uint8_t,xor); \ + FbStorePart(dst,0,CARD32,xor); \ + FbStorePart(dst,4,CARD8,xor); \ break; \ case 6: \ - IcStorePart(dst,0,uint32_t,xor); \ - IcStorePart(dst,4,uint16_t,xor); \ + FbStorePart(dst,0,CARD32,xor); \ + FbStorePart(dst,4,CARD16,xor); \ break; \ case 7: \ - IcStorePart(dst,0,uint32_t,xor); \ - IcStorePart(dst,4,uint16_t,xor); \ - IcStorePart(dst,6,uint8_t,xor); \ + FbStorePart(dst,0,CARD32,xor); \ + FbStorePart(dst,4,CARD16,xor); \ + FbStorePart(dst,6,CARD8,xor); \ break; #else -#define IcDoLeftMaskByteRRop6Cases(dst,xor) -#define IcDoRightMaskByteRRop6Cases(dst,xor) +#define FbDoLeftMaskByteRRop6Cases(dst,xor) +#define FbDoRightMaskByteRRop6Cases(dst,xor) #endif -#define IcDoLeftMaskByteRRop(dst,lb,l,and,xor) { \ +#define FbDoLeftMaskByteRRop(dst,lb,l,and,xor) { \ switch (lb) { \ - IcDoLeftMaskByteRRop6Cases(dst,xor) \ - case (sizeof (pixman_bits_t) - 3) | (1 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 3,uint8_t,xor); \ + FbDoLeftMaskByteRRop6Cases(dst,xor) \ + case (sizeof (FbBits) - 3) | (1 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 3,CARD8,xor); \ break; \ - case (sizeof (pixman_bits_t) - 3) | (2 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 3,uint8_t,xor); \ - IcStorePart(dst,sizeof (pixman_bits_t) - 2,uint8_t,xor); \ + case (sizeof (FbBits) - 3) | (2 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 3,CARD8,xor); \ + FbStorePart(dst,sizeof (FbBits) - 2,CARD8,xor); \ break; \ - case (sizeof (pixman_bits_t) - 2) | (1 << (IC_SHIFT - 3)): \ - IcStorePart(dst,sizeof (pixman_bits_t) - 2,uint8_t,xor); \ + case (sizeof (FbBits) - 2) | (1 << (FB_SHIFT - 3)): \ + FbStorePart(dst,sizeof (FbBits) - 2,CARD8,xor); \ break; \ - case sizeof (pixman_bits_t) - 3: \ - IcStorePart(dst,sizeof (pixman_bits_t) - 3,uint8_t,xor); \ - case sizeof (pixman_bits_t) - 2: \ - IcStorePart(dst,sizeof (pixman_bits_t) - 2,uint16_t,xor); \ + case sizeof (FbBits) - 3: \ + FbStorePart(dst,sizeof (FbBits) - 3,CARD8,xor); \ + case sizeof (FbBits) - 2: \ + FbStorePart(dst,sizeof (FbBits) - 2,CARD16,xor); \ break; \ - case sizeof (pixman_bits_t) - 1: \ - IcStorePart(dst,sizeof (pixman_bits_t) - 1,uint8_t,xor); \ + case sizeof (FbBits) - 1: \ + FbStorePart(dst,sizeof (FbBits) - 1,CARD8,xor); \ break; \ default: \ - *dst = IcDoMaskRRop(*dst, and, xor, l); \ + *dst = FbDoMaskRRop(*dst, and, xor, l); \ break; \ } \ } -#define IcDoRightMaskByteRRop(dst,rb,r,and,xor) { \ +#define FbDoRightMaskByteRRop(dst,rb,r,and,xor) { \ switch (rb) { \ case 1: \ - IcStorePart(dst,0,uint8_t,xor); \ + FbStorePart(dst,0,CARD8,xor); \ break; \ case 2: \ - IcStorePart(dst,0,uint16_t,xor); \ + FbStorePart(dst,0,CARD16,xor); \ break; \ case 3: \ - IcStorePart(dst,0,uint16_t,xor); \ - IcStorePart(dst,2,uint8_t,xor); \ + FbStorePart(dst,0,CARD16,xor); \ + FbStorePart(dst,2,CARD8,xor); \ break; \ - IcDoRightMaskByteRRop6Cases(dst,xor) \ + FbDoRightMaskByteRRop6Cases(dst,xor) \ default: \ - *dst = IcDoMaskRRop (*dst, and, xor, r); \ + *dst = FbDoMaskRRop (*dst, and, xor, r); \ } \ } #endif -#define IcMaskStip(x,w,l,n,r) { \ +#define FbMaskStip(x,w,l,n,r) { \ n = (w); \ - r = IcRightStipMask((x)+n); \ - l = IcLeftStipMask(x); \ + r = FbRightStipMask((x)+n); \ + l = FbLeftStipMask(x); \ if (l) { \ - n -= IC_STIP_UNIT - ((x) & IC_STIP_MASK); \ + n -= FB_STIP_UNIT - ((x) & FB_STIP_MASK); \ if (n < 0) { \ n = 0; \ l &= r; \ r = 0; \ } \ } \ - n >>= IC_STIP_SHIFT; \ + n >>= FB_STIP_SHIFT; \ } /* @@ -456,77 +483,77 @@ extern void IcSetBits (IcStip *bits, int stride, IcStip data); * sequence of partial word writes * * 'n' is the bytemask of which bytes to store, 'a' is the address - * of the pixman_bits_t base unit, 'o' is the offset within that unit + * of the FbBits base unit, 'o' is the offset within that unit * * The term "lane" comes from the hardware term "byte-lane" which */ -#define IcLaneCase1(n,a,o) ((n) == 0x01 ? \ - (*(uint8_t *) ((a)+IcPatternOffset(o,uint8_t)) = \ +#define FbLaneCase1(n,a,o) ((n) == 0x01 ? \ + (*(CARD8 *) ((a)+FbPatternOffset(o,CARD8)) = \ fgxor) : 0) -#define IcLaneCase2(n,a,o) ((n) == 0x03 ? \ - (*(uint16_t *) ((a)+IcPatternOffset(o,uint16_t)) = \ +#define FbLaneCase2(n,a,o) ((n) == 0x03 ? \ + (*(CARD16 *) ((a)+FbPatternOffset(o,CARD16)) = \ fgxor) : \ - ((void)IcLaneCase1((n)&1,a,o), \ - IcLaneCase1((n)>>1,a,(o)+1))) -#define IcLaneCase4(n,a,o) ((n) == 0x0f ? \ - (*(uint32_t *) ((a)+IcPatternOffset(o,uint32_t)) = \ + ((void)FbLaneCase1((n)&1,a,o), \ + FbLaneCase1((n)>>1,a,(o)+1))) +#define FbLaneCase4(n,a,o) ((n) == 0x0f ? \ + (*(CARD32 *) ((a)+FbPatternOffset(o,CARD32)) = \ fgxor) : \ - ((void)IcLaneCase2((n)&3,a,o), \ - IcLaneCase2((n)>>2,a,(o)+2))) -#define IcLaneCase8(n,a,o) ((n) == 0x0ff ? (*(pixman_bits_t *) ((a)+(o)) = fgxor) : \ - ((void)IcLaneCase4((n)&15,a,o), \ - IcLaneCase4((n)>>4,a,(o)+4))) + ((void)FbLaneCase2((n)&3,a,o), \ + FbLaneCase2((n)>>2,a,(o)+2))) +#define FbLaneCase8(n,a,o) ((n) == 0x0ff ? (*(FbBits *) ((a)+(o)) = fgxor) : \ + ((void)FbLaneCase4((n)&15,a,o), \ + FbLaneCase4((n)>>4,a,(o)+4))) -#if IC_SHIFT == 6 -#define IcLaneCase(n,a) IcLaneCase8(n,(uint8_t *) (a),0) +#if FB_SHIFT == 6 +#define FbLaneCase(n,a) FbLaneCase8(n,(CARD8 *) (a),0) #endif -#if IC_SHIFT == 5 -#define IcLaneCase(n,a) IcLaneCase4(n,(uint8_t *) (a),0) +#if FB_SHIFT == 5 +#define FbLaneCase(n,a) FbLaneCase4(n,(CARD8 *) (a),0) #endif /* Rotate a filled pixel value to the specified alignement */ -#define IcRot24(p,b) (IcScrRight(p,b) | IcScrLeft(p,24-(b))) -#define IcRot24Stip(p,b) (IcStipRight(p,b) | IcStipLeft(p,24-(b))) +#define FbRot24(p,b) (FbScrRight(p,b) | FbScrLeft(p,24-(b))) +#define FbRot24Stip(p,b) (FbStipRight(p,b) | FbStipLeft(p,24-(b))) -/* step a filled pixel value to the next/previous IC_UNIT alignment */ -#define IcNext24Pix(p) (IcRot24(p,(24-IC_UNIT%24))) -#define IcPrev24Pix(p) (IcRot24(p,IC_UNIT%24)) -#define IcNext24Stip(p) (IcRot24(p,(24-IC_STIP_UNIT%24))) -#define IcPrev24Stip(p) (IcRot24(p,IC_STIP_UNIT%24)) +/* step a filled pixel value to the next/previous FB_UNIT alignment */ +#define FbNext24Pix(p) (FbRot24(p,(24-FB_UNIT%24))) +#define FbPrev24Pix(p) (FbRot24(p,FB_UNIT%24)) +#define FbNext24Stip(p) (FbRot24(p,(24-FB_STIP_UNIT%24))) +#define FbPrev24Stip(p) (FbRot24(p,FB_STIP_UNIT%24)) /* step a rotation value to the next/previous rotation value */ -#if IC_UNIT == 64 -#define IcNext24Rot(r) ((r) == 16 ? 0 : (r) + 8) -#define IcPrev24Rot(r) ((r) == 0 ? 16 : (r) - 8) +#if FB_UNIT == 64 +#define FbNext24Rot(r) ((r) == 16 ? 0 : (r) + 8) +#define FbPrev24Rot(r) ((r) == 0 ? 16 : (r) - 8) #if IMAGE_BYTE_ORDER == MSBFirst -#define IcFirst24Rot(x) (((x) + 8) % 24) +#define FbFirst24Rot(x) (((x) + 8) % 24) #else -#define IcFirst24Rot(x) ((x) % 24) +#define FbFirst24Rot(x) ((x) % 24) #endif #endif -#if IC_UNIT == 32 -#define IcNext24Rot(r) ((r) == 0 ? 16 : (r) - 8) -#define IcPrev24Rot(r) ((r) == 16 ? 0 : (r) + 8) +#if FB_UNIT == 32 +#define FbNext24Rot(r) ((r) == 0 ? 16 : (r) - 8) +#define FbPrev24Rot(r) ((r) == 16 ? 0 : (r) + 8) #if IMAGE_BYTE_ORDER == MSBFirst -#define IcFirst24Rot(x) (((x) + 16) % 24) +#define FbFirst24Rot(x) (((x) + 16) % 24) #else -#define IcFirst24Rot(x) ((x) % 24) +#define FbFirst24Rot(x) ((x) % 24) #endif #endif -#define IcNext24RotStip(r) ((r) == 0 ? 16 : (r) - 8) -#define IcPrev24RotStip(r) ((r) == 16 ? 0 : (r) + 8) +#define FbNext24RotStip(r) ((r) == 0 ? 16 : (r) - 8) +#define FbPrev24RotStip(r) ((r) == 16 ? 0 : (r) + 8) /* Whether 24-bit specific code is needed for this filled pixel value */ -#define IcCheck24Pix(p) ((p) == IcNext24Pix(p)) +#define FbCheck24Pix(p) ((p) == FbNext24Pix(p)) -#define IcGetPixels(icpixels, pointer, _stride_, _bpp_, xoff, yoff) { \ +#define FbGetPixels(icpixels, pointer, _stride_, _bpp_, xoff, yoff) { \ (pointer) = icpixels->data; \ (_stride_) = icpixels->stride / sizeof(pixman_bits_t); \ (_bpp_) = icpixels->bpp; \ @@ -534,124 +561,124 @@ extern void IcSetBits (IcStip *bits, int stride, IcStip data); (yoff) = icpixels->y; /* XXX: fb.h had this ifdef'd to constant 0. Why? */ \ } -#define IcGetStipPixels(icpixels, pointer, _stride_, _bpp_, xoff, yoff) { \ - (pointer) = (IcStip *) icpixels->data; \ - (_stride_) = icpixels->stride; \ +#define FbGetStipPixels(icpixels, pointer, _stride_, _bpp_, xoff, yoff) { \ + (pointer) = (FbStip *) icpixels->data; \ + (_stride_) = icpixels->stride / sizeof(FbStip); \ (_bpp_) = icpixels->bpp; \ (xoff) = icpixels->x; \ (yoff) = icpixels->y; \ } -#ifdef IC_OLD_SCREEN +#ifdef FB_OLD_SCREEN #define BitsPerPixel(d) (\ ((1 << PixmapWidthPaddingInfo[d].padBytesLog2) * 8 / \ (PixmapWidthPaddingInfo[d].padRoundUp+1))) #endif -#define IcPowerOfTwo(w) (((w) & ((w) - 1)) == 0) +#define FbPowerOfTwo(w) (((w) & ((w) - 1)) == 0) /* - * Accelerated tiles are power of 2 width <= IC_UNIT + * Accelerated tiles are power of 2 width <= FB_UNIT */ -#define IcEvenTile(w) ((w) <= IC_UNIT && IcPowerOfTwo(w)) +#define FbEvenTile(w) ((w) <= FB_UNIT && FbPowerOfTwo(w)) /* - * Accelerated stipples are power of 2 width and <= IC_UNIT/dstBpp + * Accelerated stipples are power of 2 width and <= FB_UNIT/dstBpp * with dstBpp a power of 2 as well */ -#define IcEvenStip(w,bpp) ((w) * (bpp) <= IC_UNIT && IcPowerOfTwo(w) && IcPowerOfTwo(bpp)) +#define FbEvenStip(w,bpp) ((w) * (bpp) <= FB_UNIT && FbPowerOfTwo(w) && FbPowerOfTwo(bpp)) /* * icblt.c */ pixman_private void -IcBlt (pixman_bits_t *src, - IcStride srcStride, +fbBlt (pixman_bits_t *src, + FbStride srcStride, int srcX, - pixman_bits_t *dst, - IcStride dstStride, + FbBits *dst, + FbStride dstStride, int dstX, int width, int height, int alu, - pixman_bits_t pm, + FbBits pm, int bpp, - int reverse, - int upsidedown); + Bool reverse, + Bool upsidedown); pixman_private void -IcBlt24 (pixman_bits_t *srcLine, - IcStride srcStride, +fbBlt24 (pixman_bits_t *srcLine, + FbStride srcStride, int srcX, - pixman_bits_t *dstLine, - IcStride dstStride, + FbBits *dstLine, + FbStride dstStride, int dstX, int width, int height, int alu, - pixman_bits_t pm, + FbBits pm, - int reverse, - int upsidedown); + Bool reverse, + Bool upsidedown); pixman_private void -IcBltStip (IcStip *src, - IcStride srcStride, /* in IcStip units, not pixman_bits_t units */ +fbBltStip (FbStip *src, + FbStride srcStride, /* in FbStip units, not FbBits units */ int srcX, - IcStip *dst, - IcStride dstStride, /* in IcStip units, not pixman_bits_t units */ + FbStip *dst, + FbStride dstStride, /* in FbStip units, not FbBits units */ int dstX, int width, int height, int alu, - pixman_bits_t pm, + FbBits pm, int bpp); /* * icbltone.c */ pixman_private void -IcBltOne (IcStip *src, - IcStride srcStride, +fbBltOne (FbStip *src, + FbStride srcStride, int srcX, - pixman_bits_t *dst, - IcStride dstStride, + FbBits *dst, + FbStride dstStride, int dstX, int dstBpp, int width, int height, - pixman_bits_t fgand, - pixman_bits_t icxor, - pixman_bits_t bgand, - pixman_bits_t bgxor); + FbBits fgand, + FbBits fbxor, + FbBits bgand, + FbBits bgxor); -#ifdef IC_24BIT +#ifdef FB_24BIT pixman_private void -IcBltOne24 (IcStip *src, - IcStride srcStride, /* IcStip units per scanline */ +fbBltOne24 (FbStip *src, + FbStride srcStride, /* FbStip units per scanline */ int srcX, /* bit position of source */ - pixman_bits_t *dst, - IcStride dstStride, /* pixman_bits_t units per scanline */ + FbBits *dst, + FbStride dstStride, /* FbBits units per scanline */ int dstX, /* bit position of dest */ int dstBpp, /* bits per destination unit */ int width, /* width in bits of destination */ int height, /* height in scanlines */ - pixman_bits_t fgand, /* rrop values */ - pixman_bits_t fgxor, - pixman_bits_t bgand, - pixman_bits_t bgxor); + FbBits fgand, /* rrop values */ + FbBits fgxor, + FbBits bgand, + FbBits bgxor); #endif /* @@ -659,73 +686,73 @@ IcBltOne24 (IcStip *src, */ pixman_private void -IcTransparentSpan (pixman_bits_t *dst, +fbTransparentSpan (pixman_bits_t *dst, pixman_bits_t stip, pixman_bits_t fgxor, int n); pixman_private void -IcEvenStipple (pixman_bits_t *dst, - IcStride dstStride, +fbEvenStipple (pixman_bits_t *dst, + FbStride dstStride, int dstX, int dstBpp, int width, int height, - IcStip *stip, - IcStride stipStride, + FbStip *stip, + FbStride stipStride, int stipHeight, - pixman_bits_t fgand, - pixman_bits_t fgxor, - pixman_bits_t bgand, - pixman_bits_t bgxor, + FbBits fgand, + FbBits fgxor, + FbBits bgand, + FbBits bgxor, int xRot, int yRot); pixman_private void -IcOddStipple (pixman_bits_t *dst, - IcStride dstStride, +fbOddStipple (pixman_bits_t *dst, + FbStride dstStride, int dstX, int dstBpp, int width, int height, - IcStip *stip, - IcStride stipStride, + FbStip *stip, + FbStride stipStride, int stipWidth, int stipHeight, - pixman_bits_t fgand, - pixman_bits_t fgxor, - pixman_bits_t bgand, - pixman_bits_t bgxor, + FbBits fgand, + FbBits fgxor, + FbBits bgand, + FbBits bgxor, int xRot, int yRot); pixman_private void -IcStipple (pixman_bits_t *dst, - IcStride dstStride, +fbStipple (pixman_bits_t *dst, + FbStride dstStride, int dstX, int dstBpp, int width, int height, - IcStip *stip, - IcStride stipStride, + FbStip *stip, + FbStride stipStride, int stipWidth, int stipHeight, - int even, + Bool even, - pixman_bits_t fgand, - pixman_bits_t fgxor, - pixman_bits_t bgand, - pixman_bits_t bgxor, + FbBits fgand, + FbBits fgxor, + FbBits bgand, + FbBits bgxor, int xRot, int yRot); @@ -740,7 +767,7 @@ struct pixman_format { int alpha, alphaMask; }; -typedef struct _IcPixels { +typedef struct _FbPixels { pixman_bits_t *data; unsigned int width; unsigned int height; @@ -750,14 +777,14 @@ typedef struct _IcPixels { int x; int y; unsigned int refcnt; -} IcPixels; +} FbPixels; /* XXX: This is to avoid including colormap.h from the server includes */ typedef uint32_t Pixel; /* icutil.c */ pixman_private pixman_bits_t -IcReplicatePixel (Pixel p, int bpp); +fbReplicatePixel (Pixel p, int bpp); /* fbtrap.c */ @@ -787,14 +814,14 @@ fbRasterizeTrapezoid (pixman_image_t *pMask, good as the static function below. */ #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) # if __INT_MIN__ == 0x7fffffff -# define _IcOnes(mask) __builtin_popcount(mask) +# define _FbOnes(mask) __builtin_popcount(mask) # else -# define _IcOnes(mask) __builtin_popcountl((mask) & 0xffffffff) +# define _FbOnes(mask) __builtin_popcountl((mask) & 0xffffffff) # endif #else # define ICINT_NEED_IC_ONES int -_IcOnes(unsigned long mask); +_FbOnes(unsigned long mask); #endif /* icformat.c */ @@ -805,19 +832,19 @@ pixman_format_init (pixman_format_t *format, int format_code); /* icimage.c */ pixman_private pixman_image_t * -pixman_image_createForPixels (IcPixels *pixels, +pixman_image_createForPixels (FbPixels *pixels, pixman_format_t *format); /* icpixels.c */ -pixman_private IcPixels * -IcPixelsCreate (int width, int height, int depth); +pixman_private FbPixels * +FbPixelsCreate (int width, int height, int depth); -pixman_private IcPixels * -IcPixelsCreateForData (pixman_bits_t *data, int width, int height, int depth, int bpp, int stride); +pixman_private FbPixels * +FbPixelsCreateForData (pixman_bits_t *data, int width, int height, int depth, int bpp, int stride); pixman_private void -IcPixelsDestroy (IcPixels *pixels); +FbPixelsDestroy (FbPixels *pixels); /* ictransform.c */ @@ -902,9 +929,9 @@ typedef struct _PictFormat *PictFormatPtr; #define PICT_a1b5g5r5 PICT_FORMAT(16,PICT_TYPE_ABGR,1,5,5,5) #define PICT_x1b5g5r5 PICT_FORMAT(16,PICT_TYPE_ABGR,0,5,5,5) #define PICT_a4r4g4b4 PICT_FORMAT(16,PICT_TYPE_ARGB,4,4,4,4) -#define PICT_x4r4g4b4 PICT_FORMAT(16,PICT_TYPE_ARGB,4,4,4,4) -#define PICT_a4b4g4r4 PICT_FORMAT(16,PICT_TYPE_ARGB,4,4,4,4) -#define PICT_x4b4g4r4 PICT_FORMAT(16,PICT_TYPE_ARGB,4,4,4,4) +#define PICT_x4r4g4b4 PICT_FORMAT(16,PICT_TYPE_ARGB,0,4,4,4) +#define PICT_a4b4g4r4 PICT_FORMAT(16,PICT_TYPE_ABGR,4,4,4,4) +#define PICT_x4b4g4r4 PICT_FORMAT(16,PICT_TYPE_ABGR,0,4,4,4) /* 8bpp formats */ #define PICT_a8 PICT_FORMAT(8,PICT_TYPE_A,8,0,0,0) @@ -1044,4 +1071,34 @@ typedef xFixed_16_16 xFixed; #endif /* _PICTURE_H_ */ + +/* Macros needed by fbpict.c */ + +#define cvt8888to0565(s) ((((s) >> 3) & 0x001f) | \ + (((s) >> 5) & 0x07e0) | \ + (((s) >> 8) & 0xf800)) +#define cvt0565to0888(s) (((((s) << 3) & 0xf8) | (((s) >> 2) & 0x7)) | \ + ((((s) << 5) & 0xfc00) | (((s) >> 1) & 0x300)) | \ + ((((s) << 8) & 0xf80000) | (((s) << 3) & 0x70000))) + +#if IMAGE_BYTE_ORDER == MSBFirst +#define Fetch24(a) ((unsigned long) (a) & 1 ? \ + ((*(a) << 16) | *((CARD16 *) ((a)+1))) : \ + ((*((CARD16 *) (a)) << 8) | *((a)+2))) +#define Store24(a,v) ((unsigned long) (a) & 1 ? \ + ((*(a) = (CARD8) ((v) >> 16)), \ + (*((CARD16 *) ((a)+1)) = (CARD16) (v))) : \ + ((*((CARD16 *) (a)) = (CARD16) ((v) >> 8)), \ + (*((a)+2) = (CARD8) (v)))) +#else +#define Fetch24(a) ((unsigned long) (a) & 1 ? \ + ((*(a)) | (*((CARD16 *) ((a)+1)) << 8)) : \ + ((*((CARD16 *) (a))) | (*((a)+2) << 16))) +#define Store24(a,v) ((unsigned long) (a) & 1 ? \ + ((*(a) = (CARD8) (v)), \ + (*((CARD16 *) ((a)+1)) = (CARD16) ((v) >> 8))) : \ + ((*((CARD16 *) (a)) = (CARD16) (v)),\ + (*((a)+2) = (CARD8) ((v) >> 16)))) +#endif + #endif /* _ICINT_H_ */ diff --git a/gfx/cairo/libpixman/src/icpixels.c b/gfx/cairo/libpixman/src/icpixels.c index c9b9afc7824f..4518e62b2777 100644 --- a/gfx/cairo/libpixman/src/icpixels.c +++ b/gfx/cairo/libpixman/src/icpixels.c @@ -1,5 +1,5 @@ /* - * $Id: icpixels.c,v 1.3 2005/06/04 07:03:28 vladimir%pobox.com Exp $ + * $Id: icpixels.c,v 1.8 2006/02/03 04:49:30 vladimir%pobox.com Exp $ * * Copyright © 1998 Keith Packard * @@ -22,10 +22,10 @@ * PERFORMANCE OF THIS SOFTWARE. */ -#include "icint.h" +#include "pixman-xserver-compat.h" static void -IcPixelsInit (IcPixels *pixels, pixman_bits_t *buf, int width, int height, int depth, int bpp, int stride); +FbPixelsInit (FbPixels *pixels, pixman_bits_t *buf, int width, int height, int depth, int bpp, int stride); static unsigned int pixman_bits_per_pixel (unsigned int depth); @@ -47,10 +47,10 @@ pixman_bits_per_pixel (unsigned int depth) return 1; } -IcPixels * -IcPixelsCreate (int width, int height, int depth) +FbPixels * +FbPixelsCreate (int width, int height, int depth) { - IcPixels *pixels; + FbPixels *pixels; pixman_bits_t *buf; unsigned int buf_size; unsigned int bpp; @@ -59,9 +59,9 @@ IcPixelsCreate (int width, int height, int depth) unsigned int base; bpp = pixman_bits_per_pixel (depth); - stride = ((width * bpp + IC_MASK) >> IC_SHIFT) * sizeof (pixman_bits_t); + stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (pixman_bits_t); buf_size = height * stride; - base = sizeof (IcPixels); + base = sizeof (FbPixels); adjust = 0; if (base & 7) adjust = 8 - (base & 7); @@ -73,27 +73,27 @@ IcPixelsCreate (int width, int height, int depth) buf = (pixman_bits_t *) ((char *)pixels + base + adjust); - IcPixelsInit (pixels, buf, width, height, depth, bpp, stride); + FbPixelsInit (pixels, buf, width, height, depth, bpp, stride); return pixels; } -IcPixels * -IcPixelsCreateForData (pixman_bits_t *data, int width, int height, int depth, int bpp, int stride) +FbPixels * +FbPixelsCreateForData (pixman_bits_t *data, int width, int height, int depth, int bpp, int stride) { - IcPixels *pixels; + FbPixels *pixels; - pixels = malloc (sizeof (IcPixels)); + pixels = malloc (sizeof (FbPixels)); if (pixels == NULL) return NULL; - IcPixelsInit (pixels, data, width, height, depth, bpp, stride); + FbPixelsInit (pixels, data, width, height, depth, bpp, stride); return pixels; } static void -IcPixelsInit (IcPixels *pixels, pixman_bits_t *buf, int width, int height, int depth, int bpp, int stride) +FbPixelsInit (FbPixels *pixels, pixman_bits_t *buf, int width, int height, int depth, int bpp, int stride) { pixels->data = buf; pixels->width = width; @@ -107,7 +107,7 @@ IcPixelsInit (IcPixels *pixels, pixman_bits_t *buf, int width, int height, int d } void -IcPixelsDestroy (IcPixels *pixels) +FbPixelsDestroy (FbPixels *pixels) { if(--pixels->refcnt) return; diff --git a/gfx/cairo/libpixman/src/icrect.c b/gfx/cairo/libpixman/src/icrect.c index 996eb4f39dc6..95306790c03c 100644 --- a/gfx/cairo/libpixman/src/icrect.c +++ b/gfx/cairo/libpixman/src/icrect.c @@ -30,6 +30,77 @@ typedef void (*FillFunc) (pixman_image_t *dst, pixman_bits_t *pixel); +static void +pixman_fill_rect_1bpp (pixman_image_t *dst, + int16_t xDst, + int16_t yDst, + uint16_t width, + uint16_t height, + pixman_bits_t *pixel) +{ + uint32_t value = *pixel ? 0xffffffff : 0; + char *line; + + line = (char *)dst->pixels->data + + yDst * dst->pixels->stride; + + if ((width + xDst - 1) / 32 == xDst / 32) { + uint32_t mask = 0; + int pos = xDst / 32; + int i; + + for (i = xDst; i < width; i++) +#if BITMAP_BIT_ORDER == MSBFirst + mask |= 1 << (0x1f - i); +#else + mask |= 1 << i; +#endif + + while (height-- > 0) { + uint32_t *cur = (uint32_t *) line; + cur [pos] = (cur [pos] & ~mask) | (value & mask); + line += dst->pixels->stride; + } + } else { + uint32_t smask = 0, emask = 0; + int end = ((xDst + width) / 32); + int i; + + if (xDst % 32) + for (i = (xDst % 32); i < 32; i++) +#if BITMAP_BIT_ORDER == MSBFirst + smask |= 1 << (0x1f - i); +#else + smask |= 1 << i; +#endif + + if ((width + xDst) % 32) + for (i = 0; i < (width + xDst) % 32; i++) +#if BITMAP_BIT_ORDER == MSBFirst + emask |= 1 << (0x1f - i); +#else + emask |= 1 << i; +#endif + + while (height-- > 0) { + uint32_t *cur = (uint32_t *) line; + int start = (xDst / 32); + + if (smask) { + cur [start] = (cur [start] & ~smask) | (value & smask); + start++; + } + + if (emask) + cur [end] = (cur [end] & ~emask) | (value & emask); + + if (end > start) + memset (cur + start, value, (end - start) * 4); + line += dst->pixels->stride; + } + } +} + static void pixman_fill_rect_8bpp (pixman_image_t *dst, int16_t xDst, @@ -174,6 +245,8 @@ pixman_color_rects (pixman_image_t *dst, func = pixman_fill_rect_8bpp; else if (dst->pixels->bpp == 32) func = pixman_fill_rect_32bpp; + else if (dst->pixels->bpp == 1) + func = pixman_fill_rect_1bpp; else func = pixman_fill_rect_general; @@ -247,13 +320,13 @@ pixman_fill_rectangles (pixman_operator_t op, else { pixman_format_t rgbaFormat; - IcPixels *pixels; + FbPixels *pixels; pixman_image_t *src; pixman_bits_t pixel; pixman_format_init (&rgbaFormat, PICT_a8r8g8b8); - pixels = IcPixelsCreate (1, 1, rgbaFormat.depth); + pixels = FbPixelsCreate (1, 1, rgbaFormat.depth); if (!pixels) goto bail1; @@ -286,7 +359,7 @@ pixman_fill_rectangles (pixman_operator_t op, pixman_image_destroy (src); bail2: - IcPixelsDestroy (pixels); + FbPixelsDestroy (pixels); bail1: ; } diff --git a/gfx/cairo/libpixman/src/icrop.h b/gfx/cairo/libpixman/src/icrop.h index 7ea81f15890d..8f17547e8b94 100644 --- a/gfx/cairo/libpixman/src/icrop.h +++ b/gfx/cairo/libpixman/src/icrop.h @@ -26,112 +26,112 @@ #define _ICROP_H_ typedef struct _mergeRopBits { - pixman_bits_t ca1, cx1, ca2, cx2; -} IcMergeRopRec, *IcMergeRopPtr; + FbBits ca1, cx1, ca2, cx2; +} FbMergeRopRec, *FbMergeRopPtr; -extern const IcMergeRopRec IcMergeRopBits[16] pixman_private; +extern const FbMergeRopRec FbMergeRopBits[16] pixman_private; -#define IcDeclareMergeRop() pixman_bits_t _ca1, _cx1, _ca2, _cx2; -#define IcDeclarePrebuiltMergeRop() pixman_bits_t _cca, _ccx; +#define FbDeclareMergeRop() FbBits _ca1, _cx1, _ca2, _cx2; +#define FbDeclarePrebuiltMergeRop() FbBits _cca, _ccx; -#define IcInitializeMergeRop(alu,pm) {\ - const IcMergeRopRec *_bits; \ - _bits = &IcMergeRopBits[alu]; \ +#define FbInitializeMergeRop(alu,pm) {\ + const FbMergeRopRec *_bits; \ + _bits = &FbMergeRopBits[alu]; \ _ca1 = _bits->ca1 & pm; \ _cx1 = _bits->cx1 | ~pm; \ _ca2 = _bits->ca2 & pm; \ _cx2 = _bits->cx2 & pm; \ } -#define IcDestInvarientRop(alu,pm) ((pm) == IC_ALLONES && \ +#define FbDestInvarientRop(alu,pm) ((pm) == FB_ALLONES && \ (((alu) >> 1 & 5) == ((alu) & 5))) -#define IcDestInvarientMergeRop() (_ca1 == 0 && _cx1 == 0) +#define FbDestInvarientMergeRop() (_ca1 == 0 && _cx1 == 0) /* AND has higher precedence than XOR */ -#define IcDoMergeRop(src, dst) \ +#define FbDoMergeRop(src, dst) \ (((dst) & (((src) & _ca1) ^ _cx1)) ^ (((src) & _ca2) ^ _cx2)) -#define IcDoDestInvarientMergeRop(src) (((src) & _ca2) ^ _cx2) +#define FbDoDestInvarientMergeRop(src) (((src) & _ca2) ^ _cx2) -#define IcDoMaskMergeRop(src, dst, mask) \ +#define FbDoMaskMergeRop(src, dst, mask) \ (((dst) & ((((src) & _ca1) ^ _cx1) | ~(mask))) ^ ((((src) & _ca2) ^ _cx2) & (mask))) -#define IcDoLeftMaskByteMergeRop(dst, src, lb, l) { \ - pixman_bits_t __xor = ((src) & _ca2) ^ _cx2; \ - IcDoLeftMaskByteRRop(dst,lb,l,((src) & _ca1) ^ _cx1,__xor); \ +#define FbDoLeftMaskByteMergeRop(dst, src, lb, l) { \ + FbBits __xor = ((src) & _ca2) ^ _cx2; \ + FbDoLeftMaskByteRRop(dst,lb,l,((src) & _ca1) ^ _cx1,__xor); \ } -#define IcDoRightMaskByteMergeRop(dst, src, rb, r) { \ - pixman_bits_t __xor = ((src) & _ca2) ^ _cx2; \ - IcDoRightMaskByteRRop(dst,rb,r,((src) & _ca1) ^ _cx1,__xor); \ +#define FbDoRightMaskByteMergeRop(dst, src, rb, r) { \ + FbBits __xor = ((src) & _ca2) ^ _cx2; \ + FbDoRightMaskByteRRop(dst,rb,r,((src) & _ca1) ^ _cx1,__xor); \ } -#define IcDoRRop(dst, and, xor) (((dst) & (and)) ^ (xor)) +#define FbDoRRop(dst, and, xor) (((dst) & (and)) ^ (xor)) -#define IcDoMaskRRop(dst, and, xor, mask) \ +#define FbDoMaskRRop(dst, and, xor, mask) \ (((dst) & ((and) | ~(mask))) ^ (xor & mask)) /* * Take a single bit (0 or 1) and generate a full mask */ -#define IcFillFromBit(b,t) (~((t) ((b) & 1)-1)) +#define fbFillFromBit(b,t) (~((t) ((b) & 1)-1)) -#define IcXorT(rop,fg,pm,t) ((((fg) & IcFillFromBit((rop) >> 1,t)) | \ - (~(fg) & IcFillFromBit((rop) >> 3,t))) & (pm)) +#define fbXorT(rop,fg,pm,t) ((((fg) & fbFillFromBit((rop) >> 1,t)) | \ + (~(fg) & fbFillFromBit((rop) >> 3,t))) & (pm)) -#define IcAndT(rop,fg,pm,t) ((((fg) & IcFillFromBit (rop ^ (rop>>1),t)) | \ - (~(fg) & IcFillFromBit((rop>>2) ^ (rop>>3),t))) | \ +#define fbAndT(rop,fg,pm,t) ((((fg) & fbFillFromBit (rop ^ (rop>>1),t)) | \ + (~(fg) & fbFillFromBit((rop>>2) ^ (rop>>3),t))) | \ ~(pm)) -#define IcXor(rop,fg,pm) IcXorT(rop,fg,pm,pixman_bits_t) +#define fbXor(rop,fg,pm) fbXorT(rop,fg,pm,FbBits) -#define IcAnd(rop,fg,pm) IcAndT(rop,fg,pm,pixman_bits_t) +#define fbAnd(rop,fg,pm) fbAndT(rop,fg,pm,FbBits) -#define IcXorStip(rop,fg,pm) IcXorT(rop,fg,pm,IcStip) +#define fbXorStip(rop,fg,pm) fbXorT(rop,fg,pm,FbStip) -#define IcAndStip(rop,fg,pm) IcAndT(rop,fg,pm,IcStip) +#define fbAndStip(rop,fg,pm) fbAndT(rop,fg,pm,FbStip) /* * Stippling operations; */ /* half of table */ -extern const pixman_bits_t icStipple16Bits[256] pixman_private; -#define IcStipple16Bits(b) \ - (icStipple16Bits[(b)&0xff] | icStipple16Bits[(b) >> 8] << IC_HALFUNIT) +extern const pixman_bits_t fbStipple16Bits[256] pixman_private; +#define FbStipple16Bits(b) \ + (fbStipple16Bits[(b)&0xff] | fbStipple16Bits[(b) >> 8] << FB_HALFUNIT) pixman_private const pixman_bits_t * -IcStippleTable(int bits); +fbStippleTable(int bits); -#define IcStippleRRop(dst, b, fa, fx, ba, bx) \ - (IcDoRRop(dst, fa, fx) & b) | (IcDoRRop(dst, ba, bx) & ~b) +#define FbStippleRRop(dst, b, fa, fx, ba, bx) \ + (FbDoRRop(dst, fa, fx) & b) | (FbDoRRop(dst, ba, bx) & ~b) -#define IcStippleRRopMask(dst, b, fa, fx, ba, bx, m) \ - (IcDoMaskRRop(dst, fa, fx, m) & (b)) | (IcDoMaskRRop(dst, ba, bx, m) & ~(b)) +#define FbStippleRRopMask(dst, b, fa, fx, ba, bx, m) \ + (FbDoMaskRRop(dst, fa, fx, m) & (b)) | (FbDoMaskRRop(dst, ba, bx, m) & ~(b)) -#define IcDoLeftMaskByteStippleRRop(dst, b, fa, fx, ba, bx, lb, l) { \ - pixman_bits_t __xor = ((fx) & (b)) | ((bx) & ~(b)); \ - IcDoLeftMaskByteRRop(dst, lb, l, ((fa) & (b)) | ((ba) & ~(b)), __xor); \ +#define FbDoLeftMaskByteStippleRRop(dst, b, fa, fx, ba, bx, lb, l) { \ + FbBits __xor = ((fx) & (b)) | ((bx) & ~(b)); \ + FbDoLeftMaskByteRRop(dst, lb, l, ((fa) & (b)) | ((ba) & ~(b)), __xor); \ } -#define IcDoRightMaskByteStippleRRop(dst, b, fa, fx, ba, bx, rb, r) { \ - pixman_bits_t __xor = ((fx) & (b)) | ((bx) & ~(b)); \ - IcDoRightMaskByteRRop(dst, rb, r, ((fa) & (b)) | ((ba) & ~(b)), __xor); \ +#define FbDoRightMaskByteStippleRRop(dst, b, fa, fx, ba, bx, rb, r) { \ + FbBits __xor = ((fx) & (b)) | ((bx) & ~(b)); \ + FbDoRightMaskByteRRop(dst, rb, r, ((fa) & (b)) | ((ba) & ~(b)), __xor); \ } -#define IcOpaqueStipple(b, fg, bg) (((fg) & (b)) | ((bg) & ~(b))) +#define FbOpaqueStipple(b, fg, bg) (((fg) & (b)) | ((bg) & ~(b))) /* * Compute rop for using tile code for 1-bit dest stipples; modifies * existing rop to flip depending on pixel values */ -#define IcStipple1RopPick(alu,b) (((alu) >> (2 - (((b) & 1) << 1))) & 3) +#define FbStipple1RopPick(alu,b) (((alu) >> (2 - (((b) & 1) << 1))) & 3) -#define IcOpaqueStipple1Rop(alu,fg,bg) (IcStipple1RopPick(alu,fg) | \ - (IcStipple1RopPick(alu,bg) << 2)) +#define FbOpaqueStipple1Rop(alu,fg,bg) (FbStipple1RopPick(alu,fg) | \ + (FbStipple1RopPick(alu,bg) << 2)) -#define IcStipple1Rop(alu,fg) (IcStipple1RopPick(alu,fg) | 4) +#define FbStipple1Rop(alu,fg) (FbStipple1RopPick(alu,fg) | 4) #endif diff --git a/gfx/cairo/libpixman/src/icstipple.c b/gfx/cairo/libpixman/src/icstipple.c index 121bbaa86811..e077cbb0b193 100644 --- a/gfx/cairo/libpixman/src/icstipple.c +++ b/gfx/cairo/libpixman/src/icstipple.c @@ -22,7 +22,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -#include "icint.h" +#include "pixman-xserver-compat.h" #ifndef ICNOPIXADDR /* @@ -31,7 +31,7 @@ * transparent stipple */ #define LaneCases1(c,a) case c: \ - while (n--) { (void)IcLaneCase(c,a); a++; } \ + while (n--) { (void)FbLaneCase(c,a); a++; } \ break #define LaneCases2(c,a) LaneCases1(c,a); LaneCases1(c+1,a) #define LaneCases4(c,a) LaneCases2(c,a); LaneCases2(c+2,a) @@ -42,11 +42,11 @@ #define LaneCases128(c,a) LaneCases64(c,a); LaneCases64(c+64,a) #define LaneCases256(c,a) LaneCases128(c,a); LaneCases128(c+128,a) -#if IC_SHIFT == 6 +#if FB_SHIFT == 6 #define LaneCases(a) LaneCases256(0,a) #endif -#if IC_SHIFT == 5 +#if FB_SHIFT == 5 #define LaneCases(a) LaneCases16(0,a) #endif @@ -55,22 +55,22 @@ */ void -IcTransparentSpan (pixman_bits_t *dst, - pixman_bits_t stip, - pixman_bits_t fgxor, +fbTransparentSpan (FbBits *dst, + FbBits stip, + FbBits fgxor, int n) { - IcStip s; + FbStip s; - s = ((IcStip) (stip ) & 0x01); - s |= ((IcStip) (stip >> 8) & 0x02); - s |= ((IcStip) (stip >> 16) & 0x04); - s |= ((IcStip) (stip >> 24) & 0x08); -#if IC_SHIFT > 5 - s |= ((IcStip) (stip >> 32) & 0x10); - s |= ((IcStip) (stip >> 40) & 0x20); - s |= ((IcStip) (stip >> 48) & 0x40); - s |= ((IcStip) (stip >> 56) & 0x80); + s = ((FbStip) (stip ) & 0x01); + s |= ((FbStip) (stip >> 8) & 0x02); + s |= ((FbStip) (stip >> 16) & 0x04); + s |= ((FbStip) (stip >> 24) & 0x08); +#if FB_SHIFT > 5 + s |= ((FbStip) (stip >> 32) & 0x10); + s |= ((FbStip) (stip >> 40) & 0x20); + s |= ((FbStip) (stip >> 48) & 0x40); + s |= ((FbStip) (stip >> 56) & 0x80); #endif switch (s) { LaneCases(dst); diff --git a/gfx/cairo/libpixman/src/ictrap.c b/gfx/cairo/libpixman/src/ictrap.c index fe008461b8da..ecc8434e3af5 100644 --- a/gfx/cairo/libpixman/src/ictrap.c +++ b/gfx/cairo/libpixman/src/ictrap.c @@ -1,5 +1,5 @@ /* - * $Id: ictrap.c,v 1.3 2005/06/04 07:03:28 vladimir%pobox.com Exp $ + * $Id: ictrap.c,v 1.4 2005/08/20 05:34:02 vladimir%pobox.com Exp $ * * Copyright © 2002 Keith Packard * @@ -25,7 +25,7 @@ #include "icint.h" pixman_image_t * -IcCreateAlphaPicture (pixman_image_t *dst, +FbCreateAlphaPicture (pixman_image_t *dst, pixman_format_t *format, uint16_t width, uint16_t height) @@ -167,7 +167,7 @@ pixman_composite_trapezoids (pixman_operator_t op, if (!format) return; - image = IcCreateAlphaPicture (dst, format, + image = FbCreateAlphaPicture (dst, format, bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); if (!image) diff --git a/gfx/cairo/libpixman/src/ictri.c b/gfx/cairo/libpixman/src/ictri.c index 97fbca54491e..27deb3ca4d09 100644 --- a/gfx/cairo/libpixman/src/ictri.c +++ b/gfx/cairo/libpixman/src/ictri.c @@ -57,7 +57,7 @@ pixman_triangle_bounds (int ntri, const pixman_triangle_t *tris, pixman_box16_t } static void -IcRasterizeTriangle (pixman_image_t *image, +FbRasterizeTriangle (pixman_image_t *image, const pixman_triangle_t *tri, int x_off, int y_off) @@ -159,7 +159,7 @@ pixman_composite_triangles (pixman_operator_t op, pixman_triangle_bounds (ntris, tris, &bounds); if (bounds.x2 <= bounds.x1 || bounds.y2 <= bounds.y1) return; - image = IcCreateAlphaPicture (dst, + image = FbCreateAlphaPicture (dst, format, bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); @@ -173,14 +173,14 @@ pixman_composite_triangles (pixman_operator_t op, pixman_triangle_bounds (1, tris, &bounds); if (bounds.x2 <= bounds.x1 || bounds.y2 <= bounds.y1) continue; - image = IcCreateAlphaPicture (dst, + image = FbCreateAlphaPicture (dst, format, bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); if (!image) break; } - IcRasterizeTriangle (image, tris, -bounds.x1, -bounds.y1); + FbRasterizeTriangle (image, tris, -bounds.x1, -bounds.y1); if (!format) { xRel = bounds.x1 + xSrc - xDst; @@ -233,7 +233,7 @@ pixman_composite_tri_strip (pixman_operator_t op, pixman_point_fixed_bounds (npoints, points, &bounds); if (bounds.x2 <= bounds.x1 || bounds.y2 <= bounds.y1) return; - image = IcCreateAlphaPicture (dst, + image = FbCreateAlphaPicture (dst, format, bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); @@ -250,14 +250,14 @@ pixman_composite_tri_strip (pixman_operator_t op, pixman_triangle_bounds (1, &tri, &bounds); if (bounds.x2 <= bounds.x1 || bounds.y2 <= bounds.y1) continue; - image = IcCreateAlphaPicture (dst, + image = FbCreateAlphaPicture (dst, format, bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); if (!image) continue; } - IcRasterizeTriangle (image, &tri, -bounds.x1, -bounds.y1); + FbRasterizeTriangle (image, &tri, -bounds.x1, -bounds.y1); if (!format) { xRel = bounds.x1 + xSrc - xDst; @@ -310,7 +310,7 @@ pixman_composite_tri_fan (pixman_operator_t op, pixman_point_fixed_bounds (npoints, points, &bounds); if (bounds.x2 <= bounds.x1 || bounds.y2 <= bounds.y1) return; - image = IcCreateAlphaPicture (dst, + image = FbCreateAlphaPicture (dst, format, bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); @@ -329,14 +329,14 @@ pixman_composite_tri_fan (pixman_operator_t op, pixman_triangle_bounds (1, &tri, &bounds); if (bounds.x2 <= bounds.x1 || bounds.y2 <= bounds.y1) continue; - image = IcCreateAlphaPicture (dst, + image = FbCreateAlphaPicture (dst, format, bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); if (!image) continue; } - IcRasterizeTriangle (image, &tri, -bounds.x1, -bounds.y1); + FbRasterizeTriangle (image, &tri, -bounds.x1, -bounds.y1); if (!format) { xRel = bounds.x1 + xSrc - xDst; diff --git a/gfx/cairo/libpixman/src/icutil.c b/gfx/cairo/libpixman/src/icutil.c index 549217000bae..f6119df7b050 100644 --- a/gfx/cairo/libpixman/src/icutil.c +++ b/gfx/cairo/libpixman/src/icutil.c @@ -22,15 +22,15 @@ * PERFORMANCE OF THIS SOFTWARE. */ -#include "icint.h" +#include "pixman-xserver-compat.h" pixman_bits_t -IcReplicatePixel (Pixel p, int bpp) +fbReplicatePixel (Pixel p, int bpp) { pixman_bits_t b = p; - b &= IcFullMask (bpp); - while (bpp < IC_UNIT) + b &= FbFullMask (bpp); + while (bpp < FB_UNIT) { b |= b << bpp; bpp <<= 1; @@ -39,9 +39,9 @@ IcReplicatePixel (Pixel p, int bpp) } #define O 0 -#define I IC_ALLONES +#define I FB_ALLONES -const IcMergeRopRec IcMergeRopBits[16] = { +const FbMergeRopRec FbMergeRopBits[16] = { { O,O,O,O }, /* clear 0x0 0 */ { I,O,O,O }, /* and 0x1 src AND dst */ { I,O,I,O }, /* andReverse 0x2 src AND NOT dst */ @@ -62,11 +62,11 @@ const IcMergeRopRec IcMergeRopBits[16] = { /* * Stipple masks are independent of bit/byte order as long - * as bitorder == byteorder. IC doesn't handle the case + * as bitorder == byteorder. FB doesn't handle the case * where these differ */ -#define BitsMask(x,w) ((IC_ALLONES << ((x) & IC_MASK)) & \ - (IC_ALLONES >> ((IC_UNIT - ((x) + (w))) & IC_MASK))) +#define BitsMask(x,w) ((FB_ALLONES << ((x) & FB_MASK)) & \ + (FB_ALLONES >> ((FB_UNIT - ((x) + (w))) & FB_MASK))) #define Mask(x,w) BitsMask((x)*(w),(w)) @@ -96,23 +96,23 @@ const IcMergeRopRec IcMergeRopBits[16] = { SelMask(b,6,w) | \ SelMask(b,7,w)) -#if IC_UNIT == 16 -#define icStipple16Bits 0 -#define icStipple8Bits 0 -static const pixman_bits_t icStipple4Bits[16] = { +#if FB_UNIT == 16 +#define fbStipple16Bits 0 +#define fbStipple8Bits 0 +static const pixman_bits_t fbStipple4Bits[16] = { C4( 0,4), C4( 1,4), C4( 2,4), C4( 3,4), C4( 4,4), C4( 5,4), C4( 6,4), C4( 7,4), C4( 8,4), C4( 9,4), C4( 10,4), C4( 11,4), C4( 12,4), C4( 13,4), C4( 14,4), C4( 15,4),}; -static const pixman_bits_t icStipple2Bits[4] = { +static const pixman_bits_t fbStipple2Bits[4] = { C2( 0,8), C2( 1,8), C2( 2,8), C2( 3,8), }; -static const pixman_bits_t icStipple1Bits[2] = { +static const pixman_bits_t fbStipple1Bits[2] = { C1( 0,16), C1( 1,16), }; #endif -#if IC_UNIT == 32 -#define icStipple16Bits 0 -static const pixman_bits_t icStipple8Bits[256] = { +#if FB_UNIT == 32 +#define fbStipple16Bits 0 +static const pixman_bits_t fbStipple8Bits[256] = { C8( 0,4), C8( 1,4), C8( 2,4), C8( 3,4), C8( 4,4), C8( 5,4), C8( 6,4), C8( 7,4), C8( 8,4), C8( 9,4), C8( 10,4), C8( 11,4), C8( 12,4), C8( 13,4), C8( 14,4), C8( 15,4), C8( 16,4), C8( 17,4), @@ -157,19 +157,19 @@ static const pixman_bits_t icStipple8Bits[256] = { C8(246,4), C8(247,4), C8(248,4), C8(249,4), C8(250,4), C8(251,4), C8(252,4), C8(253,4), C8(254,4), C8(255,4), }; -static const pixman_bits_t icStipple4Bits[16] = { +static const pixman_bits_t fbStipple4Bits[16] = { C4( 0,8), C4( 1,8), C4( 2,8), C4( 3,8), C4( 4,8), C4( 5,8), C4( 6,8), C4( 7,8), C4( 8,8), C4( 9,8), C4( 10,8), C4( 11,8), C4( 12,8), C4( 13,8), C4( 14,8), C4( 15,8),}; -static const pixman_bits_t icStipple2Bits[4] = { +static const pixman_bits_t fbStipple2Bits[4] = { C2( 0,16), C2( 1,16), C2( 2,16), C2( 3,16), }; -static const pixman_bits_t icStipple1Bits[2] = { +static const pixman_bits_t fbStipple1Bits[2] = { C1( 0,32), C1( 1,32), }; #endif -#if IC_UNIT == 64 -const pixman_bits_t icStipple16Bits[256] = { +#if FB_UNIT == 64 +const pixman_bits_t fbStipple16Bits[256] = { C8( 0,4), C8( 1,4), C8( 2,4), C8( 3,4), C8( 4,4), C8( 5,4), C8( 6,4), C8( 7,4), C8( 8,4), C8( 9,4), C8( 10,4), C8( 11,4), C8( 12,4), C8( 13,4), C8( 14,4), C8( 15,4), C8( 16,4), C8( 17,4), @@ -214,7 +214,7 @@ const pixman_bits_t icStipple16Bits[256] = { C8(246,4), C8(247,4), C8(248,4), C8(249,4), C8(250,4), C8(251,4), C8(252,4), C8(253,4), C8(254,4), C8(255,4), }; -static const pixman_bits_t icStipple8Bits[256] = { +static const pixman_bits_t fbStipple8Bits[256] = { C8( 0,8), C8( 1,8), C8( 2,8), C8( 3,8), C8( 4,8), C8( 5,8), C8( 6,8), C8( 7,8), C8( 8,8), C8( 9,8), C8( 10,8), C8( 11,8), C8( 12,8), C8( 13,8), C8( 14,8), C8( 15,8), C8( 16,8), C8( 17,8), @@ -259,28 +259,28 @@ static const pixman_bits_t icStipple8Bits[256] = { C8(246,8), C8(247,8), C8(248,8), C8(249,8), C8(250,8), C8(251,8), C8(252,8), C8(253,8), C8(254,8), C8(255,8), }; -static const pixman_bits_t icStipple4Bits[16] = { +static const pixman_bits_t fbStipple4Bits[16] = { C4( 0,16), C4( 1,16), C4( 2,16), C4( 3,16), C4( 4,16), C4( 5,16), C4( 6,16), C4( 7,16), C4( 8,16), C4( 9,16), C4( 10,16), C4( 11,16), C4( 12,16), C4( 13,16), C4( 14,16), C4( 15,16),}; -static const pixman_bits_t icStipple2Bits[4] = { +static const pixman_bits_t fbStipple2Bits[4] = { C2( 0,32), C2( 1,32), C2( 2,32), C2( 3,32), }; -#define icStipple1Bits 0 +#define fbStipple1Bits 0 #endif const pixman_bits_t * -IcStippleTable(int bits) +fbStippleTable(int bits) { switch (bits) { case 1: - return icStipple1Bits; + return fbStipple1Bits; case 2: - return icStipple2Bits; + return fbStipple2Bits; case 4: - return icStipple4Bits; + return fbStipple4Bits; case 8: - return icStipple8Bits; + return fbStipple8Bits; } return 0; } diff --git a/gfx/cairo/libpixman/src/pixman-remap.h b/gfx/cairo/libpixman/src/pixman-remap.h new file mode 100644 index 000000000000..dd2ba8dc4500 --- /dev/null +++ b/gfx/cairo/libpixman/src/pixman-remap.h @@ -0,0 +1,323 @@ +#define fb16Lane _cairo_pixman_16_lane +#define fb32Lane _cairo_pixman_32_lane +#define fb8Lane _cairo_pixman_8_lane +#define fbAccessMap _cairo_pixman_access_map +#define fbBlt _cairo_pixman_blt +#define fbBlt24 _cairo_pixman_blt24 +#define fbBlt24Line _cairo_pixman_blt24_line +#define fbBltOne _cairo_pixman_blt_one +#define fbBltOne24 _cairo_pixman_blt_one24 +#define fbBltStip _cairo_pixman_blt_stip +#define fbBuildCompositeOperand _cairo_pixman_build_composite_operand +#define fbCombineAddC _cairo_pixman_combine_add_c +#define fbCombineAddU _cairo_pixman_combine_add_u +#define fbCombineAtopC _cairo_pixman_combine_atop_c +#define fbCombineAtopReverseC _cairo_pixman_combine_atop_reverse_c +#define fbCombineAtopReverseU _cairo_pixman_combine_atop_reverse_u +#define fbCombineAtopU _cairo_pixman_combine_atop_u +#define fbCombineClear _cairo_pixman_combine_clear +#define fbCombineClearC _cairo_pixman_combine_clear_c +#define fbCombineConjointAtopC _cairo_pixman_combine_conjoint_atop_c +#define fbCombineConjointAtopReverseC _cairo_pixman_combine_conjoint_atop_reverse_c +#define fbCombineConjointAtopReverseU _cairo_pixman_combine_conjoint_atop_reverse_u +#define fbCombineConjointAtopU _cairo_pixman_combine_conjoint_atop_u +#define fbCombineConjointGeneralC _cairo_pixman_combine_conjoint_general_c +#define fbCombineConjointGeneralU _cairo_pixman_combine_conjoint_general_u +#define fbCombineConjointInC _cairo_pixman_combine_conjoint_in_c +#define fbCombineConjointInPart _cairo_pixman_combine_conjoint_in_part +#define fbCombineConjointInReverseC _cairo_pixman_combine_conjoint_in_reverse_c +#define fbCombineConjointInReverseU _cairo_pixman_combine_conjoint_in_reverse_u +#define fbCombineConjointInU _cairo_pixman_combine_conjoint_in_u +#define fbCombineConjointOutC _cairo_pixman_combine_conjoint_out_c +#define fbCombineConjointOutPart _cairo_pixman_combine_conjoint_out_part +#define fbCombineConjointOutReverseC _cairo_pixman_combine_conjoint_out_reverse_c +#define fbCombineConjointOutReverseU _cairo_pixman_combine_conjoint_out_reverse_u +#define fbCombineConjointOutU _cairo_pixman_combine_conjoint_out_u +#define fbCombineConjointOverC _cairo_pixman_combine_conjoint_over_c +#define fbCombineConjointOverReverseC _cairo_pixman_combine_conjoint_over_reverse_c +#define fbCombineConjointOverReverseU _cairo_pixman_combine_conjoint_over_reverse_u +#define fbCombineConjointOverU _cairo_pixman_combine_conjoint_over_u +#define fbCombineConjointXorC _cairo_pixman_combine_conjoint_xor_c +#define fbCombineConjointXorU _cairo_pixman_combine_conjoint_xor_u +#define fbCombineDisjointAtopC _cairo_pixman_combine_disjoint_atop_c +#define fbCombineDisjointAtopReverseC _cairo_pixman_combine_disjoint_atop_reverse_c +#define fbCombineDisjointAtopReverseU _cairo_pixman_combine_disjoint_atop_reverse_u +#define fbCombineDisjointAtopU _cairo_pixman_combine_disjoint_atop_u +#define fbCombineDisjointGeneralC _cairo_pixman_combine_disjoint_general_c +#define fbCombineDisjointGeneralU _cairo_pixman_combine_disjoint_general_u +#define fbCombineDisjointInC _cairo_pixman_combine_disjoint_in_c +#define fbCombineDisjointInPart _cairo_pixman_combine_disjoint_in_part +#define fbCombineDisjointInReverseC _cairo_pixman_combine_disjoint_in_reverse_c +#define fbCombineDisjointInReverseU _cairo_pixman_combine_disjoint_in_reverse_u +#define fbCombineDisjointInU _cairo_pixman_combine_disjoint_in_u +#define fbCombineDisjointOutC _cairo_pixman_combine_disjoint_out_c +#define fbCombineDisjointOutPart _cairo_pixman_combine_disjoint_out_part +#define fbCombineDisjointOutReverseC _cairo_pixman_combine_disjoint_out_reverse_c +#define fbCombineDisjointOutReverseU _cairo_pixman_combine_disjoint_out_reverse_u +#define fbCombineDisjointOutU _cairo_pixman_combine_disjoint_out_u +#define fbCombineDisjointOverC _cairo_pixman_combine_disjoint_over_c +#define fbCombineDisjointOverReverseC _cairo_pixman_combine_disjoint_over_reverse_c +#define fbCombineDisjointOverReverseU _cairo_pixman_combine_disjoint_over_reverse_u +#define fbCombineDisjointOverU _cairo_pixman_combine_disjoint_over_u +#define fbCombineDisjointXorC _cairo_pixman_combine_disjoint_xor_c +#define fbCombineDisjointXorU _cairo_pixman_combine_disjoint_xor_u +#define fbCombineDst _cairo_pixman_combine_dst +#define fbCombineFuncC _cairo_pixman_combine_func_c +#define fbCombineFuncU _cairo_pixman_combine_func_u +#define fbCombineInC _cairo_pixman_combine_in_c +#define fbCombineInReverseC _cairo_pixman_combine_in_reverse_c +#define fbCombineInReverseU _cairo_pixman_combine_in_reverse_u +#define fbCombineInU _cairo_pixman_combine_in_u +#define fbCombineMaskAlphaC _cairo_pixman_combine_mask_alpha_c +#define fbCombineMaskAlphaU _cairo_pixman_combine_mask_alpha_u +#define fbCombineMaskC _cairo_pixman_combine_mask_c +#define fbCombineMaskU _cairo_pixman_combine_mask_u +#define fbCombineMaskValueC _cairo_pixman_combine_mask_value_c +#define fbCombineOutC _cairo_pixman_combine_out_c +#define fbCombineOutReverseC _cairo_pixman_combine_out_reverse_c +#define fbCombineOutReverseU _cairo_pixman_combine_out_reverse_u +#define fbCombineOutU _cairo_pixman_combine_out_u +#define fbCombineOverC _cairo_pixman_combine_over_c +#define fbCombineOverReverseC _cairo_pixman_combine_over_reverse_c +#define fbCombineOverReverseU _cairo_pixman_combine_over_reverse_u +#define fbCombineOverU _cairo_pixman_combine_over_u +#define fbCombineSaturateC _cairo_pixman_combine_saturate_c +#define fbCombineSaturateU _cairo_pixman_combine_saturate_u +#define fbCombineSrcC _cairo_pixman_combine_src_c +#define fbCombineSrcU _cairo_pixman_combine_src_u +#define fbCombineXorC _cairo_pixman_combine_xor_c +#define fbCombineXorU _cairo_pixman_combine_xor_u +#define fbComposeSetupMMX _cairo_pixman_compose_setup_mmx +#define fbCompositeCopyAreammx _cairo_pixman_composite_copy_area_mmx +#define fbCompositeSolidMaskSrc_nx8x8888mmx _cairo_pixman_composite_solid_mask_src_nx8x8888mmx +#define fbCompositeSolidMask_nx8888x0565Cmmx _cairo_pixman_composite_solid_mask_nx8888x0565Cmmx +#define fbCompositeSolidMask_nx8888x8888Cmmx _cairo_pixman_composite_solid_mask_nx8888x8888Cmmx +#define fbCompositeSolidMask_nx8x0565mmx _cairo_pixman_composite_solid_mask_nx8x0565mmx +#define fbCompositeSolidMask_nx8x8888mmx _cairo_pixman_composite_solid_mask_nx8x8888mmx +#define fbCompositeSolid_nx0565mmx _cairo_pixman_composite_solid_nx0565mmx +#define fbCompositeSolid_nx8888mmx _cairo_pixman_composite_solid_nx8888mmx +#define fbCompositeSrcAdd_8000x8000mmx _cairo_pixman_composite_src_add_8000x8000mmx +#define fbCompositeSrcAdd_8888x8888mmx _cairo_pixman_composite_src_add_8888x8888mmx +#define fbCompositeSrc_8888RevNPx0565mmx _cairo_pixman_composite_src_8888RevNPx0565mmx +#define fbCompositeSrc_8888RevNPx8888mmx _cairo_pixman_composite_src_8888RevNPx8888_mmx +#define fbCompositeSrc_8888x8888mmx _cairo_pixman_composite_src_8888x8888mmx +#define fbCompositeSrc_8888x8x8888mmx _cairo_pixman_composite_src_8888x8x8888mmx +#define fbCompositeSrc_x888x8x8888mmx _cairo_pixman_composite_src_x888x8x8888mmx +#define fbCopyAreammx _cairo_pixman_copy_area_mmx +#define fbHaveMMX _cairo_pixman_have_mmx +#define fbSolidFillmmx _cairo_pixman_solid_fill_mmx +#define fbCompositeSolidMask_nx1xn _cairo_pixman_composite_solid_mask_nx1xn +#define fbCompositeSolidMask_nx8888x0565 _cairo_pixman_composite_solid_mask_nx8888x0565 +#define fbCompositeSolidMask_nx8888x0565C _cairo_pixman_composite_solid_mask_nx8888x0565_c +#define fbCompositeSolidMask_nx8888x8888C _cairo_pixman_composite_solid_mask_nx8888x8888_c +#define fbCompositeSolidMask_nx8x0565 _cairo_pixman_composite_solid_mask_nx8x0565 +#define fbCompositeSolidMask_nx8x0888 _cairo_pixman_composite_solid_mask_nx8x0888 +#define fbCompositeSolidMask_nx8x8888 _cairo_pixman_composite_solid_mask_nx8x8888 +#define fbCompositeSrc_0565x0565 _cairo_pixman_composite_src_0565x0565 +#define fbCompositeSrc_8888x0565 _cairo_pixman_composite_src_8888x0565 +#define fbCompositeSrc_8888x0888 _cairo_pixman_composite_src_8888x0888 +#define fbCompositeSrc_8888x8888 _cairo_pixman_composite_src_8888x8888 +#define fbCompositeSrcAdd_1000x1000 _cairo_pixman_composite_src_add_1000x1000 +#define fbCompositeSrcAdd_8000x8000 _cairo_pixman_composite_src_add_8000x8000 +#define fbCompositeSrcAdd_8888x8888 _cairo_pixman_composite_src_add_8888x8888 +#define fbCompositeSrcSrc_nxn _cairo_pixman_composite_src_src_nxn +#define fbCompositeTrans_0565xnx0565 _cairo_pixman_composite_trans_0565xnx0565 +#define fbCompositeTrans_0888xnx0888 _cairo_pixman_composite_trans_0888xnx0888 +#define FbComputeCompositeRegion _cairo_pixman_compute_composite_region +#define FbCreateAlphaPicture _cairo_pixman_create_alpha_picture +#define fbFetch_a1 _cairo_pixman_fetch_a1 +#define fbFetch_a1b1g1r1 _cairo_pixman_fetch_a1b1g1r1 +#define fbFetch_a1b5g5r5 _cairo_pixman_fetch_a1b5g5r5 +#define fbFetch_a1r1g1b1 _cairo_pixman_fetch_a1r1g1b1 +#define fbFetch_a1r5g5b5 _cairo_pixman_fetch_a1r5g5b5 +#define fbFetch_a2r2g2b2 _cairo_pixman_fetch_a2r2g2b2 +#define fbFetch_a4 _cairo_pixman_fetch_a4 +#define fbFetch_a4b4g4r4 _cairo_pixman_fetch_a4b4g4r4 +#define fbFetch_a4r4g4b4 _cairo_pixman_fetch_a4r4g4b4 +#define fbFetch_a8 _cairo_pixman_fetch_a8 +#define fbFetch_a8b8g8r8 _cairo_pixman_fetch_a8b8g8r8 +#define fbFetch_a8r8g8b8 _cairo_pixman_fetch_a8r8g8b8 +#define fbFetcha_a1 _cairo_pixman_fetcha_a1 +#define fbFetcha_a4 _cairo_pixman_fetcha_a4 +#define fbFetcha_a8 _cairo_pixman_fetcha_a8 +#define fbFetcha_external _cairo_pixman_fetcha_external +#define fbFetcha_transform _cairo_pixman_fetcha_transform +#define fbFetch_b1g2r1 _cairo_pixman_fetch_b1g2r1 +#define fbFetch_b2g3r3 _cairo_pixman_fetch_b2g3r3 +#define fbFetch_b5g6r5 _cairo_pixman_fetch_b5g6r5 +#define fbFetch_b8g8r8 _cairo_pixman_fetch_b8g8r8 +#define fbFetch_external _cairo_pixman_fetch_external +#define fbFetch_r1g2b1 _cairo_pixman_fetch_r1g2b1 +#define fbFetch_r3g3b2 _cairo_pixman_fetch_r3g3b2 +#define fbFetch_r5g6b5 _cairo_pixman_fetch_r5g6b5 +#define fbFetch_r8g8b8 _cairo_pixman_fetch_r8g8b8 +#define fbFetch_transform _cairo_pixman_fetch_transform +#define fbFetch_x1b5g5r5 _cairo_pixman_fetch_x1b5g5r5 +#define fbFetch_x1r5g5b5 _cairo_pixman_fetch_x1r5g5b5 +#define fbFetch_x4b4g4r4 _cairo_pixman_fetch_x4b4g4r4 +#define fbFetch_x4r4g4b4 _cairo_pixman_fetch_x4r4g4b4 +#define fbFetch_x8b8g8r8 _cairo_pixman_fetch_x8b8g8r8 +#define fbFetch_x8r8g8b8 _cairo_pixman_fetch_x8r8g8b8 +#define FbFillColor _cairo_pixman_fill_color +#define fbIn _cairo_pixman_in +#define fbIn24 _cairo_pixman_in24 +#define fbLaneTable _cairo_pixman_lane_table +#define FbMergeRopBits _cairo_pixman_merge_rop_bits +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#else +#define _FbOnes _cairo_pixman_ones +#endif +#define fbOver _cairo_pixman_over +#define fbOver24 _cairo_pixman_over24 +#define FbPixelsCreate _cairo_pixman_pixels_create +#define FbPixelsCreateForData _cairo_pixman_pixels_create_for_data +#define FbPixelsDestroy _cairo_pixman_pixels_destroy +#define FbPixelsInit _cairo_pixman_pixels_init +#define fbRasterizeEdges _cairo_pixman_rasterize_edges +#define fbRasterizeEdges1 _cairo_pixman_rasterize_edges1 +#define fbRasterizeEdges4 _cairo_pixman_rasterize_edges4 +#define fbRasterizeEdges8 _cairo_pixman_rasterize_edges8 +#define fbRasterizeTrapezoid _cairo_pixman_rasterize_trapezoid +#define FbRasterizeTriangle _cairo_pixman_rasterize_triangle +#define fbReplicatePixel _cairo_pixman_replicate_pixel +#define fbSet _cairo_pixman_set +#define fbSet_external _cairo_pixman_set_external +#define fbSet_transform _cairo_pixman_set_transform +#define fbStepDown _cairo_pixman_step_down +#define fbStepDown_external _cairo_pixman_step_down_external +#define fbStepDown_transform _cairo_pixman_step_down_transform +#define fbStepOver _cairo_pixman_step_over +#define fbStepOver_external _cairo_pixman_step_over_external +#define fbStepOver_transform _cairo_pixman_step_over_transform +#define fbStipple1Bits _cairo_pixman_stipple1_bits +#define fbStipple24Bits _cairo_pixman_stipple24_bits +#define fbStipple2Bits _cairo_pixman_stipple2_bits +#define fbStipple4Bits _cairo_pixman_stipple4_bits +#define fbStipple8Bits _cairo_pixman_stipple8_bits +#define fbStippleTable _cairo_pixman_stipple_table +#define fbStore_a1 _cairo_pixman_store_a1 +#define fbStore_a1b1g1r1 _cairo_pixman_store_a1b1g1r1 +#define fbStore_a1b5g5r5 _cairo_pixman_store_a1b5g5r5 +#define fbStore_a1r1g1b1 _cairo_pixman_store_a1r1g1b1 +#define fbStore_a1r5g5b5 _cairo_pixman_store_a1r5g5b5 +#define fbStore_a2r2g2b2 _cairo_pixman_store_a2r2g2b2 +#define fbStore_a4 _cairo_pixman_store_a4 +#define fbStore_a4b4g4r4 _cairo_pixman_store_a4b4g4r4 +#define fbStore_a4r4g4b4 _cairo_pixman_store_a4r4g4b4 +#define fbStore_a8 _cairo_pixman_store_a8 +#define fbStore_a8b8g8r8 _cairo_pixman_store_a8b8g8r8 +#define fbStore_a8r8g8b8 _cairo_pixman_store_a8r8g8b8 +#define fbStore_b1g2r1 _cairo_pixman_store_b1g2r1 +#define fbStore_b2g3r3 _cairo_pixman_store_b2g3r3 +#define fbStore_b5g6r5 _cairo_pixman_store_b5g6r5 +#define fbStore_b8g8r8 _cairo_pixman_store_b8g8r8 +#define fbStore_external _cairo_pixman_store_external +#define fbStore_r1g2b1 _cairo_pixman_store_r1g2b1 +#define fbStore_r3g3b2 _cairo_pixman_store_r3g3b2 +#define fbStore_r5g6b5 _cairo_pixman_store_r5g6b5 +#define fbStore_r8g8b8 _cairo_pixman_store_r8g8b8 +#define fbStore_x1b5g5r5 _cairo_pixman_store_x1b5g5r5 +#define fbStore_x1r5g5b5 _cairo_pixman_store_x1r5g5b5 +#define fbStore_x4b4g4r4 _cairo_pixman_store_x4b4g4r4 +#define fbStore_x4r4g4b4 _cairo_pixman_store_x4r4g4b4 +#define fbStore_x8b8g8r8 _cairo_pixman_store_x8b8g8r8 +#define fbStore_x8r8g8b8 _cairo_pixman_store_x8r8g8b8 +#define fbTransparentSpan _cairo_pixman_transparent_span +#define INT_pixman_color_to_pixel _cairo_pixman_color_to_pixel +#define INT_pixman_composite _cairo_pixman_composite +#define pixman_fill_rectangles _cairo_pixman_fill_rectangles +#define pixman_format_init _cairo_pixman_format_init +#define pixman_image_create _cairo_pixman_image_create +#define pixman_image_destroy _cairo_pixman_image_destroy +#define pixman_image_set_component_alpha _cairo_pixman_image_set_component_alpha +#define pixman_image_set_repeat _cairo_pixman_image_set_repeat +#define pixman_region_copy _cairo_pixman_region_copy +#define pixman_region_create_simple _cairo_pixman_region_create_simple +#define pixman_region_union _cairo_pixman_region_union +#define miIsSolidAlpha _cairo_pixman_is_solid_alpha +#define pixman_add_trapezoids _cairo_pixman_add_trapezoids +#define pixman_bits_per_pixel _cairo_pixman_bits_per_pixel +#define pixman_break _cairo_pixman_break +#define pixman_brokendata _cairo_pixman_brokendata +#define pixman_brokenregion _cairo_pixman_brokenregion +#define pixman_coalesce _cairo_pixman_coalesce +#define pixman_color_rects _cairo_pixman_color_rects +#define pixman_color_to_pixel _cairo_pixman_color_to_pixel +#define pixman_composite _cairo_pixman_composite +#define pixman_compositeGeneral _cairo_pixman_composite_general +#define pixman_composite_trapezoids _cairo_pixman_composite_trapezoids +#define pixman_composite_triangles _cairo_pixman_composite_triangles +#define pixman_composite_tri_fan _cairo_pixman_composite_tri_fan +#define pixman_composite_tri_strip _cairo_pixman_composite_tri_strip +#define pixman_fill_rect_32bpp _cairo_pixman_fill_rect_32bpp +#define pixman_fill_rect_8bpp _cairo_pixman_fill_rect_8bpp +#define pixman_fill_rectangle _cairo_pixman_fill_rectangle +#define pixman_fill_rectangles _cairo_pixman_fill_rectangles +#define pixman_fill_rect_general _cairo_pixman_fill_rect_general +#define pixman_format_create _cairo_pixman_format_create +#define pixman_format_create_masks _cairo_pixman_format_create_masks +#define pixman_format_destroy _cairo_pixman_format_destroy +#define pixman_format_get_masks _cairo_pixman_format_get_masks +#define pixman_format_init _cairo_pixman_format_init +#define pixman_image_create _cairo_pixman_image_create +#define pixman_image_create_for_data _cairo_pixman_image_create_for_data +#define pixman_image_createForPixels _cairo_pixman_image_create_for_pixels +#define pixman_image_destroy _cairo_pixman_image_destroy +#define pixman_image_destroyClip _cairo_pixman_image_destroy_clip +#define pixman_image_get_data _cairo_pixman_image_get_data +#define pixman_image_get_depth _cairo_pixman_image_get_depth +#define pixman_image_get_format _cairo_pixman_image_get_format +#define pixman_image_get_height _cairo_pixman_image_get_height +#define pixman_image_get_stride _cairo_pixman_image_get_stride +#define pixman_image_get_width _cairo_pixman_image_get_width +#define pixman_image_init _cairo_pixman_image_init +#define pixman_image_set_clip_region _cairo_pixman_image_set_clip_region +#define pixman_image_set_component_alpha _cairo_pixman_image_set_component_alpha +#define pixman_image_set_filter _cairo_pixman_image_set_filter +#define pixman_image_set_repeat _cairo_pixman_image_set_repeat +#define pixman_image_set_transform _cairo_pixman_image_set_transform +#define pixman_init _cairo_pixman_init +#define pixman_line_fixed_x _cairo_pixman_line_fixed_x +#define pixman_op _cairo_pixman_op +#define pixman_pixel_to_color _cairo_pixman_pixel_to_color +#define pixman_point_fixed_bounds _cairo_pixman_point_fixed_bounds +#define pixman_rect_alloc _cairo_pixman_rect_alloc +#define pixman_region_append _cairo_pixman_region_append +#define pixman_region_contains_point _cairo_pixman_region_contains_point +#define pixman_region_contains_rectangle _cairo_pixman_region_contains_rectangle +#define pixman_region_copy _cairo_pixman_region_copy +#define pixman_region_create _cairo_pixman_region_create +#define pixman_region_create_simple _cairo_pixman_region_create_simple +#define pixman_region_destroy _cairo_pixman_region_destroy +#define pixman_region_empty _cairo_pixman_region_empty +#define pixman_region_emptyBox _cairo_pixman_region_empty_box +#define pixman_region_emptyData _cairo_pixman_region_empty_data +#define pixman_region_extents _cairo_pixman_region_extents +#define pixman_region_intersect _cairo_pixman_region_intersect +#define pixman_region_intersectO _cairo_pixman_region_intersect_o +#define pixman_region_inverse _cairo_pixman_region_inverse +#define pixman_region_not_empty _cairo_pixman_region_not_empty +#define pixman_region_num_rects _cairo_pixman_region_num_rects +#define pixman_region_rects _cairo_pixman_region_rects +#define pixman_region_reset _cairo_pixman_region_reset +#define pixman_region_subtract _cairo_pixman_region_subtract +#define pixman_region_subtractO _cairo_pixman_region_subtract_o +#define pixman_region_translate _cairo_pixman_region_translate +#define pixman_region_union _cairo_pixman_region_union +#define pixman_region_unionO _cairo_pixman_region_union_o +#define pixman_region_union_rect _cairo_pixman_region_union_rect +#define pixman_region_validate _cairo_pixman_region_validate +#define pixman_set_extents _cairo_pixman_set_extents +#define pixman_transform_point _cairo_pixman_transform_point +#define pixman_trapezoid_bounds _cairo_pixman_trapezoid_bounds +#define pixman_triangle_bounds _cairo_pixman_triangle_bounds +#define pixman_uninit _cairo_pixman_uninit +#define QuickSortRects _cairo_pixman_quick_sort_rects +#define QuickSortSpans _cairo_pixman_quick_sort_spans +#define RenderEdgeInit _cairo_pixman_render_edge_init +#define _RenderEdgeMultiInit _cairo_pixman_render_edge_multi_init +#define RenderEdgeStep _cairo_pixman_render_edge_step +#define RenderLineFixedEdgeInit _cairo_pixman_render_line_fixed_edge_init +#define RenderSampleCeilY _cairo_pixman_render_sample_ceil_y +#define RenderSampleFloorY _cairo_pixman_render_sample_floor_y +#define composeFunctions _cairo_pixman_compose_functions diff --git a/gfx/cairo/libpixman/src/pixman-vc71.lib b/gfx/cairo/libpixman/src/pixman-vc71.lib deleted file mode 100644 index e9b3f66bc03a..000000000000 Binary files a/gfx/cairo/libpixman/src/pixman-vc71.lib and /dev/null differ diff --git a/gfx/cairo/libpixman/src/pixman-xserver-compat.h b/gfx/cairo/libpixman/src/pixman-xserver-compat.h index 6ee83737a074..5113abd545b5 100644 --- a/gfx/cairo/libpixman/src/pixman-xserver-compat.h +++ b/gfx/cairo/libpixman/src/pixman-xserver-compat.h @@ -48,7 +48,7 @@ /* Then, define any names that the server code will be expecting in * terms of libpixman names. */ - +/* typedef uint8_t CARD8; typedef uint16_t CARD16; typedef int16_t INT16; @@ -66,24 +66,42 @@ typedef pixman_point_fixed_t xPointFixed; typedef pixman_line_fixed_t xLineFixed; typedef pixman_trapezoid_t xTrapezoid; typedef pixman_triangle_t xTriangle; - +*/ #define RENDER 1 +/* #define FB_SHIFT IC_SHIFT #define FB_MASK IC_MASK #define FB_ALLONES IC_ALLONES #define FbMaskBits IcMaskBits +*/ /* XXX: We changed some function and field names which makes for some * ugly hacks... */ #define pDrawable pixels -#define fbGetDrawable(pDrawable, pointer, stride, bpp, xoff, yoff) { \ +#define fbGetDrawable(pDrawable, buf, outstride, outbpp, xoff, yoff) { \ (buf) = (pDrawable)->data; \ - (stride) = ((int) pDrawable->stride) / sizeof (pixman_bits_t); \ - (bpp) = (pDrawable)->bpp; \ + (outstride) = ((int) pDrawable->stride) / sizeof (pixman_bits_t); \ + (outbpp) = (pDrawable)->bpp; \ (xoff) = 0; \ (yoff) = 0; \ } +/* Extended repeat attributes included in 0.10 */ +#define RepeatNone 0 +#define RepeatNormal 1 +#define RepeatPad 2 +#define RepeatReflect 3 + +typedef pixman_vector_t PictVector; +typedef pixman_vector_t* PictVectorPtr; + +#define miIndexedPtr FbIndexedPtr +#define miIndexToEnt24 FbIndexToEnt24 +#define miIndexToEntY24 FbIndexToEntY24 + +#define MAX_FIXED_48_16 ((xFixed_48_16) 0x7fffffff) +#define MIN_FIXED_48_16 (-((xFixed_48_16) 1 << 31)) + /* Then, include any header files that have been copied directly * from xserver. */ diff --git a/gfx/cairo/libpixman/src/pixman.h b/gfx/cairo/libpixman/src/pixman.h index 2361b88e58e1..61593f86b22c 100644 --- a/gfx/cairo/libpixman/src/pixman.h +++ b/gfx/cairo/libpixman/src/pixman.h @@ -54,7 +54,7 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ -/* $Id: pixman.h,v 1.6 2005/06/04 07:03:28 vladimir%pobox.com Exp $ */ +/* $Id: pixman.h,v 1.7 2005/08/20 05:34:03 vladimir%pobox.com Exp $ */ /* libic.h */ @@ -91,6 +91,7 @@ SOFTWARE. # include "mozstdint.h" #endif +#include "pixman-remap.h" #if defined(__cplusplus) || defined(c_plusplus) extern "C" { @@ -272,6 +273,7 @@ pixman_image_create (pixman_format_t *format, */ #ifndef IC_SHIFT #define IC_SHIFT 5 +#define FB_SHIFT IC_SHIFT typedef uint32_t pixman_bits_t; #endif diff --git a/gfx/cairo/libpixman/src/pixregion.c b/gfx/cairo/libpixman/src/pixregion.c index 40bcfc6b67b1..659434b34588 100644 --- a/gfx/cairo/libpixman/src/pixregion.c +++ b/gfx/cairo/libpixman/src/pixregion.c @@ -46,12 +46,12 @@ SOFTWARE. ******************************************************************/ +#undef DEBUG + #include #include #include -#undef DEBUG - #include "pixregionint.h" #include "slim_internal.h" @@ -1158,7 +1158,7 @@ pixman_region_union_rect(pixman_region16_t *dest, pixman_region16_t *source, pixman_region16_t region; if (!width || !height) - return PIXMAN_REGION_STATUS_FAILURE; + return PIXMAN_REGION_STATUS_SUCCESS; region.data = NULL; region.extents.x1 = x; region.extents.y1 = y; diff --git a/gfx/cairo/optimize-opaque-paint.diff b/gfx/cairo/optimize-opaque-paint.diff deleted file mode 100644 index b801a786a903..000000000000 --- a/gfx/cairo/optimize-opaque-paint.diff +++ /dev/null @@ -1,23 +0,0 @@ ---- ../../../../../cairo-cvs/dist/cairo-0.5.0/src/cairo.c 2005-05-11 19:59:13.000000000 -0700 -+++ cairo/src/cairo.c 2005-06-01 23:09:11.000000000 -0700 -@@ -1168,12 +1162,16 @@ - if (cr->status) - return; - -- _cairo_color_init_rgba (&color, 1., 1., 1., alpha); -- _cairo_pattern_init_solid (&pattern.solid, &color); -+ if (alpha == 1.0) { -+ cr->status = _cairo_gstate_paint (cr->gstate); -+ } else { -+ _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); -+ cr->status = _cairo_gstate_mask (cr->gstate, &pattern.base); - -- _cairo_pattern_fini (&pattern.base); -+ _cairo_pattern_fini (&pattern.base); -+ } - - CAIRO_CHECK_SANITY (cr); - } diff --git a/gfx/cairo/win32-extents.diff b/gfx/cairo/win32-extents.diff deleted file mode 100644 index 9605d9258297..000000000000 --- a/gfx/cairo/win32-extents.diff +++ /dev/null @@ -1,26 +0,0 @@ -Index: cairo/src/cairo-win32-font.c -=================================================================== -RCS file: /cvsroot/mozilla/gfx/cairo/cairo/src/cairo-win32-font.c,v -retrieving revision 1.1 -diff -u -8 -p -r1.1 cairo-win32-font.c ---- cairo/src/cairo-win32-font.c 4 Jun 2005 07:03:27 -0000 1.1 -+++ cairo/src/cairo-win32-font.c 14 Jun 2005 21:14:20 -0000 -@@ -709,17 +709,17 @@ _cairo_win32_scaled_font_glyph_extents ( - * of the font. - */ - status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc); - GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX, - &metrics, 0, NULL, &matrix); - _cairo_win32_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; - extents->y_advance = (double)metrics.gmCellIncY / scaled_font->em_square; - } - - return CAIRO_STATUS_SUCCESS; - }