summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Biesinger <cbiesinger@web.de>2005-12-18 17:20:06 +0000
committerChristian Biesinger <cbiesinger@web.de>2005-12-18 17:20:06 +0000
commit6142bc534850dda7ecf823c2a672ed65c13978eb (patch)
tree37028a8d22e8c5799ff6d414c9d2e39c8777657a
parent93da7fa203a8e4bce40aab590a8c245400013787 (diff)
Mention new --enable-svg option
Add notes for the new BeOS backend Add disabled by default BeOS backend Add BeOS files New New BEOS_SURFACE_FEATURE BeOS mutex functions Ignore files generates by the BeOS tests Add cairo-test-beos.* New. Test BeOS backend.
-rw-r--r--ChangeLog17
-rw-r--r--INSTALL1
-rw-r--r--README5
-rw-r--r--configure.in44
-rw-r--r--src/Makefile.am11
-rw-r--r--src/cairo-beos-surface.cpp731
-rw-r--r--src/cairo-beos.h61
-rw-r--r--src/cairo-features.h.in2
-rw-r--r--src/cairoint.h11
-rw-r--r--test/.cvsignore3
-rw-r--r--test/Makefile.am6
-rw-r--r--test/cairo-test-beos.cpp239
-rw-r--r--test/cairo-test-beos.h26
-rw-r--r--test/cairo-test.c13
14 files changed, 1170 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index b0c64f0f..a53ffdea 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/INSTALL b/INSTALL
index 854113ea..4a49f008 100644
--- a/INSTALL
+++ b/INSTALL
@@ -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
diff --git a/README b/README
index 2c31deda..a8ee4723 100644
--- a/README
+++ b/README
@@ -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) {