Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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. }
  985.