beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-beos-surface.cpp
blobc97641685fc0a3f7ffb6ae32d35ba4363a7f6610
1 /* vim:set ts=8 sw=4 noet cin: */
2 /* cairo - a vector graphics library with display and print output
4 * Copyright © 2005 Christian Biesinger <cbiesinger@web.de>
6 * This library is free software; you can redistribute it and/or
7 * modify it either under the terms of the GNU Lesser General Public
8 * License version 2.1 as published by the Free Software Foundation
9 * (the "LGPL") or, at your option, under the terms of the Mozilla
10 * Public License Version 1.1 (the "MPL"). If you do not alter this
11 * notice, a recipient may use your version of this file under either
12 * the MPL or the LGPL.
14 * You should have received a copy of the LGPL along with this library
15 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is Christian Biesinger
32 * <cbiesinger@web.de>
34 * Contributor(s):
37 // This is a C++ file in order to use the C++ BeOS API
39 #include "cairoint.h"
41 #include "cairo-beos.h"
43 #include "cairo-error-private.h"
44 #include "cairo-image-surface-inline.h"
46 #include <new>
48 #include <Bitmap.h>
49 #include <Region.h>
50 #if 0
51 #include <DirectWindow.h>
52 #endif
53 #include <Screen.h>
54 #include <Window.h>
55 #include <Locker.h>
57 /**
58 * SECTION:beos-surface
59 * @Title: BeOS Surfaces
60 * @Short_Description: BeOS surface support
61 * @See_Also: #cairo_surface_t
63 * The BeOS surface is used to render cairo graphics to BeOS views
64 * and bitmaps.
65 **/
67 #define CAIRO_INT_STATUS_SUCCESS (cairo_int_status_t)(CAIRO_STATUS_SUCCESS)
69 struct cairo_beos_surface_t {
70 cairo_surface_t base;
72 cairo_region_t *clip_region;
74 BView* view;
77 * A view is either attached to a bitmap, a window, or unattached.
78 * If it is attached to a window, we can copy data out of it using BScreen.
79 * If it is attached to a bitmap, we can read the bitmap data.
80 * If it is not attached, it doesn't draw anything, we need not bother.
82 * Since there doesn't seem to be a way to get the bitmap from a view if it
83 * is attached to one, we have to use a special surface creation function.
86 BBitmap* bitmap;
88 // If true, surface and view should be deleted when this surface is
89 // destroyed
90 bool owns_bitmap_view;
93 class AutoLockView {
94 public:
95 AutoLockView(BView* view) : mView(view) {
96 mOK = mView->LockLooper();
99 ~AutoLockView() {
100 if (mOK)
101 mView->UnlockLooper();
104 operator bool() {
105 return mOK;
108 private:
109 BView* mView;
110 bool mOK;
113 static cairo_surface_t *
114 _cairo_beos_surface_create_internal (BView* view,
115 BBitmap* bmp,
116 bool owns_bitmap_view = false);
118 static inline BRect
119 _cairo_rectangle_to_brect (const cairo_rectangle_int_t* rect)
121 // A BRect is one pixel wider than you'd think
122 return BRect (rect->x, rect->y,
123 rect->x + rect->width - 1,
124 rect->y + rect->height - 1);
127 static inline cairo_rectangle_int_t
128 _brect_to_cairo_rectangle (const BRect &rect)
130 cairo_rectangle_int_t retval;
131 retval.x = floor (rect.left);
132 retval.y = floor (rect.top);
133 retval.width = ceil (rect.right) - retval.x + 1;
134 retval.height = ceil (rect.bottom) - rectval.y + 1;
135 return retval;
138 static inline rgb_color
139 _cairo_color_to_be_color (const cairo_color_t *color)
141 // This factor ensures a uniform distribution of numbers
142 const float factor = 256 - 1e-5;
143 // Using doubles to have non-premultiplied colors
144 rgb_color be_color = { uint8(color->red * factor),
145 uint8(color->green * factor),
146 uint8(color->blue * factor),
147 uint8(color->alpha * factor) };
149 return be_color;
152 enum ViewCopyStatus {
154 NOT_VISIBLE, // The view or the interest rect is not visible on screen
155 ERROR // The view was visible, but the rect could not be copied. Probably OOM
159 * _cairo_beos_view_to_bitmap:
160 * @bitmap: [out] The resulting bitmap.
161 * @rect: [out] The rectangle that was copied, in the view's coordinate system
162 * @interestRect: If non-null, only this part of the view will be copied (view's coord system).
164 * Gets the contents of the view as a BBitmap*. Caller must delete the bitmap.
166 static ViewCopyStatus
167 _cairo_beos_view_to_bitmap (BView* view,
168 BBitmap** bitmap,
169 BRect* rect = NULL,
170 const BRect* interestRect = NULL)
172 *bitmap = NULL;
174 BWindow* wnd = view->Window();
175 // If we have no window, can't do anything
176 if (!wnd)
177 return NOT_VISIBLE;
179 view->Sync();
180 wnd->Sync();
182 #if 0
183 // Is it a direct window?
184 BDirectWindow* directWnd = dynamic_cast<BDirectWindow*>(wnd);
185 if (directWnd) {
186 // WRITEME
188 #endif
190 // Is it visible? If so, we can copy the content off the screen
191 if (wnd->IsHidden())
192 return NOT_VISIBLE;
194 BRect rectToCopy(view->Bounds());
195 if (interestRect)
196 rectToCopy = rectToCopy & *interestRect;
198 if (!rectToCopy.IsValid())
199 return NOT_VISIBLE;
201 BScreen screen(wnd);
202 BRect screenRect(view->ConvertToScreen(rectToCopy));
203 screenRect = screenRect & screen.Frame();
205 if (!screen.IsValid())
206 return NOT_VISIBLE;
208 if (rect)
209 *rect = view->ConvertFromScreen(screenRect);
211 if (screen.GetBitmap(bitmap, false, &screenRect) == B_OK)
212 return OK;
214 return ERROR;
217 static void
218 unpremultiply_bgra (unsigned char* data,
219 int width,
220 int height,
221 int stride,
222 unsigned char* retdata)
224 unsigned char* end = data + stride * height;
225 for (unsigned char* in = data, *out = retdata;
226 in < end;
227 in += stride, out += stride)
229 for (int i = 0; i < width; i ++) {
230 uint8_t *b = &out[4*i];
231 uint32_t pixel;
232 uint8_t alpha;
234 memcpy (&pixel, &data[4*i], sizeof (uint32_t));
235 alpha = pixel & 0xff;
236 if (alpha == 0) {
237 b[0] = b[1] = b[2] = b[3] = 0;
238 } else {
239 b[0] = (((pixel >> 24) & 0xff) * 255 + alpha / 2) / alpha;
240 b[1] = (((pixel >> 16) & 0xff) * 255 + alpha / 2) / alpha;
241 b[2] = (((pixel >> 8) & 0xff) * 255 + alpha / 2) / alpha;
242 b[3] = alpha;
248 static inline int
249 multiply_alpha (int alpha, int color)
251 int temp = (alpha * color) + 0x80;
252 return ((temp + (temp >> 8)) >> 8);
255 static unsigned char*
256 premultiply_bgra (unsigned char* data,
257 int width,
258 int height,
259 int stride)
261 uint8_t * retdata = reinterpret_cast<unsigned char*>(_cairo_malloc_ab(height, stride));
262 if (!retdata)
263 return NULL;
265 uint8_t * end = data + stride * height;
266 for (uint8_t * in = data, *out = retdata;
267 in < end;
268 in += stride, out += stride)
270 for (int i = 0; i < width; i ++) {
271 uint8_t *base = &in[4*i];
272 uint8_t alpha = base[3];
273 uint32_t p;
275 if (alpha == 0) {
276 p = 0;
277 } else {
278 uint8_t blue = base[0];
279 uint8_t green = base[1];
280 uint8_t red = base[2];
282 if (alpha != 0xff) {
283 blue = multiply_alpha (alpha, blue);
284 green = multiply_alpha (alpha, green);
285 red = multiply_alpha (alpha, red);
287 p = (alpha << 0) | (red << 8) | (green << 16) | (blue << 24);
289 memcpy (&out[4*i], &p, sizeof (uint32_t));
292 return retdata;
295 static cairo_int_status_t
296 _cairo_beos_surface_set_clip_region (cairo_beos_surface_t *surface,
297 cairo_region_t *region)
299 cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
300 abstract_surface);
301 AutoLockView locker(surface->view);
302 assert (locker);
304 if (region == surface->clip_region)
305 return CAIRO_INT_STATUS_SUCCESS;
307 cairo_region_destroy (surface->clip_region);
308 surface->clip_region = cairo_region_reference (region);
310 if (region == NULL) {
311 // No clipping
312 surface->view->ConstrainClippingRegion(NULL);
313 return CAIRO_INT_STATUS_SUCCESS;
316 int count = cairo_region_num_rectangles (region);
317 BRegion bregion;
318 for (int i = 0; i < count; ++i) {
319 cairo_rectangle_int_t rect;
321 cairo_region_get_rectangle (region, i, &rect);
322 // Have to subtract one, because for pixman, the second coordinate
323 // lies outside the rectangle.
324 bregion.Include (_cairo_rectangle_to_brect (&rect));
326 surface->view->ConstrainClippingRegion(&bregion);
327 return CAIRO_INT_STATUS_SUCCESS;
332 * _cairo_beos_bitmap_to_surface:
334 * Returns an addrefed image surface for a BBitmap. The bitmap need not outlive
335 * the surface.
337 static cairo_image_surface_t*
338 _cairo_beos_bitmap_to_surface (BBitmap* bitmap)
340 color_space format = bitmap->ColorSpace();
341 if (format != B_RGB32 && format != B_RGBA32) {
342 BBitmap bmp(bitmap->Bounds(), B_RGB32, true);
343 BView view(bitmap->Bounds(), "Cairo bitmap drawing view",
344 B_FOLLOW_ALL_SIDES, 0);
345 bmp.AddChild(&view);
347 view.LockLooper();
349 view.DrawBitmap(bitmap, BPoint(0.0, 0.0));
350 view.Sync();
352 cairo_image_surface_t* imgsurf = _cairo_beos_bitmap_to_surface(&bmp);
354 view.UnlockLooper();
355 bmp.RemoveChild(&view);
356 return imgsurf;
359 cairo_format_t cformat = format == B_RGB32 ?
360 CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32;
362 BRect bounds(bitmap->Bounds());
363 unsigned char* bits = reinterpret_cast<unsigned char*>(bitmap->Bits());
364 int width = bounds.IntegerWidth() + 1;
365 int height = bounds.IntegerHeight() + 1;
366 unsigned char* premultiplied;
367 if (cformat == CAIRO_FORMAT_ARGB32) {
368 premultiplied = premultiply_bgra (bits, width, height,
369 bitmap->BytesPerRow());
370 } else {
371 premultiplied = reinterpret_cast<unsigned char*>(
372 _cairo_malloc_ab(bitmap->BytesPerRow(), height));
373 if (premultiplied)
374 memcpy(premultiplied, bits, bitmap->BytesPerRow() * height);
376 if (!premultiplied)
377 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
379 cairo_image_surface_t* surf = reinterpret_cast<cairo_image_surface_t*>
380 (cairo_image_surface_create_for_data(premultiplied,
381 cformat,
382 width,
383 height,
384 bitmap->BytesPerRow()));
385 if (surf->base.status)
386 free(premultiplied);
387 else
388 _cairo_image_surface_assume_ownership_of_data(surf);
389 return surf;
393 * _cairo_image_surface_to_bitmap:
395 * Converts an image surface to a BBitmap. The return value must be freed with
396 * delete.
398 static BBitmap*
399 _cairo_image_surface_to_bitmap (cairo_image_surface_t* surface)
401 BRect size(0.0, 0.0, surface->width - 1, surface->height - 1);
402 switch (surface->format) {
403 case CAIRO_FORMAT_ARGB32: {
404 BBitmap* data = new BBitmap(size, B_RGBA32);
405 unpremultiply_bgra (surface->data,
406 surface->width,
407 surface->height,
408 surface->stride,
409 reinterpret_cast<unsigned char*>(data->Bits()));
410 return data;
412 case CAIRO_FORMAT_RGB24: {
413 BBitmap* data = new BBitmap(size, B_RGB32);
414 memcpy(data->Bits(), surface->data, surface->height * surface->stride);
415 return data;
417 default:
418 assert(0);
419 return NULL;
424 * _cairo_op_to_be_op:
426 * Converts a cairo drawing operator to a beos drawing_mode. Returns true if
427 * the operator could be converted, false otherwise.
429 static bool
430 _cairo_op_to_be_op (cairo_operator_t cairo_op,
431 drawing_mode* beos_op)
433 switch (cairo_op) {
434 case CAIRO_OPERATOR_SOURCE:
435 *beos_op = B_OP_COPY;
436 return true;
437 case CAIRO_OPERATOR_OVER:
438 *beos_op = B_OP_ALPHA;
439 return true;
441 case CAIRO_OPERATOR_ADD:
442 // Does not actually work
443 // XXX This is a fundamental compositing operator, it has to work!
444 #if 1
445 return false;
446 #else
447 *beos_op = B_OP_ADD;
448 return true;
449 #endif
451 case CAIRO_OPERATOR_CLEAR:
452 // Does not map to B_OP_ERASE - it replaces the dest with the low
453 // color, instead of transparency; could be done by setting low
454 // color appropriately.
456 case CAIRO_OPERATOR_IN:
457 case CAIRO_OPERATOR_OUT:
458 case CAIRO_OPERATOR_ATOP:
460 case CAIRO_OPERATOR_DEST:
461 case CAIRO_OPERATOR_DEST_OVER:
462 case CAIRO_OPERATOR_DEST_IN:
463 case CAIRO_OPERATOR_DEST_OUT:
464 case CAIRO_OPERATOR_DEST_ATOP:
466 case CAIRO_OPERATOR_XOR:
467 case CAIRO_OPERATOR_SATURATE:
469 default:
470 return false;
474 static cairo_surface_t *
475 _cairo_beos_surface_create_similar (void *abstract_surface,
476 cairo_content_t content,
477 int width,
478 int height)
480 cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
481 abstract_surface);
483 if (width <= 0)
484 width = 1;
485 if (height <= 0)
486 height = 1;
488 BRect rect(0.0, 0.0, width - 1, height - 1);
489 BBitmap* bmp;
490 switch (content) {
491 case CAIRO_CONTENT_ALPHA:
492 return NULL;
493 case CAIRO_CONTENT_COLOR_ALPHA:
494 bmp = new BBitmap(rect, B_RGBA32, true);
495 break;
496 case CAIRO_CONTENT_COLOR:
497 // Match the color depth
498 if (surface->bitmap) {
499 color_space space = surface->bitmap->ColorSpace();
500 // No alpha was requested -> make sure not to return
501 // a surface with alpha
502 if (space == B_RGBA32)
503 space = B_RGB32;
504 if (space == B_RGBA15)
505 space = B_RGB15;
506 bmp = new BBitmap(rect, space, true);
507 } else {
508 BScreen scr(surface->view->Window());
509 color_space space = B_RGB32;
510 if (scr.IsValid())
511 space = scr.ColorSpace();
512 bmp = new BBitmap(rect, space, true);
514 break;
515 default:
516 ASSERT_NOT_REACHED;
517 return NULL;
519 BView* view = new BView(rect, "Cairo bitmap view", B_FOLLOW_ALL_SIDES, 0);
520 bmp->AddChild(view);
521 return _cairo_beos_surface_create_internal(view, bmp, true);
524 static cairo_status_t
525 _cairo_beos_surface_finish (void *abstract_surface)
527 cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
528 abstract_surface);
529 if (surface->owns_bitmap_view) {
530 if (surface->bitmap)
531 surface->bitmap->RemoveChild(surface->view);
533 delete surface->view;
534 delete surface->bitmap;
536 surface->view = NULL;
537 surface->bitmap = NULL;
540 cairo_region_destroy (surface->clip_region);
542 return CAIRO_STATUS_SUCCESS;
545 static cairo_status_t
546 _cairo_beos_surface_acquire_source_image (void *abstract_surface,
547 cairo_image_surface_t **image_out,
548 void **image_extra)
550 cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
551 abstract_surface);
552 AutoLockView locker(surface->view);
553 if (!locker)
554 return CAIRO_STATUS_NO_MEMORY; /// XXX not exactly right, but what can we do?
557 surface->view->Sync();
559 if (surface->bitmap) {
560 *image_out = _cairo_beos_bitmap_to_surface (surface->bitmap);
561 if (unlikely ((*image_out)->base.status))
562 return (*image_out)->base.status;
564 *image_extra = NULL;
565 return CAIRO_STATUS_SUCCESS;
568 BBitmap* bmp;
569 if (_cairo_beos_view_to_bitmap(surface->view, &bmp) != OK)
570 return CAIRO_STATUS_NO_MEMORY; /// XXX incorrect if the error was NOT_VISIBLE
572 *image_out = _cairo_beos_bitmap_to_surface (bmp);
573 if (unlikely ((*image_out)->base.status)) {
574 delete bmp;
575 return (*image_out)->base.status;
577 *image_extra = bmp;
579 return CAIRO_STATUS_SUCCESS;
582 static void
583 _cairo_beos_surface_release_source_image (void *abstract_surface,
584 cairo_image_surface_t *image,
585 void *image_extra)
587 cairo_surface_destroy (&image->base);
589 if (image_extra != NULL) {
590 BBitmap* bmp = static_cast<BBitmap*>(image_extra);
591 delete bmp;
595 static cairo_status_t
596 _cairo_beos_surface_acquire_dest_image (void *abstract_surface,
597 cairo_rectangle_int_t *interest_rect,
598 cairo_image_surface_t **image_out,
599 cairo_rectangle_int_t *image_rect,
600 void **image_extra)
602 cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
603 abstract_surface);
605 AutoLockView locker(surface->view);
606 if (!locker) {
607 *image_out = NULL;
608 *image_extra = NULL;
609 return (cairo_status_t) CAIRO_INT_STATUS_NOTHING_TO_DO;
612 if (surface->bitmap) {
613 surface->view->Sync();
614 *image_out = _cairo_beos_bitmap_to_surface(surface->bitmap);
615 if (unlikely ((*image_out)->base.status))
616 return (*image_out)->base.status;
618 image_rect->x = 0;
619 image_rect->y = 0;
620 image_rect->width = (*image_out)->width;
621 image_rect->height = (*image_out)->height;
623 *image_extra = NULL;
624 return CAIRO_STATUS_SUCCESS;
627 BRect b_interest_rect (_cairo_rectangle_to_brect (interest_rect));
629 BRect rect;
630 BBitmap* bitmap;
631 ViewCopyStatus status = _cairo_beos_view_to_bitmap(surface->view, &bitmap,
632 &rect, &b_interest_rect);
633 if (status == NOT_VISIBLE) {
634 *image_out = NULL;
635 *image_extra = NULL;
636 return CAIRO_STATUS_SUCCESS;
638 if (status == ERROR)
639 return CAIRO_STATUS_NO_MEMORY;
641 *image_rect = _brect_to_cairo_rectangle(rect);
642 *image_out = _cairo_beos_bitmap_to_surface(bitmap);
643 delete bitmap;
644 if (unlikely ((*image_out)->base.status))
645 return (*image_out)->base.status;
647 *image_extra = NULL;
649 return CAIRO_STATUS_SUCCESS;
653 static void
654 _cairo_beos_surface_release_dest_image (void *abstract_surface,
655 cairo_rectangle_int_t *intersect_rect,
656 cairo_image_surface_t *image,
657 cairo_rectangle_int_t *image_rect,
658 void *image_extra)
660 cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
661 abstract_surface);
663 AutoLockView locker(surface->view);
664 if (!locker)
665 return;
667 BBitmap* bitmap_to_draw = _cairo_image_surface_to_bitmap(image);
668 surface->view->PushState();
670 surface->view->SetDrawingMode(B_OP_COPY);
672 surface->view->DrawBitmap (bitmap_to_draw,
673 _cairo_rectangle_to_brect (image_rect));
675 surface->view->PopState();
677 delete bitmap_to_draw;
678 cairo_surface_destroy(&image->base);
681 static cairo_int_status_t
682 _cairo_beos_surface_composite (cairo_operator_t op,
683 cairo_pattern_t *src,
684 cairo_pattern_t *mask,
685 void *dst,
686 int src_x,
687 int src_y,
688 int mask_x,
689 int mask_y,
690 int dst_x,
691 int dst_y,
692 unsigned int width,
693 unsigned int height,
694 cairo_region_t *clip_region)
696 cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
697 dst);
698 cairo_int_status_t status;
699 AutoLockView locker(surface->view);
700 if (!locker)
701 return CAIRO_INT_STATUS_SUCCESS;
703 drawing_mode mode;
704 if (!_cairo_op_to_be_op(op, &mode))
705 return CAIRO_INT_STATUS_UNSUPPORTED;
707 // XXX Masks are not yet supported
708 if (mask)
709 return CAIRO_INT_STATUS_UNSUPPORTED;
711 // XXX should eventually support the others
712 if (src->type != CAIRO_PATTERN_TYPE_SURFACE ||
713 src->extend != CAIRO_EXTEND_NONE)
715 return CAIRO_INT_STATUS_UNSUPPORTED;
718 // Can we maybe support other matrices as well? (scale? if the filter is right)
719 int itx, ity;
720 if (!_cairo_matrix_is_integer_translation(&src->matrix, &itx, &ity))
721 return CAIRO_INT_STATUS_UNSUPPORTED;
723 status = _cairo_beos_surface_set_clip_region (surface, clip_region);
724 if (unlikely (status))
725 return status;
727 BRect srcRect(src_x + itx,
728 src_y + ity,
729 src_x + itx + width - 1,
730 src_y + ity + height - 1);
731 BRect dstRect(dst_x, dst_y, dst_x + width - 1, dst_y + height - 1);
733 cairo_surface_t* src_surface = reinterpret_cast<cairo_surface_pattern_t*>(src)->
734 surface;
736 // Get a bitmap
737 BBitmap* bmp = NULL;
738 bool free_bmp = false;
739 if (_cairo_surface_is_image(src_surface)) {
740 cairo_image_surface_t* img_surface =
741 reinterpret_cast<cairo_image_surface_t*>(src_surface);
743 bmp = _cairo_image_surface_to_bitmap(img_surface);
744 free_bmp = true;
745 } else if (src_surface->backend == surface->base.backend) {
746 cairo_beos_surface_t *beos_surface =
747 reinterpret_cast<cairo_beos_surface_t*>(src_surface);
748 if (beos_surface->bitmap) {
749 AutoLockView locker(beos_surface->view);
750 if (locker)
751 beos_surface->view->Sync();
752 bmp = beos_surface->bitmap;
753 } else {
754 _cairo_beos_view_to_bitmap(surface->view, &bmp);
755 free_bmp = true;
759 if (!bmp)
760 return CAIRO_INT_STATUS_UNSUPPORTED;
762 // So, BeOS seems to screw up painting an opaque bitmap onto a
763 // translucent one (it makes them partly transparent). Just return
764 // unsupported.
765 if (bmp->ColorSpace() == B_RGB32 && surface->bitmap &&
766 surface->bitmap->ColorSpace() == B_RGBA32 &&
767 (mode == B_OP_COPY || mode == B_OP_ALPHA))
769 if (free_bmp)
770 delete bmp;
771 return CAIRO_INT_STATUS_UNSUPPORTED;
774 // Draw it on screen.
775 surface->view->PushState();
777 // If our image rect is only a subrect of the desired size, and we
778 // aren't using B_OP_ALPHA, then we need to fill the rect first.
779 if (mode == B_OP_COPY && !bmp->Bounds().Contains(srcRect)) {
780 rgb_color black = { 0, 0, 0, 0 };
782 surface->view->SetDrawingMode(mode);
783 surface->view->SetHighColor(black);
784 surface->view->FillRect(dstRect);
787 if (mode == B_OP_ALPHA && bmp->ColorSpace() == B_RGB32) {
788 mode = B_OP_COPY;
790 surface->view->SetDrawingMode(mode);
792 if (surface->bitmap && surface->bitmap->ColorSpace() == B_RGBA32)
793 surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE);
794 else
795 surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
797 surface->view->DrawBitmap(bmp, srcRect, dstRect);
799 surface->view->PopState();
801 if (free_bmp)
802 delete bmp;
804 return CAIRO_INT_STATUS_SUCCESS;
808 static cairo_int_status_t
809 _cairo_beos_surface_fill_rectangles (void *abstract_surface,
810 cairo_operator_t op,
811 const cairo_color_t *color,
812 cairo_rectangle_int_t *rects,
813 int num_rects,
814 cairo_region_t *clip_region)
816 cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
817 abstract_surface);
818 cairo_int_status_t status;
820 if (num_rects <= 0)
821 return CAIRO_INT_STATUS_SUCCESS;
823 AutoLockView locker(surface->view);
824 if (!locker)
825 return CAIRO_INT_STATUS_SUCCESS;
827 drawing_mode mode;
828 if (!_cairo_op_to_be_op(op, &mode))
829 return CAIRO_INT_STATUS_UNSUPPORTED;
831 status = _cairo_beos_surface_set_clip_region (surface, clip_region);
832 if (unlikely (status))
833 return status;
835 rgb_color be_color = _cairo_color_to_be_color(color);
837 if (mode == B_OP_ALPHA && be_color.alpha == 0xFF)
838 mode = B_OP_COPY;
840 // For CAIRO_OPERATOR_SOURCE, cairo expects us to use the premultiplied
841 // color info. This is only relevant when drawing into an rgb24 buffer
842 // (as for others, we can convert when asked for the image)
843 if (mode == B_OP_COPY && be_color.alpha != 0xFF &&
844 (!surface->bitmap || surface->bitmap->ColorSpace() != B_RGBA32))
846 be_color.red = color->red_short >> 8;
847 be_color.green = color->green_short >> 8;
848 be_color.blue = color->blue_short >> 8;
851 surface->view->PushState();
853 surface->view->SetDrawingMode(mode);
854 surface->view->SetHighColor(be_color);
855 if (surface->bitmap && surface->bitmap->ColorSpace() == B_RGBA32)
856 surface->view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
857 else
858 surface->view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
860 for (int i = 0; i < num_rects; ++i)
861 surface->view->FillRect (_cairo_rectangle_to_brect (&rects[i]));
863 surface->view->PopState();
865 return CAIRO_INT_STATUS_SUCCESS;
868 static cairo_bool_t
869 _cairo_beos_surface_get_extents (void *abstract_surface,
870 cairo_rectangle_int_t *rectangle)
872 cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
873 abstract_surface);
874 AutoLockView locker(surface->view);
875 if (!locker)
876 return FALSE;
878 *rectangle = _brect_to_cairo_rectangle (surface->view->Bounds());
879 return TRUE;
882 static const struct _cairo_surface_backend cairo_beos_surface_backend = {
883 CAIRO_SURFACE_TYPE_BEOS,
884 _cairo_beos_surface_create_similar,
885 _cairo_beos_surface_finish,
886 _cairo_beos_surface_acquire_source_image,
887 _cairo_beos_surface_release_source_image,
888 _cairo_beos_surface_acquire_dest_image,
889 _cairo_beos_surface_release_dest_image,
890 NULL, /* clone_similar */
891 _cairo_beos_surface_composite, /* composite */
892 _cairo_beos_surface_fill_rectangles,
893 NULL, /* composite_trapezoids */
894 NULL, /* create_span_renderer */
895 NULL, /* check_span_renderer */
896 NULL, /* copy_page */
897 NULL, /* show_page */
898 _cairo_beos_surface_get_extents,
899 NULL, /* old_show_glyphs */
900 NULL, /* get_font_options */
901 NULL, /* flush */
902 NULL, /* mark_dirty_rectangle */
903 NULL, /* scaled_font_fini */
904 NULL, /* scaled_glyph_fini */
906 NULL, /* paint */
907 NULL, /* mask */
908 NULL, /* stroke */
909 NULL, /* fill */
910 NULL /* show_glyphs */
913 static cairo_surface_t *
914 _cairo_beos_surface_create_internal (BView* view,
915 BBitmap* bmp,
916 bool owns_bitmap_view)
918 // Must use malloc, because cairo code will use free() on the surface
919 cairo_beos_surface_t *surface = static_cast<cairo_beos_surface_t*>(
920 malloc(sizeof(cairo_beos_surface_t)));
921 if (surface == NULL) {
922 _cairo_error (CAIRO_STATUS_NO_MEMORY);
923 return const_cast<cairo_surface_t*>(&_cairo_surface_nil);
926 cairo_content_t content = CAIRO_CONTENT_COLOR;
927 if (bmp && (bmp->ColorSpace() == B_RGBA32 || bmp->ColorSpace() == B_RGBA15))
928 content = CAIRO_CONTENT_COLOR_ALPHA;
929 _cairo_surface_init (&surface->base,
930 &cairo_beos_surface_backend,
931 NULL, /* device */
932 content);
934 surface->view = view;
935 surface->bitmap = bmp;
936 surface->owns_bitmap_view = owns_bitmap_view;
938 surface->clip_region = NULL;
940 return &surface->base;
944 * cairo_beos_surface_create:
945 * @view: The view to draw on
947 * Creates a Cairo surface that draws onto a BeOS BView.
948 * The caller must ensure that the view does not get deleted before the surface.
949 * If the view is attached to a bitmap rather than an on-screen window, use
950 * cairo_beos_surface_create_for_bitmap() instead of this function.
952 * Since: TBD
954 cairo_surface_t *
955 cairo_beos_surface_create (BView* view)
957 return cairo_beos_surface_create_for_bitmap(view, NULL);
961 * cairo_beos_surface_create_for_bitmap:
962 * @view: The view to draw on
963 * @bmp: The bitmap to which the view is attached
965 * Creates a Cairo surface that draws onto a BeOS BView which is attached to a
966 * BBitmap.
967 * The caller must ensure that the view and the bitmap do not get deleted
968 * before the surface.
970 * For views that draw to a bitmap (as opposed to a screen), use this function
971 * rather than cairo_beos_surface_create(). Not using this function WILL lead to
972 * incorrect behaviour.
974 * For now, only views that draw to the entire area of bmp are supported.
975 * The view must already be attached to the bitmap.
977 * Since: TBD
979 cairo_surface_t *
980 cairo_beos_surface_create_for_bitmap (BView* view,
981 BBitmap* bmp)
983 return _cairo_beos_surface_create_internal(view, bmp);