diff options
-rw-r--r-- | ChangeLog | 17 | ||||
-rw-r--r-- | INSTALL | 1 | ||||
-rw-r--r-- | README | 5 | ||||
-rw-r--r-- | configure.in | 44 | ||||
-rw-r--r-- | src/Makefile.am | 11 | ||||
-rw-r--r-- | src/cairo-beos-surface.cpp | 731 | ||||
-rw-r--r-- | src/cairo-beos.h | 61 | ||||
-rw-r--r-- | src/cairo-features.h.in | 2 | ||||
-rw-r--r-- | src/cairoint.h | 11 | ||||
-rw-r--r-- | test/.cvsignore | 3 | ||||
-rw-r--r-- | test/Makefile.am | 6 | ||||
-rw-r--r-- | test/cairo-test-beos.cpp | 239 | ||||
-rw-r--r-- | test/cairo-test-beos.h | 26 | ||||
-rw-r--r-- | test/cairo-test.c | 13 |
14 files changed, 1170 insertions, 0 deletions
@@ -1,5 +1,22 @@ 2005-12-19 Christian Biesinger <cbiesinger@web.de> + * INSTALL: Mention new --enable-svg option + * README: Add notes for the new BeOS backend + * configure.in: Add disabled by default BeOS backend + * src/Makefile.am: Add BeOS files + * src/cairo-beos-surface.cpp: New + * src/cairo-beos.h: New + * src/cairo-features.h.in: BEOS_SURFACE_FEATURE + * src/cairoint.h: BeOS mutex functions + * test/.cvsignore: Ignore files generates by the BeOS tests + * test/Makefile.am: Add cairo-test-beos.* + * test/cairo-test-beos.cpp: New. (Must be a C++ file, hence not part of + cairo-test.c) + * test/cairo-test-beos.h: New. + * test/cairo-test.c: (cairo_test_expecting): Test BeOS backend. + +2005-12-19 Christian Biesinger <cbiesinger@web.de> + reviewed by: cworth * src/cairo-clip-private.h: Move enum to cairoint.h @@ -66,6 +66,7 @@ More detailed build instructions --enable-atsui --enable-xcb --enable-glitz + --enable-beos Some of cairo's backends are marked as experimental and will not be built by default. If you would like to build and @@ -98,6 +98,11 @@ Surface backends: ------------ Xrender >= 0.6 http://freedesktop.org/Software/xlibs + beos backend + ------------ + No dependencies in itself other than an installed BeOS system, but cairo + requires a font backend. See the freetype dependency list. + Font backends: freetype font backend diff --git a/configure.in b/configure.in index 95dbdc34..a795ab6f 100644 --- a/configure.in +++ b/configure.in @@ -190,6 +190,46 @@ if test "x$use_win32" = "xyes"; then fi AC_SUBST(WIN32_FONT_FEATURE) + +dnl =========================================================================== + + +AC_MSG_CHECKING([for BeOS/Zeta]) +case "$host" in + *-*-beos) + cairo_platform_beos=yes + ;; + *) + cairo_platform_beos=no + ;; +esac +AC_MSG_RESULT([$cairo_platform_beos]) + +AC_ARG_ENABLE(beos, + [ --enable-beos Disable cairo's BeOS/Zeta backend], + [use_beos=$enableval], [use_beos=no]) + +if test "x$cairo_platform_beos" != "xyes" ; then + if test "x$use_beos" = "xyes"; then + AC_MSG_WARN([The BeOS backend requires a BeOS platform; disabling]) +# use_beos=no + fi +fi + +if test "x$use_beos" = "xyes"; then + AC_PROG_CXX + dnl Add libbe and libzeta if available + AC_CHECK_LIB(be,main,CAIRO_LIBS="$CAIRO_LIBS -lbe") + AC_CHECK_LIB(zeta,main,CAIRO_LIBS="$CAIRO_LIBS -lzeta") +fi + +AM_CONDITIONAL(CAIRO_HAS_BEOS_SURFACE, test "x$use_beos" = "xyes") +if test "x$use_beos" = "xyes"; then + BEOS_SURFACE_FEATURE="#define CAIRO_HAS_BEOS_SURFACE 1" +fi +AC_SUBST(BEOS_SURFACE_FEATURE) + + dnl =========================================================================== AC_ARG_ENABLE(png, @@ -682,6 +722,7 @@ echo " PostScript: $use_ps" echo " PDF: $use_pdf" echo " SVG: $use_svg" echo " glitz: $use_glitz" +echo " BeOS: $use_beos" echo "" echo "the following font backends:" echo " FreeType: $use_freetype" @@ -732,3 +773,6 @@ if test x"$use_quartz" = "xyes" ; then echo "$WARNING_MESSAGE" | sed 's/@BACKEND@/ATSUI/' fi +if test x"$use_beos" = "xyes" ; then + echo "$WARNING_MESSAGE" | sed 's/@BACKEND@/BeOS/' +fi diff --git a/src/Makefile.am b/src/Makefile.am index 147016df..158751c2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -50,6 +50,12 @@ if CAIRO_HAS_WIN32_FONT libcairo_win32_sources += cairo-win32-font.c endif +libcairo_beos_sources = +if CAIRO_HAS_BEOS_SURFACE +libcairo_beos_headers = cairo-beos.h +libcairo_beos_sources += cairo-beos-surface.cpp +endif + if CAIRO_HAS_GLITZ_SURFACE libcairo_glitz_headers = cairo-glitz.h libcairo_glitz_sources = cairo-glitz-surface.c @@ -102,6 +108,7 @@ cairoinclude_HEADERS = \ $(libcairo_ps_headers) \ $(libcairo_quartz_headers) \ $(libcairo_win32_headers) \ + $(libcairo_beos_headers) \ $(libcairo_xcb_headers) \ $(libcairo_xlib_headers) @@ -167,9 +174,13 @@ libcairo_la_SOURCES = \ $(libcairo_xcb_sources) \ $(libcairo_glitz_sources) \ $(libcairo_win32_sources) \ + $(libcairo_beos_sources) \ cairoint.h libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined $(export_symbols) +# this -Wno-multichar line is really just for the beos surface, because the +# system headers trigger this warning. +libcairo_la_CXXFLAGS = -Wno-multichar INCLUDES = -I$(srcdir) -I$(top_srcdir)/pixman/src $(CAIRO_CFLAGS) diff --git a/src/cairo-beos-surface.cpp b/src/cairo-beos-surface.cpp new file mode 100644 index 00000000..ae9b7f34 --- /dev/null +++ b/src/cairo-beos-surface.cpp @@ -0,0 +1,731 @@ +/* vim:set ts=8 sw=4 noet cin: */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Christian Biesinger <cbiesinger@web.de> + * + * 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 Christian Biesinger + * <cbiesinger@web.de> + * + * Contributor(s): + */ + +// This is a C++ file in order to use the C++ BeOS API + +#include <new> + +#include <Bitmap.h> +#include <Region.h> +#if 0 +#include <DirectWindow.h> +#endif +#include <Screen.h> +#include <Window.h> +#include <Locker.h> + +#include "cairoint.h" +#include "cairo-beos.h" + +#define CAIRO_INT_STATUS_SUCCESS (cairo_int_status_t)(CAIRO_STATUS_SUCCESS) + +struct cairo_beos_surface { + cairo_surface_t base; + + BView* view; + + /* + * A view is either attached to a bitmap, a window, or unattached. + * If it is attached to a window, we can copy data out of it using BScreen. + * If it is attached to a bitmap, we can read the bitmap data. + * If it is not attached, it doesn't draw anything, we need not bother. + * + * Since there doesn't seem to be a way to get the bitmap from a view if it + * is attached to one, we have to use a special surface creation function. + */ + + BBitmap* bitmap; + + +} cairo_beos_surface_t; + +static BRect +_cairo_rect_to_brect (const cairo_rectangle_t* rect) +{ + // A BRect is one pixel wider than you'd think + return BRect(rect->x, rect->y, rect->x + rect->width - 1, + rect->y + rect->height - 1); +} + +static cairo_rectangle_t +_brect_to_cairo_rect (const BRect& rect) +{ + cairo_rectangle_t retval; + retval.x = int(rect.left + 0.5); + retval.y = int(rect.top + 0.5); + retval.width = rect.IntegerWidth() + 1; + retval.height = rect.IntegerHeight() + 1; + return retval; +} + +static rgb_color +_cairo_color_to_be_color (const cairo_color_t* color) +{ + // This factor ensures a uniform distribution of numbers + const float factor = 256 - 1e-5; + // Using doubles to have non-premultiplied colors + rgb_color be_color = { uint8(color->red * factor), + uint8(color->green * factor), + uint8(color->blue * factor), + uint8(color->alpha * factor) }; + + return be_color; +} + +enum ViewCopyStatus { + OK, + NOT_VISIBLE, // The view or the interest rect is not visible on screen + ERROR // The view was visible, but the rect could not be copied. Probably OOM +}; + +/** + * Gets the contents of the view as a BBitmap*. Caller must delete the bitmap. + * @param bitmap[out] The resulting bitmap. + * @param[out] rect The rectangle that was copied, in the view's coordinate system + * @param interestRect If non-null, only this part of the view will be copied (view's coord system). + */ +static ViewCopyStatus +_cairo_beos_view_to_bitmap (BView* view, + BBitmap** bitmap, + BRect* rect = NULL, + const BRect* interestRect = NULL) +{ + *bitmap = NULL; + + BWindow* wnd = view->Window(); + // If we have no window, can't do anything + if (!wnd) + return NOT_VISIBLE; + + view->Sync(); + wnd->Sync(); + +#if 0 + // Is it a direct window? + BDirectWindow* directWnd = dynamic_cast<BDirectWindow*>(wnd); + if (directWnd) { + // WRITEME + } +#endif + + // Is it visible? If so, we can copy the content off the screen + if (wnd->IsHidden()) + return NOT_VISIBLE; + + BRect rectToCopy(view->Bounds()); + if (interestRect) + rectToCopy = rectToCopy & *interestRect; + + if (!rectToCopy.IsValid()) + return NOT_VISIBLE; + + BScreen screen(wnd); + BRect screenRect(view->ConvertToScreen(rectToCopy)); + screenRect = screenRect & screen.Frame(); + + if (!screen.IsValid()) + return NOT_VISIBLE; + + if (rect) + *rect = view->ConvertFromScreen(screenRect); + + if (screen.GetBitmap(bitmap, false, &screenRect) == B_OK) + return OK; + + return ERROR; +} + +inline unsigned char +unpremultiply (unsigned char color, + unsigned char alpha) +{ + if (alpha == 0) + return 0; + // plus alpha/2 to round instead of truncate + return (color * 255 + alpha / 2) / alpha; +} + +inline unsigned char +premultiply (unsigned char color, + unsigned char alpha) +{ + // + 127 to round, instead of truncate + return (color * alpha + 127) / 255; +} + +/** + * Takes an input in ABGR premultiplied image data and unmultiplies it. + * The result is stored in retdata. + */ +static void +unpremultiply_rgba (unsigned char* data, + int width, + int height, + int stride, + unsigned char* retdata) +{ + unsigned char* end = data + stride * height; + for (unsigned char* in = data, *out = retdata; + in < end; + in += stride, out += stride) + { + for (int i = 0; i < width; ++i) { + // XXX for a big-endian platform this'd have to change + int idx = 4 * i; + unsigned char alpha = in[idx + 3]; + out[idx + 0] = unpremultiply(in[idx + 0], alpha); // B + out[idx + 1] = unpremultiply(in[idx + 1], alpha); // G + out[idx + 2] = unpremultiply(in[idx + 2], alpha); // R + out[idx + 3] = in[idx + 3]; // Alpha + } + } +} + +/** + * Takes an input in ABGR non-premultiplied image data and premultiplies it. + * The returned data must be freed with free(). + */ +static unsigned char* +premultiply_rgba (unsigned char* data, + int width, + int height, + int stride) +{ + unsigned char* retdata = reinterpret_cast<unsigned char*>(malloc(stride * height)); + if (!retdata) + return NULL; + + unsigned char* end = data + stride * height; + for (unsigned char* in = data, *out = retdata; + in < end; + in += stride, out += stride) + { + for (int i = 0; i < width; ++i) { + // XXX for a big-endian platform this'd have to change + int idx = 4 * i; + unsigned char alpha = in[idx + 3]; + out[idx + 0] = premultiply(in[idx + 0], alpha); // B + out[idx + 1] = premultiply(in[idx + 1], alpha); // G + out[idx + 2] = premultiply(in[idx + 2], alpha); // R + out[idx + 3] = in[idx + 3]; // Alpha + } + } + return retdata; +} + +/** + * Returns an addrefed image surface for a BBitmap. The bitmap need not outlive + * the surface. + */ +static cairo_image_surface_t* +_cairo_beos_bitmap_to_surface (BBitmap* bitmap) +{ + color_space format = bitmap->ColorSpace(); + if (format != B_RGB32 && format != B_RGBA32) { + BBitmap bmp(bitmap->Bounds(), B_RGB32, true); + BView view(bitmap->Bounds(), "Cairo bitmap drawing view", + B_FOLLOW_ALL_SIDES, 0); + bmp.AddChild(&view); + + view.LockLooper(); + + view.DrawBitmap(bitmap, BPoint(0.0, 0.0)); + view.Sync(); + + cairo_image_surface_t* imgsurf = _cairo_beos_bitmap_to_surface(&bmp); + + view.UnlockLooper(); + bmp.RemoveChild(&view); + return imgsurf; + } + + cairo_format_t cformat = format == B_RGB32 ? CAIRO_FORMAT_RGB24 + : CAIRO_FORMAT_ARGB32; + + BRect bounds(bitmap->Bounds()); + unsigned char* bits = reinterpret_cast<unsigned char*>(bitmap->Bits()); + int width = bounds.IntegerWidth() + 1; + int height = bounds.IntegerHeight() + 1; + unsigned char* premultiplied; + if (cformat == CAIRO_FORMAT_ARGB32) { + premultiplied = premultiply_rgba(bits, width, height, + bitmap->BytesPerRow()); + } else { + premultiplied = reinterpret_cast<unsigned char*>( + malloc(bitmap->BytesPerRow() * height)); + if (premultiplied) + memcpy(premultiplied, bits, bitmap->BytesPerRow() * height); + } + if (!premultiplied) + return NULL; + + cairo_image_surface_t* surf = reinterpret_cast<cairo_image_surface_t*> + (cairo_image_surface_create_for_data(premultiplied, + cformat, + width, + height, + bitmap->BytesPerRow())); + if (surf->base.status) + free(premultiplied); + else + _cairo_image_surface_assume_ownership_of_data(surf); + return surf; +} + +/** + * Converts an image surface to a BBitmap. The return value must be freed with + * delete. + */ +static BBitmap* +_cairo_image_surface_to_bitmap (cairo_image_surface_t* surface) +{ + BRect size(0.0, 0.0, surface->width - 1, surface->height - 1); + switch (surface->format) { + case CAIRO_FORMAT_ARGB32: { + BBitmap* data = new BBitmap(size, B_RGBA32); + unpremultiply_rgba(surface->data, + surface->width, + surface->height, + surface->stride, + reinterpret_cast<unsigned char*>(data->Bits())); + return data; + } + case CAIRO_FORMAT_RGB24: { + BBitmap* data = new BBitmap(size, B_RGB32); + memcpy(data->Bits(), surface->data, surface->height * surface->stride); + return data; + } + default: + return NULL; + } +} + +/** + * Converts a cairo drawing operator to a beos drawing_mode. Returns true if + * the operator could be converted, false otherwise. + */ +static bool +_cairo_op_to_be_op (cairo_operator_t cairo_op, + drawing_mode* beos_op) +{ + switch (cairo_op) { + + case CAIRO_OPERATOR_SOURCE: + *beos_op = B_OP_COPY; + return true; + case CAIRO_OPERATOR_OVER: + *beos_op = B_OP_ALPHA; + return true; + + case CAIRO_OPERATOR_ADD: + *beos_op = B_OP_ADD; + return true; + + case CAIRO_OPERATOR_CLEAR: + // Does not map to B_OP_ERASE - it replaces the dest with the low + // color, instead of transparency; could be done by setting low + // color appropriately. + case CAIRO_OPERATOR_IN: + case CAIRO_OPERATOR_OUT: + case CAIRO_OPERATOR_ATOP: + + case CAIRO_OPERATOR_DEST: + case CAIRO_OPERATOR_DEST_OVER: + case CAIRO_OPERATOR_DEST_IN: + case CAIRO_OPERATOR_DEST_OUT: + case CAIRO_OPERATOR_DEST_ATOP: + + case CAIRO_OPERATOR_XOR: + case CAIRO_OPERATOR_SATURATE: + + default: + return false; + }; +} + +static cairo_status_t +_cairo_beos_surface_finish (void *abstract_surface) +{ + // Nothing to do + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_beos_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + fprintf(stderr, "Getting source image\n"); + cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>( + abstract_surface); + surface->view->Sync(); + + if (surface->bitmap) { + *image_out = _cairo_beos_bitmap_to_surface(surface->bitmap); + if (!*image_out) { + _cairo_error(CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } + + *image_extra = NULL; + return CAIRO_STATUS_SUCCESS; + } + + BBitmap* bmp; + if (_cairo_beos_view_to_bitmap(surface->view, &bmp) != OK) { + _cairo_error(CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; /// XXX incorrect if the error was NOT_VISIBLE + } + + *image_out = _cairo_beos_bitmap_to_surface(bmp); + if (!*image_out) { + delete bmp; + _cairo_error(CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } + *image_extra = bmp; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_beos_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_surface_destroy (&image->base); + + BBitmap* bmp = static_cast<BBitmap*>(image_extra); + delete bmp; +} + + + +static cairo_status_t +_cairo_beos_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect, + void **image_extra) +{ + cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>( + abstract_surface); + + if (surface->bitmap) { + surface->view->Sync(); + *image_out = _cairo_beos_bitmap_to_surface(surface->bitmap); + if (!*image_out) { + _cairo_error(CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } + + image_rect->x = 0; + image_rect->y = 0; + image_rect->width = (*image_out)->width; + image_rect->height = (*image_out)->height; + + *image_extra = NULL; + return CAIRO_STATUS_SUCCESS; + } + + BRect b_interest_rect(_cairo_rect_to_brect(interest_rect)); + + BRect rect; + BBitmap* bitmap; + ViewCopyStatus status = _cairo_beos_view_to_bitmap(surface->view, &bitmap, + &rect, &b_interest_rect); + if (status == NOT_VISIBLE) { + *image_out = NULL; + *image_extra = NULL; + return CAIRO_STATUS_SUCCESS; + } + if (status == ERROR) { + _cairo_error(CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } + + *image_rect = _brect_to_cairo_rect(rect); + +#if 0 + fprintf(stderr, "Requested: (cairo rects) (%ix%i) dim (%u, %u) returning (%ix%i) dim (%u, %u)\n", + interest_rect->x, interest_rect->y, interest_rect->width, interest_rect->height, + image_rect->x, image_rect->y, image_rect->width, image_rect->height); +#endif + + *image_out = _cairo_beos_bitmap_to_surface(bitmap); + delete bitmap; + if (!*image_out) { + _cairo_error(CAIRO_STATUS_NO_MEMORY); + return CAIRO_STATUS_NO_MEMORY; + } + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; +} + + +static void +_cairo_beos_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_t *intersect_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) +{ + fprintf(stderr, "Fallback drawing\n"); + cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>( + abstract_surface); + + BBitmap* bitmap_to_draw = _cairo_image_surface_to_bitmap(image); + + surface->view->PushState(); + + surface->view->SetDrawingMode(B_OP_COPY); + BRect rect(_cairo_rect_to_brect(image_rect)); + + surface->view->DrawBitmap(bitmap_to_draw, rect); + + surface->view->PopState(); + + delete bitmap_to_draw; + cairo_surface_destroy(&image->base); +} + +static void +_cairo_beos_fill_rectangle (cairo_beos_surface_t *surface, + cairo_rectangle_t *rect) +{ + BRect brect(_cairo_rect_to_brect(rect)); + surface->view->FillRect(brect); +} + +static cairo_int_status_t +_cairo_beos_fill_rectangles (void *abstract_surface, + cairo_operator_t op, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int num_rects) +{ + fprintf(stderr, "Drawing %i rectangles\n", num_rects); + cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>( + abstract_surface); + + if (num_rects <= 0) + return CAIRO_INT_STATUS_SUCCESS; + + drawing_mode mode; + if (!_cairo_op_to_be_op(op, &mode)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + rgb_color be_color = _cairo_color_to_be_color(color); + + if (mode == B_OP_ALPHA && be_color.alpha == 0xFF) + mode = B_OP_COPY; + + surface->view->PushState(); + + surface->view->SetDrawingMode(mode); + surface->view->SetHighColor(be_color); + if (surface->bitmap && surface->bitmap->ColorSpace() == B_RGBA32) + surface->view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE); + else + surface->view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY); + + for (int i = 0; i < num_rects; ++i) { + _cairo_beos_fill_rectangle(surface, &rects[i]); + } + + surface->view->PopState(); + + return CAIRO_INT_STATUS_SUCCESS; +} + + + +static cairo_int_status_t +_cairo_beos_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) +{ + fprintf(stderr, "Setting clip region\n"); + cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>( + abstract_surface); + if (region == NULL) { + // No clipping + surface->view->ConstrainClippingRegion(NULL); + return CAIRO_INT_STATUS_SUCCESS; + } + + int count = pixman_region_num_rects(region); + pixman_box16_t* rects = pixman_region_rects(region); + BRegion bregion; + for (int i = 0; i < count; ++i) { + // Have to substract one, because for pixman, the second coordinate + // lies outside the rectangle. + bregion.Include(BRect(rects[i].x1, rects[i].y1, rects[i].x2 - 1, rects[i].y2 - 1)); + } + surface->view->ConstrainClippingRegion(&bregion); + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_beos_surface_get_extents (void *abstract_surface, + cairo_rectangle_t *rectangle) +{ + cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>( + abstract_surface); + + BRect size = surface->view->Bounds(); + + *rectangle = _brect_to_cairo_rect(size); + + // Make sure to have our upperleft edge as (0,0) + rectangle->x = 0; + rectangle->y = 0; + + return CAIRO_INT_STATUS_SUCCESS; +} + +static const struct _cairo_surface_backend cairo_beos_surface_backend = { + NULL, /* create_similar */ + _cairo_beos_surface_finish, + _cairo_beos_surface_acquire_source_image, + _cairo_beos_surface_release_source_image, + _cairo_beos_surface_acquire_dest_image, + _cairo_beos_surface_release_dest_image, + NULL, /* clone_similar */ + NULL, /* composite */ + _cairo_beos_fill_rectangles, + NULL, /* composite_trapezoids */ + NULL, /* copy_page */ + NULL, /* show_page */ + _cairo_beos_surface_set_clip_region, + NULL, /* intersect_clip_path */ + _cairo_beos_surface_get_extents, + NULL, /* old_show_glyphs */ + NULL, /* get_font_options */ + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + NULL, /* scaled_font_fini */ + NULL, /* scaled_glyph_fini */ + + NULL, /* paint */ + NULL, /* mask */ + NULL, /* stroke */ + NULL, /* fill */ + NULL /* show_glyphs */ +}; + +/** + * cairo_beos_surface_create: + * @view: The view to draw on + * + * Creates a Cairo surface that draws onto a BeOS BView. + * The caller must ensure that the view does not get deleted before the surface. + * If the view is attached to a bitmap rather than an on-screen window, use + * cairo_beos_surface_create_for_bitmap instead of this function. + **/ +cairo_surface_t * +cairo_beos_surface_create (BView* view) +{ + return cairo_beos_surface_create_for_bitmap(view, NULL); +} + +/** + * cairo_beos_surface_create_for_bitmap: + * @view: The view to draw on + * @bmp: The bitmap to which the view is attached + * + * Creates a Cairo surface that draws onto a BeOS BView which is attached to a + * BBitmap. + * The caller must ensure that the view and the bitmap do not get deleted + * before the surface. + * + * For views that draw to a bitmap (as opposed to a screen), use this function + * rather than cairo_beos_surface_create. Not using this function WILL lead to + * incorrect behaviour. + * + * For now, only views that draw to the entire area of bmp are supported. + * The view must already be attached to the bitmap. + **/ +cairo_surface_t * +cairo_beos_surface_create_for_bitmap (BView* view, + BBitmap* bmp) +{ + // Must use malloc, because cairo code will use free() on the surface + cairo_beos_surface_t *surface = static_cast<cairo_beos_surface_t*>( + malloc(sizeof(cairo_beos_surface_t))); + if (surface == NULL) { + _cairo_error (CAIRO_STATUS_NO_MEMORY); + return const_cast<cairo_surface_t*>(&_cairo_surface_nil); + } + + _cairo_surface_init(&surface->base, &cairo_beos_surface_backend); + + surface->view = view; + surface->bitmap = bmp; + + return (cairo_surface_t *) surface; +} + +// --------------------------------------------------------------------------- +// Cairo uses locks without explicit initialization. To support that, we +// provide a class here which manages the locks and is in global scope, so the +// compiler will instantiate it on library load and destroy it on library +// unload. + +class BeLocks { + public: + BLocker cairo_toy_font_face_hash_table_mutex; + BLocker cairo_scaled_font_map_mutex; + BLocker cairo_ft_unscaled_font_map_mutex; +}; + +static BeLocks locks; + +void* cairo_toy_font_face_hash_table_mutex = &locks.cairo_toy_font_face_hash_table_mutex; +void* cairo_scaled_font_map_mutex = &locks.cairo_scaled_font_map_mutex; +void* cairo_ft_unscaled_font_map_mutex = &locks.cairo_ft_unscaled_font_map_mutex; + +void _cairo_beos_lock (void* locker) { + BLocker* bLocker = reinterpret_cast<BLocker*>(locker); + bLocker->Lock(); +} + +void _cairo_beos_unlock (void* locker) { + BLocker* bLocker = reinterpret_cast<BLocker*>(locker); + bLocker->Unlock(); +} + diff --git a/src/cairo-beos.h b/src/cairo-beos.h new file mode 100644 index 00000000..d253bcb3 --- /dev/null +++ b/src/cairo-beos.h @@ -0,0 +1,61 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Christian Biesinger <cbiesinger@web.de> + * + * 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 Christian Biesinger + * <cbiesinger@web.de> + * + * Contributor(s): + */ + +#ifndef CAIRO_BEOS_H +#define CAIRO_BEOS_H + +#include <cairo.h> + +#if CAIRO_HAS_BEOS_SURFACE + +#include <View.h> + +CAIRO_BEGIN_DECLS + +cairo_public cairo_surface_t * +cairo_beos_surface_create (BView* view); + +cairo_public cairo_surface_t * +cairo_beos_surface_create_for_bitmap (BView* view, + BBitmap* bmp); + +CAIRO_END_DECLS + +#else /* CAIRO_HAS_BEOS_SURFACE */ +# error Cairo was not compiled with support for the beos backend +#endif /* CAIRO_HAS_BEOS_SURFACE */ + +#endif /* CAIRO_BEOS_H */ + diff --git a/src/cairo-features.h.in b/src/cairo-features.h.in index 8daf9f36..4af0501f 100644 --- a/src/cairo-features.h.in +++ b/src/cairo-features.h.in @@ -69,6 +69,8 @@ @WIN32_SURFACE_FEATURE@ +@BEOS_SURFACE_FEATURE@ + @GLITZ_SURFACE_FEATURE@ @FT_FONT_FEATURE@ diff --git a/src/cairoint.h b/src/cairoint.h index 43e71b31..39875502 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -150,6 +150,17 @@ CAIRO_BEGIN_DECLS # define CAIRO_MUTEX_UNLOCK(name) LeaveCriticalSection (&name) #endif +#if !defined(CAIRO_MUTEX_DECLARE) && defined CAIRO_HAS_BEOS_SURFACE +cairo_private void _cairo_beos_lock(void*); +cairo_private void _cairo_beos_unlock(void*); + /* the real initialization takes place in a global constructor */ +# define CAIRO_MUTEX_DECLARE(name) extern void* name; +# define CAIRO_MUTEX_DECLARE_GLOBAL(name) extern void* name; +# define CAIRO_MUTEX_LOCK(name) _cairo_beos_lock (&name) +# define CAIRO_MUTEX_UNLOCK(name) _cairo_beos_unlock (&name) +#endif + + #ifndef CAIRO_MUTEX_DECLARE # error "No mutex declarations. Cairo will not work with multiple threads." \ "(Remove this #error directive to acknowledge & accept this limitation)." diff --git a/test/.cvsignore b/test/.cvsignore index fc913fce..2638f3f3 100644 --- a/test/.cvsignore +++ b/test/.cvsignore @@ -92,6 +92,9 @@ xlib-surface *-xlib-out.png *-xlib-argb32-out.png *-xlib-rgb24-out.png +*-beos-rgb24-out.png +*-beos_bitmap-rgb24-out.png +*-beos_bitmap-argb32-out.png *-diff.png *.gcno *.la diff --git a/test/Makefile.am b/test/Makefile.am index a2676950..4558b2a1 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -252,6 +252,12 @@ write-png.h \ xmalloc.c \ xmalloc.h +if CAIRO_HAS_BEOS_SURFACE +libcairotest_la_SOURCES += cairo-test-beos.cpp cairo-test-beos.h +# BeOS system headers trigger this warning +libcairotest_la_CXXFLAGS = -Wno-multichar +endif + LDADDS = libcairotest.la $(top_builddir)/src/libcairo.la if CAIRO_CAN_TEST_GLITZ_AGL_SURFACE diff --git a/test/cairo-test-beos.cpp b/test/cairo-test-beos.cpp new file mode 100644 index 00000000..1913c697 --- /dev/null +++ b/test/cairo-test-beos.cpp @@ -0,0 +1,239 @@ +/* vim:set ts=8 sw=4 noet cin: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Takashi Toyoshima <toyoshim@be-in.org> + * Fredrik Holmqvist <thesuckiestemail@yahoo.se> + * Christian Biesinger <cbiesinger@web.de> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// Part of this code was originally part of +// xpfe/bootstrap/nsNativeAppSupportBeOS.cpp in the Mozilla source code. + +#include <Application.h> +#include <Window.h> +#include <View.h> +#include <Bitmap.h> + +extern "C" { +#include "cairo-test.h" +} + +#include "cairo-test-beos.h" +#include "cairo-beos.h" + +class CairoTestWindow : public BWindow +{ +public: + CairoTestWindow(BRect frame, const char* title); + virtual ~CairoTestWindow(); + BView* View() const { return mView; } +private: + BView* mView; +}; + +CairoTestWindow::CairoTestWindow(BRect frame, const char* title) + : BWindow(frame, title, B_TITLED_WINDOW, + B_NOT_RESIZABLE|B_NOT_ZOOMABLE) +{ + mView = new BView(frame, "CairoWindowTestView", B_FOLLOW_ALL_SIDES, 0); + AddChild(mView); + Show(); +} + +CairoTestWindow::~CairoTestWindow() +{ + RemoveChild(mView); + delete mView; +} + + +class nsBeOSApp : public BApplication +{ +public: + nsBeOSApp(sem_id sem) : BApplication(GetAppSig()), init(sem) + {} + + void ReadyToRun() + { + release_sem(init); + } + + static int32 Main(void *args) + { + nsBeOSApp *app = new nsBeOSApp( (sem_id)args ); + if(app == NULL) + return B_ERROR; + return app->Run(); + } + +private: + + const char *GetAppSig() + { + return "application/x-vnd.cairo-test-app"; + } + + sem_id init; +}; //class nsBeOSApp + +class AppRunner +{ + public: + AppRunner(); + ~AppRunner(); +}; + +AppRunner::AppRunner() +{ + if (be_app) + return; + + sem_id initsem = create_sem(0, "Cairo BApplication init"); + if (initsem < B_OK) { + cairo_test_log("Error creating BeOS initialization semaphore\n"); + return; + } + + thread_id tid = spawn_thread(nsBeOSApp::Main, "Cairo/BeOS test", B_NORMAL_PRIORITY, (void *)initsem); + if (tid < B_OK || B_OK != resume_thread(tid)) { + cairo_test_log("Error spawning thread\n"); + return; + } + + if (B_OK != acquire_sem(initsem)) { + cairo_test_log("Error acquiring semaphore\n"); + return; + } + + delete_sem(initsem); + return; +} + +AppRunner::~AppRunner() +{ + if (be_app) { + if (be_app->Lock()) + be_app->Quit(); + delete be_app; + be_app = NULL; + } +} + +// Make sure that the BApplication is initialized +static AppRunner sAppRunner; + +struct beos_test_closure +{ + BView* view; + BBitmap* bitmap; + BWindow* window; +}; + +// Test a real window +cairo_surface_t * +create_beos_surface (cairo_test_t* test, cairo_format_t format, void **closure) +{ + float right = test->width ? test->width - 1 : 0; + float bottom = test->height ? test->height - 1 : 0; + BRect rect(0.0, 0.0, right, bottom); + CairoTestWindow* wnd = new CairoTestWindow(rect, test->name); + if (!wnd->View()->LockLooper()) { + cairo_test_log("Error locking looper\n"); + return NULL; + } + + beos_test_closure* bclosure = new beos_test_closure; + bclosure->view = wnd->View(); + bclosure->bitmap = NULL; + bclosure->window = wnd; + + *closure = bclosure; + + return cairo_beos_surface_create(wnd->View()); +} + +void +cleanup_beos (void* closure) +{ + beos_test_closure* bclosure = reinterpret_cast<beos_test_closure*>(closure); + + bclosure->window->Quit(); + + delete bclosure; +} + +// Test a bitmap +cairo_surface_t * +create_beos_bitmap_surface (cairo_test_t* test, cairo_format_t format, + void **closure) +{ + BRect rect(0.0, 0.0, test->width - 1, test->height - 1); + color_space beosformat = (format == CAIRO_FORMAT_RGB24) ? B_RGB32 + : B_RGBA32; + BBitmap* bmp = new BBitmap(rect, beosformat, true); + BView* view = new BView(rect, "Cairo test view", B_FOLLOW_ALL_SIDES, 0); + bmp->AddChild(view); + + if (!view->LockLooper()) { + cairo_test_log("Error locking looper\n"); + return NULL; + } + + beos_test_closure* bclosure = new beos_test_closure; + bclosure->view = view; + bclosure->bitmap = bmp; + bclosure->window = NULL; + *closure = bclosure; + + return cairo_beos_surface_create_for_bitmap(view, bmp); +} + +void +cleanup_beos_bitmap (void* closure) +{ + beos_test_closure* bclosure = reinterpret_cast<beos_test_closure*>(closure); + + bclosure->view->UnlockLooper(); + + bclosure->bitmap->RemoveChild(bclosure->view); + + + delete bclosure->view; + delete bclosure->bitmap; + + delete bclosure; +} + + diff --git a/test/cairo-test-beos.h b/test/cairo-test-beos.h new file mode 100644 index 00000000..6ef1cd87 --- /dev/null +++ b/test/cairo-test-beos.h @@ -0,0 +1,26 @@ +#ifndef CAIRO_TEST_BEOS_H_ +#define CAIRO_TEST_BEOS_H_ + +/* Two functions: One for a real window, one for a bitmap */ + +#include <cairo.h> + +CAIRO_BEGIN_DECLS + +extern cairo_surface_t * +create_beos_surface (cairo_test_t* test, cairo_format_t format, + void **closure); + +extern void +cleanup_beos (void* closure); + +extern cairo_surface_t * +create_beos_bitmap_surface (cairo_test_t* test, cairo_format_t format, + void **closure); + +extern void +cleanup_beos_bitmap (void* closure); + +CAIRO_END_DECLS + +#endif diff --git a/test/cairo-test.c b/test/cairo-test.c index 4e23d67b..1cb4a7c7 100644 --- a/test/cairo-test.c +++ b/test/cairo-test.c @@ -992,6 +992,11 @@ cleanup_xlib (void *closure) } #endif +#if CAIRO_HAS_BEOS_SURFACE +/* BeOS test functions are external as they need to be C++ */ +#include "cairo-test-beos.h" +#endif + #if CAIRO_HAS_PS_SURFACE #include "cairo-ps.h" @@ -1302,6 +1307,14 @@ cairo_test_expecting (cairo_test_t *test, cairo_test_draw_function_t draw, { "pdf", CAIRO_FORMAT_RGB24, create_pdf_surface, pdf_surface_write_to_png, cleanup_pdf }, #endif +#if CAIRO_HAS_BEOS_SURFACE + { "beos", CAIRO_FORMAT_RGB24, + create_beos_surface, cairo_surface_write_to_png, cleanup_beos}, + { "beos_bitmap", CAIRO_FORMAT_RGB24, + create_beos_bitmap_surface, cairo_surface_write_to_png, cleanup_beos_bitmap}, + { "beos_bitmap", CAIRO_FORMAT_ARGB32, + create_beos_bitmap_surface, cairo_surface_write_to_png, cleanup_beos_bitmap}, +#endif }; if ((tname = getenv ("CAIRO_TEST_TARGET")) != NULL) { |