/* vim:set ts=8 sw=4 noet cin: */ /* cairo - a vector graphics library with display and print output * * Copyright © 2005 Christian Biesinger * * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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 * * * Contributor(s): */ // This is a C++ file in order to use the C++ BeOS API #include "cairoint.h" #include "cairo-beos.h" #include "cairo-error-private.h" #include "cairo-image-surface-inline.h" #include #include #include #if 0 #include #endif #include #include #include /** * SECTION:beos-surface * @Title: BeOS Surfaces * @Short_Description: BeOS surface support * @See_Also: #cairo_surface_t * * The BeOS surface is used to render cairo graphics to BeOS views * and bitmaps. **/ #define CAIRO_INT_STATUS_SUCCESS (cairo_int_status_t)(CAIRO_STATUS_SUCCESS) struct cairo_beos_surface_t { cairo_surface_t base; cairo_region_t *clip_region; 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; // If true, surface and view should be deleted when this surface is // destroyed bool owns_bitmap_view; }; class AutoLockView { public: AutoLockView(BView* view) : mView(view) { mOK = mView->LockLooper(); } ~AutoLockView() { if (mOK) mView->UnlockLooper(); } operator bool() { return mOK; } private: BView* mView; bool mOK; }; static cairo_surface_t * _cairo_beos_surface_create_internal (BView* view, BBitmap* bmp, bool owns_bitmap_view = false); static inline BRect _cairo_rectangle_to_brect (const cairo_rectangle_int_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 inline cairo_rectangle_int_t _brect_to_cairo_rectangle (const BRect &rect) { cairo_rectangle_int_t retval; retval.x = floor (rect.left); retval.y = floor (rect.top); retval.width = ceil (rect.right) - retval.x + 1; retval.height = ceil (rect.bottom) - rectval.y + 1; return retval; } static inline 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 }; /** * _cairo_beos_view_to_bitmap: * @bitmap: [out] The resulting bitmap. * @rect: [out] The rectangle that was copied, in the view's coordinate system * @interestRect: If non-null, only this part of the view will be copied (view's coord system). * * Gets the contents of the view as a BBitmap*. Caller must delete the bitmap. **/ 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(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; } static void unpremultiply_bgra (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 ++) { uint8_t *b = &out[4*i]; uint32_t pixel; uint8_t alpha; memcpy (&pixel, &data[4*i], sizeof (uint32_t)); alpha = pixel & 0xff; if (alpha == 0) { b[0] = b[1] = b[2] = b[3] = 0; } else { b[0] = (((pixel >> 24) & 0xff) * 255 + alpha / 2) / alpha; b[1] = (((pixel >> 16) & 0xff) * 255 + alpha / 2) / alpha; b[2] = (((pixel >> 8) & 0xff) * 255 + alpha / 2) / alpha; b[3] = alpha; } } } } static inline int multiply_alpha (int alpha, int color) { int temp = (alpha * color) + 0x80; return ((temp + (temp >> 8)) >> 8); } static unsigned char* premultiply_bgra (unsigned char* data, int width, int height, int stride) { uint8_t * retdata = reinterpret_cast(_cairo_malloc_ab(height, stride)); if (!retdata) return NULL; uint8_t * end = data + stride * height; for (uint8_t * in = data, *out = retdata; in < end; in += stride, out += stride) { for (int i = 0; i < width; i ++) { uint8_t *base = &in[4*i]; uint8_t alpha = base[3]; uint32_t p; if (alpha == 0) { p = 0; } else { uint8_t blue = base[0]; uint8_t green = base[1]; uint8_t red = base[2]; if (alpha != 0xff) { blue = multiply_alpha (alpha, blue); green = multiply_alpha (alpha, green); red = multiply_alpha (alpha, red); } p = (alpha << 0) | (red << 8) | (green << 16) | (blue << 24); } memcpy (&out[4*i], &p, sizeof (uint32_t)); } } return retdata; } static cairo_int_status_t _cairo_beos_surface_set_clip_region (cairo_beos_surface_t *surface, cairo_region_t *region) { cairo_beos_surface_t *surface = reinterpret_cast( abstract_surface); AutoLockView locker(surface->view); assert (locker); if (region == surface->clip_region) return CAIRO_INT_STATUS_SUCCESS; cairo_region_destroy (surface->clip_region); surface->clip_region = cairo_region_reference (region); if (region == NULL) { // No clipping surface->view->ConstrainClippingRegion(NULL); return CAIRO_INT_STATUS_SUCCESS; } int count = cairo_region_num_rectangles (region); BRegion bregion; for (int i = 0; i < count; ++i) { cairo_rectangle_int_t rect; cairo_region_get_rectangle (region, i, &rect); // Have to subtract one, because for pixman, the second coordinate // lies outside the rectangle. bregion.Include (_cairo_rectangle_to_brect (&rect)); } surface->view->ConstrainClippingRegion(&bregion); return CAIRO_INT_STATUS_SUCCESS; } /** * _cairo_beos_bitmap_to_surface: * * 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(bitmap->Bits()); int width = bounds.IntegerWidth() + 1; int height = bounds.IntegerHeight() + 1; unsigned char* premultiplied; if (cformat == CAIRO_FORMAT_ARGB32) { premultiplied = premultiply_bgra (bits, width, height, bitmap->BytesPerRow()); } else { premultiplied = reinterpret_cast( _cairo_malloc_ab(bitmap->BytesPerRow(), height)); if (premultiplied) memcpy(premultiplied, bits, bitmap->BytesPerRow() * height); } if (!premultiplied) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); cairo_image_surface_t* surf = reinterpret_cast (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; } /** * _cairo_image_surface_to_bitmap: * * 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_bgra (surface->data, surface->width, surface->height, surface->stride, reinterpret_cast(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: assert(0); return NULL; } } /** * _cairo_op_to_be_op: * * 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: // Does not actually work // XXX This is a fundamental compositing operator, it has to work! #if 1 return false; #else *beos_op = B_OP_ADD; return true; #endif 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_surface_t * _cairo_beos_surface_create_similar (void *abstract_surface, cairo_content_t content, int width, int height) { cairo_beos_surface_t *surface = reinterpret_cast( abstract_surface); if (width <= 0) width = 1; if (height <= 0) height = 1; BRect rect(0.0, 0.0, width - 1, height - 1); BBitmap* bmp; switch (content) { case CAIRO_CONTENT_ALPHA: return NULL; case CAIRO_CONTENT_COLOR_ALPHA: bmp = new BBitmap(rect, B_RGBA32, true); break; case CAIRO_CONTENT_COLOR: // Match the color depth if (surface->bitmap) { color_space space = surface->bitmap->ColorSpace(); // No alpha was requested -> make sure not to return // a surface with alpha if (space == B_RGBA32) space = B_RGB32; if (space == B_RGBA15) space = B_RGB15; bmp = new BBitmap(rect, space, true); } else { BScreen scr(surface->view->Window()); color_space space = B_RGB32; if (scr.IsValid()) space = scr.ColorSpace(); bmp = new BBitmap(rect, space, true); } break; default: ASSERT_NOT_REACHED; return NULL; } BView* view = new BView(rect, "Cairo bitmap view", B_FOLLOW_ALL_SIDES, 0); bmp->AddChild(view); return _cairo_beos_surface_create_internal(view, bmp, true); } static cairo_status_t _cairo_beos_surface_finish (void *abstract_surface) { cairo_beos_surface_t *surface = reinterpret_cast( abstract_surface); if (surface->owns_bitmap_view) { if (surface->bitmap) surface->bitmap->RemoveChild(surface->view); delete surface->view; delete surface->bitmap; surface->view = NULL; surface->bitmap = NULL; } cairo_region_destroy (surface->clip_region); 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) { cairo_beos_surface_t *surface = reinterpret_cast( abstract_surface); AutoLockView locker(surface->view); if (!locker) return CAIRO_STATUS_NO_MEMORY; /// XXX not exactly right, but what can we do? surface->view->Sync(); if (surface->bitmap) { *image_out = _cairo_beos_bitmap_to_surface (surface->bitmap); if (unlikely ((*image_out)->base.status)) return (*image_out)->base.status; *image_extra = NULL; return CAIRO_STATUS_SUCCESS; } BBitmap* bmp; if (_cairo_beos_view_to_bitmap(surface->view, &bmp) != OK) return CAIRO_STATUS_NO_MEMORY; /// XXX incorrect if the error was NOT_VISIBLE *image_out = _cairo_beos_bitmap_to_surface (bmp); if (unlikely ((*image_out)->base.status)) { delete bmp; return (*image_out)->base.status; } *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); if (image_extra != NULL) { BBitmap* bmp = static_cast(image_extra); delete bmp; } } static cairo_status_t _cairo_beos_surface_acquire_dest_image (void *abstract_surface, cairo_rectangle_int_t *interest_rect, cairo_image_surface_t **image_out, cairo_rectangle_int_t *image_rect, void **image_extra) { cairo_beos_surface_t *surface = reinterpret_cast( abstract_surface); AutoLockView locker(surface->view); if (!locker) { *image_out = NULL; *image_extra = NULL; return (cairo_status_t) CAIRO_INT_STATUS_NOTHING_TO_DO; } if (surface->bitmap) { surface->view->Sync(); *image_out = _cairo_beos_bitmap_to_surface(surface->bitmap); if (unlikely ((*image_out)->base.status)) return (*image_out)->base.status; 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_rectangle_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) return CAIRO_STATUS_NO_MEMORY; *image_rect = _brect_to_cairo_rectangle(rect); *image_out = _cairo_beos_bitmap_to_surface(bitmap); delete bitmap; if (unlikely ((*image_out)->base.status)) return (*image_out)->base.status; *image_extra = NULL; return CAIRO_STATUS_SUCCESS; } static void _cairo_beos_surface_release_dest_image (void *abstract_surface, cairo_rectangle_int_t *intersect_rect, cairo_image_surface_t *image, cairo_rectangle_int_t *image_rect, void *image_extra) { cairo_beos_surface_t *surface = reinterpret_cast( abstract_surface); AutoLockView locker(surface->view); if (!locker) return; BBitmap* bitmap_to_draw = _cairo_image_surface_to_bitmap(image); surface->view->PushState(); surface->view->SetDrawingMode(B_OP_COPY); surface->view->DrawBitmap (bitmap_to_draw, _cairo_rectangle_to_brect (image_rect)); surface->view->PopState(); delete bitmap_to_draw; cairo_surface_destroy(&image->base); } static cairo_int_status_t _cairo_beos_surface_composite (cairo_operator_t op, cairo_pattern_t *src, cairo_pattern_t *mask, void *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_region_t *clip_region) { cairo_beos_surface_t *surface = reinterpret_cast( dst); cairo_int_status_t status; AutoLockView locker(surface->view); if (!locker) return CAIRO_INT_STATUS_SUCCESS; drawing_mode mode; if (!_cairo_op_to_be_op(op, &mode)) return CAIRO_INT_STATUS_UNSUPPORTED; // XXX Masks are not yet supported if (mask) return CAIRO_INT_STATUS_UNSUPPORTED; // XXX should eventually support the others if (src->type != CAIRO_PATTERN_TYPE_SURFACE || src->extend != CAIRO_EXTEND_NONE) { return CAIRO_INT_STATUS_UNSUPPORTED; } // Can we maybe support other matrices as well? (scale? if the filter is right) int itx, ity; if (!_cairo_matrix_is_integer_translation(&src->matrix, &itx, &ity)) return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_beos_surface_set_clip_region (surface, clip_region); if (unlikely (status)) return status; BRect srcRect(src_x + itx, src_y + ity, src_x + itx + width - 1, src_y + ity + height - 1); BRect dstRect(dst_x, dst_y, dst_x + width - 1, dst_y + height - 1); cairo_surface_t* src_surface = reinterpret_cast(src)-> surface; // Get a bitmap BBitmap* bmp = NULL; bool free_bmp = false; if (_cairo_surface_is_image(src_surface)) { cairo_image_surface_t* img_surface = reinterpret_cast(src_surface); bmp = _cairo_image_surface_to_bitmap(img_surface); free_bmp = true; } else if (src_surface->backend == surface->base.backend) { cairo_beos_surface_t *beos_surface = reinterpret_cast(src_surface); if (beos_surface->bitmap) { AutoLockView locker(beos_surface->view); if (locker) beos_surface->view->Sync(); bmp = beos_surface->bitmap; } else { _cairo_beos_view_to_bitmap(surface->view, &bmp); free_bmp = true; } } if (!bmp) return CAIRO_INT_STATUS_UNSUPPORTED; // So, BeOS seems to screw up painting an opaque bitmap onto a // translucent one (it makes them partly transparent). Just return // unsupported. if (bmp->ColorSpace() == B_RGB32 && surface->bitmap && surface->bitmap->ColorSpace() == B_RGBA32 && (mode == B_OP_COPY || mode == B_OP_ALPHA)) { if (free_bmp) delete bmp; return CAIRO_INT_STATUS_UNSUPPORTED; } // Draw it on screen. surface->view->PushState(); // If our image rect is only a subrect of the desired size, and we // aren't using B_OP_ALPHA, then we need to fill the rect first. if (mode == B_OP_COPY && !bmp->Bounds().Contains(srcRect)) { rgb_color black = { 0, 0, 0, 0 }; surface->view->SetDrawingMode(mode); surface->view->SetHighColor(black); surface->view->FillRect(dstRect); } if (mode == B_OP_ALPHA && bmp->ColorSpace() == B_RGB32) { mode = B_OP_COPY; } surface->view->SetDrawingMode(mode); if (surface->bitmap && surface->bitmap->ColorSpace() == B_RGBA32) surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE); else surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); surface->view->DrawBitmap(bmp, srcRect, dstRect); surface->view->PopState(); if (free_bmp) delete bmp; return CAIRO_INT_STATUS_SUCCESS; } static cairo_int_status_t _cairo_beos_surface_fill_rectangles (void *abstract_surface, cairo_operator_t op, const cairo_color_t *color, cairo_rectangle_int_t *rects, int num_rects, cairo_region_t *clip_region) { cairo_beos_surface_t *surface = reinterpret_cast( abstract_surface); cairo_int_status_t status; if (num_rects <= 0) return CAIRO_INT_STATUS_SUCCESS; AutoLockView locker(surface->view); if (!locker) return CAIRO_INT_STATUS_SUCCESS; drawing_mode mode; if (!_cairo_op_to_be_op(op, &mode)) return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_beos_surface_set_clip_region (surface, clip_region); if (unlikely (status)) return status; rgb_color be_color = _cairo_color_to_be_color(color); if (mode == B_OP_ALPHA && be_color.alpha == 0xFF) mode = B_OP_COPY; // For CAIRO_OPERATOR_SOURCE, cairo expects us to use the premultiplied // color info. This is only relevant when drawing into an rgb24 buffer // (as for others, we can convert when asked for the image) if (mode == B_OP_COPY && be_color.alpha != 0xFF && (!surface->bitmap || surface->bitmap->ColorSpace() != B_RGBA32)) { be_color.red = color->red_short >> 8; be_color.green = color->green_short >> 8; be_color.blue = color->blue_short >> 8; } 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) surface->view->FillRect (_cairo_rectangle_to_brect (&rects[i])); surface->view->PopState(); return CAIRO_INT_STATUS_SUCCESS; } static cairo_bool_t _cairo_beos_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { cairo_beos_surface_t *surface = reinterpret_cast( abstract_surface); AutoLockView locker(surface->view); if (!locker) return FALSE; *rectangle = _brect_to_cairo_rectangle (surface->view->Bounds()); return TRUE; } static const struct _cairo_surface_backend cairo_beos_surface_backend = { CAIRO_SURFACE_TYPE_BEOS, _cairo_beos_surface_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 */ _cairo_beos_surface_composite, /* composite */ _cairo_beos_surface_fill_rectangles, NULL, /* composite_trapezoids */ NULL, /* create_span_renderer */ NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ _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 */ }; static cairo_surface_t * _cairo_beos_surface_create_internal (BView* view, BBitmap* bmp, bool owns_bitmap_view) { // Must use malloc, because cairo code will use free() on the surface cairo_beos_surface_t *surface = static_cast( malloc(sizeof(cairo_beos_surface_t))); if (surface == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); return const_cast(&_cairo_surface_nil); } cairo_content_t content = CAIRO_CONTENT_COLOR; if (bmp && (bmp->ColorSpace() == B_RGBA32 || bmp->ColorSpace() == B_RGBA15)) content = CAIRO_CONTENT_COLOR_ALPHA; _cairo_surface_init (&surface->base, &cairo_beos_surface_backend, NULL, /* device */ content); surface->view = view; surface->bitmap = bmp; surface->owns_bitmap_view = owns_bitmap_view; surface->clip_region = NULL; return &surface->base; } /** * 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. * * Since: TBD **/ 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. * * Since: TBD **/ cairo_surface_t * cairo_beos_surface_create_for_bitmap (BView* view, BBitmap* bmp) { return _cairo_beos_surface_create_internal(view, bmp); }