Tizen 2.0 Release
[framework/graphics/cairo.git] / src / cairo-beos-surface.cpp
1 /* vim:set ts=8 sw=4 noet cin: */
2 /* cairo - a vector graphics library with display and print output
3  *
4  * Copyright © 2005 Christian Biesinger <cbiesinger@web.de>
5  *
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.
13  *
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
19  *
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/
24  *
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.
28  *
29  * The Original Code is the cairo graphics library.
30  *
31  * The Initial Developer of the Original Code is Christian Biesinger
32  * <cbiesinger@web.de>
33  *
34  * Contributor(s):
35  */
36
37 // This is a C++ file in order to use the C++ BeOS API
38
39 #include "cairoint.h"
40
41 #include "cairo-beos.h"
42
43 #include "cairo-error-private.h"
44 #include "cairo-image-surface-inline.h"
45
46 #include <new>
47
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>
56
57 /**
58  * SECTION:beos-surface
59  * @Title: BeOS Surfaces
60  * @Short_Description: BeOS surface support
61  * @See_Also: #cairo_surface_t
62  *
63  * The BeOS surface is used to render cairo graphics to BeOS views 
64  * and bitmaps.
65  **/
66
67 #define CAIRO_INT_STATUS_SUCCESS (cairo_int_status_t)(CAIRO_STATUS_SUCCESS)
68
69 struct cairo_beos_surface_t {
70     cairo_surface_t base;
71
72     cairo_region_t *clip_region;
73
74     BView* view;
75
76     /*
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.
81      *
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.
84      */
85
86     BBitmap* bitmap;
87
88     // If true, surface and view should be deleted when this surface is
89     // destroyed
90     bool owns_bitmap_view;
91 };
92
93 class AutoLockView {
94     public:
95         AutoLockView(BView* view) : mView(view) {
96             mOK = mView->LockLooper();
97         }
98
99         ~AutoLockView() {
100             if (mOK)
101                 mView->UnlockLooper();
102         }
103
104         operator bool() {
105             return mOK;
106         }
107
108     private:
109         BView* mView;
110         bool   mOK;
111 };
112
113 static cairo_surface_t *
114 _cairo_beos_surface_create_internal (BView*   view,
115                                      BBitmap* bmp,
116                                      bool     owns_bitmap_view = false);
117
118 static inline BRect
119 _cairo_rectangle_to_brect (const cairo_rectangle_int_t* rect)
120 {
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);
125 }
126
127 static inline cairo_rectangle_int_t
128 _brect_to_cairo_rectangle (const BRect &rect)
129 {
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;
136 }
137
138 static inline rgb_color
139 _cairo_color_to_be_color (const cairo_color_t *color)
140 {
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) };
148
149     return be_color;
150 }
151
152 enum ViewCopyStatus {
153     OK,
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
156 };
157
158 /**
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).
163  *
164  * Gets the contents of the view as a BBitmap*. Caller must delete the bitmap.
165  **/
166 static ViewCopyStatus
167 _cairo_beos_view_to_bitmap (BView*       view,
168                             BBitmap**    bitmap,
169                             BRect*       rect = NULL,
170                             const BRect* interestRect = NULL)
171 {
172     *bitmap = NULL;
173
174     BWindow* wnd = view->Window();
175     // If we have no window, can't do anything
176     if (!wnd)
177         return NOT_VISIBLE;
178
179     view->Sync();
180     wnd->Sync();
181
182 #if 0
183     // Is it a direct window?
184     BDirectWindow* directWnd = dynamic_cast<BDirectWindow*>(wnd);
185     if (directWnd) {
186         // WRITEME
187     }
188 #endif
189
190     // Is it visible? If so, we can copy the content off the screen
191     if (wnd->IsHidden())
192         return NOT_VISIBLE;
193
194     BRect rectToCopy(view->Bounds());
195     if (interestRect)
196         rectToCopy = rectToCopy & *interestRect;
197
198     if (!rectToCopy.IsValid())
199         return NOT_VISIBLE;
200
201     BScreen screen(wnd);
202     BRect screenRect(view->ConvertToScreen(rectToCopy));
203     screenRect = screenRect & screen.Frame();
204
205     if (!screen.IsValid())
206         return NOT_VISIBLE;
207
208     if (rect)
209         *rect = view->ConvertFromScreen(screenRect);
210
211     if (screen.GetBitmap(bitmap, false, &screenRect) == B_OK)
212         return OK;
213
214     return ERROR;
215 }
216
217 static void
218 unpremultiply_bgra (unsigned char* data,
219                     int            width,
220                     int            height,
221                     int            stride,
222                     unsigned char* retdata)
223 {
224     unsigned char* end = data + stride * height;
225     for (unsigned char* in = data, *out = retdata;
226          in < end;
227          in += stride, out += stride)
228     {
229         for (int i = 0; i < width; i ++) {
230             uint8_t *b = &out[4*i];
231             uint32_t pixel;
232             uint8_t  alpha;
233
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;
243             }
244         }
245     }
246 }
247
248 static inline int
249 multiply_alpha (int alpha, int color)
250 {
251     int temp = (alpha * color) + 0x80;
252     return ((temp + (temp >> 8)) >> 8);
253 }
254
255 static unsigned char*
256 premultiply_bgra (unsigned char* data,
257                   int            width,
258                   int            height,
259                   int            stride)
260 {
261     uint8_t * retdata = reinterpret_cast<unsigned char*>(_cairo_malloc_ab(height, stride));
262     if (!retdata)
263         return NULL;
264
265     uint8_t * end = data + stride * height;
266     for (uint8_t * in = data, *out = retdata;
267          in < end;
268          in += stride, out += stride)
269     {
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;
274
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];
281
282                 if (alpha != 0xff) {
283                     blue  = multiply_alpha (alpha, blue);
284                     green = multiply_alpha (alpha, green);
285                     red   = multiply_alpha (alpha, red);
286                 }
287                 p = (alpha << 0) | (red << 8) | (green << 16) | (blue << 24);
288             }
289             memcpy (&out[4*i], &p, sizeof (uint32_t));
290         }
291     }
292     return retdata;
293 }
294
295 static cairo_int_status_t
296 _cairo_beos_surface_set_clip_region (cairo_beos_surface_t *surface,
297                                      cairo_region_t     *region)
298 {
299     cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
300                                                         abstract_surface);
301     AutoLockView locker(surface->view);
302     assert (locker);
303
304     if (region == surface->clip_region)
305         return CAIRO_INT_STATUS_SUCCESS;
306
307     cairo_region_destroy (surface->clip_region);
308     surface->clip_region = cairo_region_reference (region);
309
310     if (region == NULL) {
311         // No clipping
312         surface->view->ConstrainClippingRegion(NULL);
313         return CAIRO_INT_STATUS_SUCCESS;
314     }
315
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;
320
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));
325     }
326     surface->view->ConstrainClippingRegion(&bregion);
327     return CAIRO_INT_STATUS_SUCCESS;
328 }
329
330
331 /**
332  * _cairo_beos_bitmap_to_surface:
333  *
334  * Returns an addrefed image surface for a BBitmap. The bitmap need not outlive
335  * the surface.
336  **/
337 static cairo_image_surface_t*
338 _cairo_beos_bitmap_to_surface (BBitmap* bitmap)
339 {
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);
346
347         view.LockLooper();
348
349         view.DrawBitmap(bitmap, BPoint(0.0, 0.0));
350         view.Sync();
351
352         cairo_image_surface_t* imgsurf = _cairo_beos_bitmap_to_surface(&bmp);
353
354         view.UnlockLooper();
355         bmp.RemoveChild(&view);
356         return imgsurf;
357     }
358
359     cairo_format_t cformat = format == B_RGB32 ?
360                              CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32;
361
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);
375     }
376     if (!premultiplied)
377         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
378
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;
390 }
391
392 /**
393  * _cairo_image_surface_to_bitmap:
394  *
395  * Converts an image surface to a BBitmap. The return value must be freed with
396  * delete.
397  **/
398 static BBitmap*
399 _cairo_image_surface_to_bitmap (cairo_image_surface_t* surface)
400 {
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;
411         }
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;
416         }
417         default:
418             assert(0);
419             return NULL;
420     }
421 }
422
423 /**
424  * _cairo_op_to_be_op:
425  *
426  * Converts a cairo drawing operator to a beos drawing_mode. Returns true if
427  * the operator could be converted, false otherwise.
428  **/
429 static bool
430 _cairo_op_to_be_op (cairo_operator_t cairo_op,
431                     drawing_mode*    beos_op)
432 {
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;
440
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
450
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.
455
456     case CAIRO_OPERATOR_IN:
457     case CAIRO_OPERATOR_OUT:
458     case CAIRO_OPERATOR_ATOP:
459
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:
465
466     case CAIRO_OPERATOR_XOR:
467     case CAIRO_OPERATOR_SATURATE:
468
469     default:
470         return false;
471     }
472 }
473
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)
479 {
480     cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
481                                                         abstract_surface);
482
483     if (width <= 0)
484         width = 1;
485     if (height <= 0)
486         height = 1;
487
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);
513             }
514             break;
515         default:
516             ASSERT_NOT_REACHED;
517             return NULL;
518     }
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);
522 }
523
524 static cairo_status_t
525 _cairo_beos_surface_finish (void *abstract_surface)
526 {
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);
532
533         delete surface->view;
534         delete surface->bitmap;
535
536         surface->view = NULL;
537         surface->bitmap = NULL;
538     }
539
540     cairo_region_destroy (surface->clip_region);
541
542     return CAIRO_STATUS_SUCCESS;
543 }
544
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)
549 {
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?
555
556
557     surface->view->Sync();
558
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;
563
564         *image_extra = NULL;
565         return CAIRO_STATUS_SUCCESS;
566     }
567
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
571
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;
576     }
577     *image_extra = bmp;
578
579     return CAIRO_STATUS_SUCCESS;
580 }
581
582 static void
583 _cairo_beos_surface_release_source_image (void                  *abstract_surface,
584                                           cairo_image_surface_t *image,
585                                           void                  *image_extra)
586 {
587     cairo_surface_destroy (&image->base);
588
589     if (image_extra != NULL) {
590         BBitmap* bmp = static_cast<BBitmap*>(image_extra);
591         delete bmp;
592     }
593 }
594
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)
601 {
602     cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
603                                                         abstract_surface);
604
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;
610     }
611
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;
617
618         image_rect->x = 0;
619         image_rect->y = 0;
620         image_rect->width = (*image_out)->width;
621         image_rect->height = (*image_out)->height;
622
623         *image_extra = NULL;
624         return CAIRO_STATUS_SUCCESS;
625     }
626
627     BRect b_interest_rect (_cairo_rectangle_to_brect (interest_rect));
628
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;
637     }
638     if (status == ERROR)
639         return CAIRO_STATUS_NO_MEMORY;
640
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;
646
647     *image_extra = NULL;
648
649     return CAIRO_STATUS_SUCCESS;
650 }
651
652
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)
659 {
660     cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
661                                                         abstract_surface);
662
663     AutoLockView locker(surface->view);
664     if (!locker)
665         return;
666
667     BBitmap* bitmap_to_draw = _cairo_image_surface_to_bitmap(image);
668     surface->view->PushState();
669
670         surface->view->SetDrawingMode(B_OP_COPY);
671
672         surface->view->DrawBitmap (bitmap_to_draw,
673                                    _cairo_rectangle_to_brect (image_rect));
674
675     surface->view->PopState();
676
677     delete bitmap_to_draw;
678     cairo_surface_destroy(&image->base);
679 }
680
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)
695 {
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;
702
703     drawing_mode mode;
704     if (!_cairo_op_to_be_op(op, &mode))
705         return CAIRO_INT_STATUS_UNSUPPORTED;
706
707     // XXX Masks are not yet supported
708     if (mask)
709         return CAIRO_INT_STATUS_UNSUPPORTED;
710
711     // XXX should eventually support the others
712     if (src->type != CAIRO_PATTERN_TYPE_SURFACE ||
713         src->extend != CAIRO_EXTEND_NONE)
714     {
715         return CAIRO_INT_STATUS_UNSUPPORTED;
716     }
717
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;
722
723     status = _cairo_beos_surface_set_clip_region (surface, clip_region);
724     if (unlikely (status))
725         return status;
726
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);
732
733     cairo_surface_t* src_surface = reinterpret_cast<cairo_surface_pattern_t*>(src)->
734                                         surface;
735
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);
742
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;
756         }
757     }
758
759     if (!bmp)
760         return CAIRO_INT_STATUS_UNSUPPORTED;
761
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))
768     {
769         if (free_bmp)
770             delete bmp;
771         return CAIRO_INT_STATUS_UNSUPPORTED;
772     }
773
774     // Draw it on screen.
775     surface->view->PushState();
776
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 };
781
782             surface->view->SetDrawingMode(mode);
783             surface->view->SetHighColor(black);
784             surface->view->FillRect(dstRect);
785         }
786
787         if (mode == B_OP_ALPHA && bmp->ColorSpace() == B_RGB32) {
788             mode = B_OP_COPY;
789         }
790         surface->view->SetDrawingMode(mode);
791
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);
796
797         surface->view->DrawBitmap(bmp, srcRect, dstRect);
798
799     surface->view->PopState();
800
801     if (free_bmp)
802         delete bmp;
803
804     return CAIRO_INT_STATUS_SUCCESS;
805 }
806
807
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)
815 {
816     cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
817                                                         abstract_surface);
818     cairo_int_status_t status;
819
820     if (num_rects <= 0)
821         return CAIRO_INT_STATUS_SUCCESS;
822
823     AutoLockView locker(surface->view);
824     if (!locker)
825         return CAIRO_INT_STATUS_SUCCESS;
826
827     drawing_mode mode;
828     if (!_cairo_op_to_be_op(op, &mode))
829         return CAIRO_INT_STATUS_UNSUPPORTED;
830
831     status = _cairo_beos_surface_set_clip_region (surface, clip_region);
832     if (unlikely (status))
833         return status;
834
835     rgb_color be_color = _cairo_color_to_be_color(color);
836
837     if (mode == B_OP_ALPHA && be_color.alpha == 0xFF)
838         mode = B_OP_COPY;
839
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))
845     {
846         be_color.red   = color->red_short  >> 8;
847         be_color.green = color->green_short >> 8;
848         be_color.blue  = color->blue_short  >> 8;
849     }
850
851     surface->view->PushState();
852
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);
859
860         for (int i = 0; i < num_rects; ++i)
861             surface->view->FillRect (_cairo_rectangle_to_brect (&rects[i]));
862
863     surface->view->PopState();
864
865     return CAIRO_INT_STATUS_SUCCESS;
866 }
867
868 static cairo_bool_t
869 _cairo_beos_surface_get_extents (void                           *abstract_surface,
870                                  cairo_rectangle_int_t  *rectangle)
871 {
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;
877
878     *rectangle = _brect_to_cairo_rectangle (surface->view->Bounds());
879     return TRUE;
880 }
881
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 */
905
906     NULL, /* paint */
907     NULL, /* mask */
908     NULL, /* stroke */
909     NULL, /* fill */
910     NULL  /* show_glyphs */
911 };
912
913 static cairo_surface_t *
914 _cairo_beos_surface_create_internal (BView*   view,
915                                      BBitmap* bmp,
916                                      bool     owns_bitmap_view)
917 {
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);
924     }
925
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);
933
934     surface->view = view;
935     surface->bitmap = bmp;
936     surface->owns_bitmap_view = owns_bitmap_view;
937
938     surface->clip_region = NULL;
939
940     return &surface->base;
941 }
942
943 /**
944  * cairo_beos_surface_create:
945  * @view: The view to draw on
946  *
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.
951  *
952  * Since: TBD
953  **/
954 cairo_surface_t *
955 cairo_beos_surface_create (BView* view)
956 {
957     return cairo_beos_surface_create_for_bitmap(view, NULL);
958 }
959
960 /**
961  * cairo_beos_surface_create_for_bitmap:
962  * @view: The view to draw on
963  * @bmp: The bitmap to which the view is attached
964  *
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.
969  *
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.
973  *
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.
976  *
977  * Since: TBD
978  **/
979 cairo_surface_t *
980 cairo_beos_surface_create_for_bitmap (BView*   view,
981                                       BBitmap* bmp)
982 {
983     return _cairo_beos_surface_create_internal(view, bmp);
984 }