Back to index

lightning-sunbird  0.9+nobinonly
cairo-os2-surface.c
Go to the documentation of this file.
00001 /* Cairo - a vector graphics library with display and print output
00002  *
00003  * Copyright © 2005 Red Hat, Inc.
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it either under the terms of the GNU Lesser General Public
00007  * License version 2.1 as published by the Free Software Foundation
00008  * (the "LGPL") or, at your option, under the terms of the Mozilla
00009  * Public License Version 1.1 (the "MPL"). If you do not alter this
00010  * notice, a recipient may use your version of this file under either
00011  * the MPL or the LGPL.
00012  *
00013  * You should have received a copy of the LGPL along with this library
00014  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
00015  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00016  * You should have received a copy of the MPL along with this library
00017  * in the file COPYING-MPL-1.1
00018  *
00019  * The contents of this file are subject to the Mozilla Public License
00020  * Version 1.1 (the "License"); you may not use this file except in
00021  * compliance with the License. You may obtain a copy of the License at
00022  * http://www.mozilla.org/MPL/
00023  *
00024  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
00025  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
00026  * the specific language governing rights and limitations.
00027  *
00028  * The Original Code is the cairo graphics library.
00029  *
00030  * The Initial Developer of the Original Code is Red Hat, Inc.
00031  *
00032  * Contributor(s):
00033  *     Doodle <doodle@scenergy.dfmk.hu>
00034  */
00035 
00036 #include <stdio.h>
00037 #include <float.h>
00038 #include "cairoint.h"
00039 #include "cairo-os2-private.h"
00040 #include "fontconfig/fontconfig.h"
00041 
00042 /* Forward declaration */
00043 static const cairo_surface_backend_t cairo_os2_surface_backend;
00044 
00045 /* Unpublished API:
00046  *   GpiEnableYInversion = PMGPI.723
00047  *   GpiQueryYInversion = PMGPI.726
00048  *   BOOL APIENTRY GpiEnableYInversion(HPS hps, LONG lHeight);
00049  *   LONG APIENTRY GpiQueryYInversion(HPS hps);
00050  */
00051 
00052 BOOL APIENTRY GpiEnableYInversion(HPS hps, LONG lHeight);
00053 LONG APIENTRY GpiQueryYInversion(HPS hps);
00054 
00055 /* Initialization counter: */
00056 static int cairo_os2_initialization_count = 0;
00057 
00058 static void inline
00059 DisableFPUException (void)
00060 {
00061   unsigned short usCW;
00062 
00063   /* Some OS/2 PM API calls modify the FPU Control Word,
00064    * but forget to restore it.
00065    *
00066    * This can result in XCPT_FLOAT_INVALID_OPCODE exceptions,
00067    * so to be sure, we disable Invalid Opcode FPU exception
00068    * before using FPU stuffs.
00069    */
00070   usCW = _control87 (0, 0);
00071   usCW = usCW | EM_INVALID | 0x80;
00072   _control87 (usCW, MCW_EM | 0x80);
00073 }
00074 
00075 void cairo_os2_initialize (void)
00076 {
00077   /* This may initialize some stuffs */
00078 
00079   cairo_os2_initialization_count++;
00080   if (cairo_os2_initialization_count > 1) return;
00081 
00082   DisableFPUException ();
00083 
00084   /* Initialize FontConfig */
00085   FcInit ();
00086 }
00087 
00088 void cairo_os2_uninitialize (void)
00089 {
00090   /* This has to uninitialize some stuffs */
00091 
00092   if (cairo_os2_initialization_count <= 0) return;
00093   cairo_os2_initialization_count--;
00094   if (cairo_os2_initialization_count > 0) return;
00095 
00096   DisableFPUException ();
00097 
00098   /* Free allocated memories! */
00099   /* (Check cairo_debug_reset_static_date () for an example of this!) */
00100   _cairo_font_reset_static_data ();
00101 #ifdef CAIRO_HAS_FT_FONT
00102   _cairo_ft_font_reset_static_data ();
00103 #endif
00104 
00105   /* Uninitialize FontConfig */
00106   FcFini ();
00107 }
00108 
00109 static void _cairo_os2_surface_blit_pixels(cairo_os2_surface_t *pOS2Surface,
00110                                            HPS hpsBeginPaint,
00111                                            PRECTL prclBeginPaintRect)
00112 {
00113   POINTL aptlPoints[4];
00114   LONG lOldYInversion, rc = GPI_OK;
00115 
00116   /* Enable Y Inversion for the HPS, so the
00117    * GpiDrawBits will work with upside-top image, not with upside-down image!
00118    */
00119   lOldYInversion = GpiQueryYInversion(hpsBeginPaint);
00120   GpiEnableYInversion(hpsBeginPaint, pOS2Surface->bmi2BitmapInfo.cy-1);
00121 
00122   /* Target coordinates (Noninclusive) */
00123   aptlPoints[0].x = prclBeginPaintRect->xLeft;
00124   aptlPoints[0].y = prclBeginPaintRect->yBottom;
00125   
00126   aptlPoints[1].x = prclBeginPaintRect->xRight-1;
00127   aptlPoints[1].y = prclBeginPaintRect->yTop-1;
00128 
00129   /* Source coordinates (Inclusive) */
00130   aptlPoints[2].x = prclBeginPaintRect->xLeft;
00131   aptlPoints[2].y = prclBeginPaintRect->yBottom;
00132 
00133   aptlPoints[3].x = prclBeginPaintRect->xRight;
00134   aptlPoints[3].y = (prclBeginPaintRect->yTop);
00135 
00136   /* Some extra checking for limits
00137    * (Dunno if really needed, but had some crashes sometimes without it,
00138    *  while developing the code...)
00139    */
00140   
00141   {
00142     int i;
00143     for (i=0; i<4; i++)
00144     {
00145       if (aptlPoints[i].x<0)
00146         aptlPoints[i].x = 0;
00147       if (aptlPoints[i].y<0)
00148         aptlPoints[i].y = 0;
00149       if (aptlPoints[i].x>pOS2Surface->bmi2BitmapInfo.cx)
00150         aptlPoints[i].x = pOS2Surface->bmi2BitmapInfo.cx;
00151       if (aptlPoints[i].y>pOS2Surface->bmi2BitmapInfo.cy)
00152         aptlPoints[i].y = pOS2Surface->bmi2BitmapInfo.cy;
00153     }
00154   }
00155   
00156 
00157   /* Debug code to draw rectangle limits */
00158   /*
00159   {
00160     int x, y;
00161     unsigned char *pchPixels;
00162 
00163     pchPixels = pOS2Surface->pchPixels;
00164     for (x=0; x<pOS2Surface->bmi2BitmapInfo.cx; x++)
00165       for (y=0; y<pOS2Surface->bmi2BitmapInfo.cy; y++)
00166       {
00167         if ((x==0) ||
00168             (y==0) ||
00169             (x==y) ||
00170             (x>=pOS2Surface->bmi2BitmapInfo.cx-1) ||
00171             (y>=pOS2Surface->bmi2BitmapInfo.cy-1)
00172             )
00173           pchPixels[y*pOS2Surface->bmi2BitmapInfo.cx*4+x*4] = 255;
00174       }
00175   }
00176   */
00177   rc = GpiDrawBits (hpsBeginPaint,
00178                     pOS2Surface->pchPixels,
00179                     &(pOS2Surface->bmi2BitmapInfo),
00180                     4,
00181                     aptlPoints,
00182                     ROP_SRCCOPY,
00183                     BBO_IGNORE);
00184 
00185   if (rc != GPI_OK) {
00186     /* if GpiDrawBits () failed then this is most likely because the
00187      * display driver could not handle a 32bit bitmap. So we need to
00188      * - create a buffer that only contains 3 bytes per pixel
00189      * - change the bitmap info header to contain 24bit
00190      * - pass the new buffer to GpiDrawBits () again
00191      * - clean up the new buffer
00192      */
00193     BITMAPINFOHEADER2 bmpheader;
00194     unsigned char *pchPixBuf, *pchPixSource;
00195     void *pBufStart;
00196     unsigned int iPixels;
00197 
00198     /* allocate temporary pixel buffer */
00199     pchPixBuf = (unsigned char *) malloc (3 * pOS2Surface->bmi2BitmapInfo.cx *
00200                                           pOS2Surface->bmi2BitmapInfo.cy);
00201     pchPixSource = pOS2Surface->pchPixels; /* start at beginning of pixel buffer */
00202     pBufStart = pchPixBuf; /* remember beginning of the new pixel buffer */
00203 
00204     /* copy the first three bytes for each pixel but skip over the fourth */
00205     for (iPixels = 0; iPixels < pOS2Surface->bmi2BitmapInfo.cx * pOS2Surface->bmi2BitmapInfo.cy; iPixels++)
00206     {
00207       memcpy (pchPixBuf, pchPixSource, 3); /* copy BGR */
00208       pchPixSource += 4; /* jump over BGR and alpha channel in source buffer */
00209       pchPixBuf += 3; /* just advance over BGR in target buffer */
00210     }
00211 
00212     /* jump back to start of the buffer for display and cleanup */
00213     pchPixBuf = pBufStart;
00214 
00215     /* set up the bitmap header, but this time with 24bit depth only */
00216     memset (&bmpheader, 0, sizeof (bmpheader));
00217     bmpheader.cbFix = sizeof (BITMAPINFOHEADER2);
00218     bmpheader.cx = pOS2Surface->bmi2BitmapInfo.cx;
00219     bmpheader.cy = pOS2Surface->bmi2BitmapInfo.cy;
00220     bmpheader.cPlanes = pOS2Surface->bmi2BitmapInfo.cPlanes;
00221     bmpheader.cBitCount = 24;
00222     rc = GpiDrawBits (hpsBeginPaint,
00223                       pchPixBuf,
00224                       (PBITMAPINFO2)&bmpheader,
00225                       4,
00226                       aptlPoints,
00227                       ROP_SRCCOPY,
00228                       BBO_IGNORE);
00229 
00230     free (pchPixBuf);
00231   }
00232 
00233   /* Restore Y inversion */
00234   GpiEnableYInversion(hpsBeginPaint, lOldYInversion);
00235 }
00236 
00237 static void _cairo_os2_surface_get_pixels_from_screen(cairo_os2_surface_t *pOS2Surface,
00238                                                       HPS hpsBeginPaint,
00239                                                       PRECTL prclBeginPaintRect)
00240 {
00241   HPS hps;
00242   HDC hdc;
00243   HAB hab;
00244   SIZEL sizlTemp;
00245   HBITMAP hbmpTemp;
00246   BITMAPINFO2 bmi2Temp;
00247   POINTL aptlPoints[4];
00248   int y;
00249   char *pchTemp;
00250 
00251   /* To copy pixels from screen to our buffer, we do the following steps:
00252    *
00253    * - Blit pixels from screen to a HBITMAP:
00254    *   -- Create Memory Device Context
00255    *   -- Create a PS into it
00256    *   -- Create a HBITMAP
00257    *   -- Select HBITMAP into memory PS
00258    *   -- Blit dirty pixels from screen to HBITMAP
00259    * - Copy HBITMAP lines (pixels) into our buffer
00260    * - Free resources
00261    *
00262    * These steps will require an Anchor Block (HAB). However,
00263    * WinQUeryAnchorBlock() documentation says that HAB is not
00264    * used in current OS/2 implementations, OS/2 deduces all information
00265    * it needs from the TID. Anyway, we'd be in trouble if we'd have to
00266    * get a HAB where we only know a HPS...
00267    * So, we'll simply use a fake HAB.
00268    */
00269 
00270   hab = (HAB) 1; /* OS/2 doesn't really use HAB... */
00271 
00272   /* Create a memory device context */
00273   hdc=DevOpenDC(hab, OD_MEMORY,"*",0L, NULL, NULLHANDLE);
00274   if (!hdc)
00275   {
00276     /* printf("Could not create DC!\n"); */
00277     return;
00278   }
00279 
00280   /* Create a memory PS */
00281   sizlTemp.cx = prclBeginPaintRect->xRight - prclBeginPaintRect->xLeft;
00282   sizlTemp.cy = prclBeginPaintRect->yTop - prclBeginPaintRect->yBottom;
00283   /* printf("Creating PS: %dx%d\n", sizlTemp.cx, sizlTemp.cy);*/
00284   hps = GpiCreatePS (hab,
00285                      hdc,
00286                      &sizlTemp,
00287                      PU_PELS | GPIT_NORMAL | GPIA_ASSOC );
00288   if (!hps)
00289   {
00290     /* printf("Could not create PS!\n"); */
00291     DevCloseDC(hdc);
00292     return;
00293   }
00294 
00295   /* Create an uninitialized bitmap. */
00296   /* Prepare BITMAPINFO2 structure for our buffer */
00297 
00298   memset(&bmi2Temp, 0, sizeof(bmi2Temp));
00299   bmi2Temp.cbFix = sizeof(BITMAPINFOHEADER2);
00300   bmi2Temp.cx = sizlTemp.cx;
00301   bmi2Temp.cy = sizlTemp.cy;
00302   bmi2Temp.cPlanes = 1;
00303   bmi2Temp.cBitCount = 32;
00304 
00305   hbmpTemp = GpiCreateBitmap (hps,
00306                               (PBITMAPINFOHEADER2) &bmi2Temp,
00307                               0,
00308                               NULL,
00309                               NULL);
00310 
00311   if (!hbmpTemp)
00312   {
00313     /* printf("Could not create Bitmap!\n"); */
00314     GpiDestroyPS(hps);
00315     DevCloseDC(hdc);
00316     return;
00317   }
00318 
00319   /* Select the bitmap into the memory device context. */
00320   GpiSetBitmap(hps,
00321                hbmpTemp);
00322 
00323 
00324   /* Target coordinates (Noninclusive) */
00325   aptlPoints[0].x = 0;
00326   aptlPoints[0].y = 0;
00327   
00328   aptlPoints[1].x = sizlTemp.cx;
00329   aptlPoints[1].y = sizlTemp.cy;
00330 
00331   /* Source coordinates (Inclusive) */
00332   aptlPoints[2].x = prclBeginPaintRect->xLeft;
00333   aptlPoints[2].y = pOS2Surface->bmi2BitmapInfo.cy - prclBeginPaintRect->yBottom;
00334 
00335   aptlPoints[3].x = prclBeginPaintRect->xRight;
00336   aptlPoints[3].y = pOS2Surface->bmi2BitmapInfo.cy - prclBeginPaintRect->yTop;
00337 
00338   /*
00339   printf("BitBlt... Surface: (%d x %d)\n",
00340          pOS2Surface->bmi2BitmapInfo.cx,
00341          pOS2Surface->bmi2BitmapInfo.cy);
00342 
00343   printf("BitBlt... Target: (%d x %d) -> (%d x %d)\n",
00344          aptlPoints[0].x, aptlPoints[0].y,
00345          aptlPoints[1].x, aptlPoints[1].y);
00346   printf("BitBlt... Source: (%d x %d) -> (%d x %d)\n",
00347          aptlPoints[2].x, aptlPoints[2].y,
00348          aptlPoints[3].x, aptlPoints[3].y);
00349          */
00350 
00351   /* Blit pixels from screen to bitmap */
00352   GpiBitBlt(hps, hpsBeginPaint,
00353             4,
00354             aptlPoints,
00355             ROP_SRCCOPY,
00356             BBO_IGNORE);
00357 
00358   /* Now we have to extract the pixels from the bitmap. */
00359   /* printf("Getting pixels from bitmap...\n"); */
00360 
00361   pchTemp =
00362     pOS2Surface->pchPixels +
00363     (prclBeginPaintRect->yBottom)*pOS2Surface->bmi2BitmapInfo.cx*4 +
00364     prclBeginPaintRect->xLeft*4;
00365   for (y = 0; y<sizlTemp.cy; y++)
00366   {
00367     /* Get one line of pixels */
00368     GpiQueryBitmapBits(hps,
00369                        sizlTemp.cy - y - 1, /* lScanStart */
00370                        1,                   /* lScans */
00371                        pchTemp,
00372                        &bmi2Temp);
00373 
00374     /* Go for next line */
00375     pchTemp += pOS2Surface->bmi2BitmapInfo.cx*4;
00376   }
00377 
00378   /* Clean up resources */
00379   GpiSetBitmap(hps,
00380                (HBITMAP) NULL);
00381   GpiDeleteBitmap(hbmpTemp);
00382   GpiDestroyPS(hps);
00383   DevCloseDC(hdc);
00384 }
00385 
00386 static cairo_status_t _cairo_os2_surface_acquire_source_image (void                    *abstract_surface,
00387                                                                cairo_image_surface_t  **image_out,
00388                                                                void                   **image_extra)
00389 {
00390   cairo_os2_surface_t *pOS2Surface;
00391 
00392   pOS2Surface = (cairo_os2_surface_t *) abstract_surface;
00393   if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
00394   {
00395     /* Invalid parameter (wrong surface)! */
00396     return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
00397   }
00398 
00399   DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT);
00400 
00401   /* Increase lend counter */
00402   pOS2Surface->iPixelArrayLendCounter++;
00403 
00404   *image_out = pOS2Surface->pImageSurface;
00405   *image_extra = NULL;
00406 
00407   DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
00408 
00409   return CAIRO_STATUS_SUCCESS;
00410 }
00411 
00412 static void _cairo_os2_surface_release_source_image (void                   *abstract_surface,
00413                                                      cairo_image_surface_t  *image,
00414                                                      void                   *image_extra)
00415 {
00416   cairo_os2_surface_t *pOS2Surface;
00417 
00418   pOS2Surface = (cairo_os2_surface_t *) abstract_surface;
00419   if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
00420   {
00421     /* Invalid parameter (wrong surface)! */
00422     return;
00423   }
00424 
00425   /* Decrease Lend counter! */
00426   DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT);
00427 
00428   if (pOS2Surface->iPixelArrayLendCounter>0)
00429     pOS2Surface->iPixelArrayLendCounter--;
00430   DosPostEventSem(pOS2Surface->hevPixelArrayCameBack);
00431 
00432   DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
00433   return;
00434 }
00435 
00436 static cairo_status_t _cairo_os2_surface_acquire_dest_image (void                    *abstract_surface,
00437                                                              cairo_rectangle_t       *interest_rect,
00438                                                              cairo_image_surface_t  **image_out,
00439                                                              cairo_rectangle_t       *image_rect,
00440                                                              void                   **image_extra)
00441 {
00442   cairo_os2_surface_t *pOS2Surface;
00443 
00444   pOS2Surface = (cairo_os2_surface_t *) abstract_surface;
00445   if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
00446   {
00447     /* Invalid parameter (wrong surface)! */
00448     return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
00449   }
00450 
00451   DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT);
00452 
00453   /* Increase lend counter */
00454   pOS2Surface->iPixelArrayLendCounter++;
00455 
00456   *image_out = pOS2Surface->pImageSurface;
00457   *image_extra = NULL;
00458 
00459   image_rect->x = 0;
00460   image_rect->y = 0;
00461   image_rect->width = pOS2Surface->bmi2BitmapInfo.cx;
00462   image_rect->height = pOS2Surface->bmi2BitmapInfo.cy;
00463 
00464   DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
00465 
00466   return CAIRO_STATUS_SUCCESS;
00467 }
00468 
00469 static void _cairo_os2_surface_release_dest_image(void                   *abstract_surface,
00470                                                   cairo_rectangle_t      *interest_rect,
00471                                                   cairo_image_surface_t  *image,
00472                                                   cairo_rectangle_t      *image_rect,
00473                                                   void                   *image_extra)
00474 {
00475   cairo_os2_surface_t *pOS2Surface;
00476   RECTL rclToBlit;
00477 
00478   pOS2Surface = (cairo_os2_surface_t *) abstract_surface;
00479   if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
00480   {
00481     /* Invalid parameter (wrong surface)! */
00482     return;
00483   }
00484 
00485   /* So, we got back the image, and if all goes well, then
00486    * something has been changed inside the interest_rect.
00487    * So, we blit it to the screen!
00488    */
00489 
00490   if (pOS2Surface->bBlitAsChanges)
00491   {
00492     /* Get mutex, we'll work with the pixel array! */
00493     if (DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT)!=NO_ERROR)
00494     {
00495       /* Could not get mutex! */
00496       return;
00497     }
00498 
00499     if (pOS2Surface->hwndClientWindow)
00500     {
00501       /* We know the HWND, so let's invalidate the window region,
00502        * so the application will redraw itself, using the
00503        * cairo_os2_surface_repaint_window() API from its own PM thread.
00504        *
00505        * This is the safe method, which should be preferred every time.
00506        */
00507 
00508       rclToBlit.xLeft = interest_rect->x;
00509       rclToBlit.xRight = interest_rect->x+interest_rect->width; /* Noninclusive */
00510       rclToBlit.yTop = pOS2Surface->bmi2BitmapInfo.cy - (interest_rect->y);
00511       rclToBlit.yBottom = pOS2Surface->bmi2BitmapInfo.cy - (interest_rect->y+interest_rect->height); /* Noninclusive */
00512 
00513       WinInvalidateRect(pOS2Surface->hwndClientWindow,
00514                         &rclToBlit,
00515                         FALSE);
00516     } else
00517     {
00518       /* We don't know the HWND, so try to blit the pixels from here!
00519        * Please note that it can be problematic if this is not the PM thread!
00520        *
00521        * It can cause internal PM stuffs to be scewed up, for some reason.
00522        * Please always tell the HWND to the surface using the
00523        * cairo_os2_surface_set_HWND() API, and call cairo_os2_surface_repaint_window()
00524        * from your WM_PAINT, if it's possible!
00525        */
00526 
00527       rclToBlit.xLeft = interest_rect->x;
00528       rclToBlit.xRight = interest_rect->x+interest_rect->width; /* Noninclusive */
00529       rclToBlit.yBottom = interest_rect->y;
00530       rclToBlit.yTop = interest_rect->y+interest_rect->height; /* Noninclusive */
00531       /* Now blit there the stuffs! */
00532       _cairo_os2_surface_blit_pixels(pOS2Surface,
00533                                      pOS2Surface->hpsClientWindow,
00534                                      &rclToBlit);
00535     }
00536 
00537     /* Done! */
00538     DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
00539   }
00540   /* Also decrease Lend counter! */
00541   DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT);
00542 
00543   if (pOS2Surface->iPixelArrayLendCounter>0)
00544     pOS2Surface->iPixelArrayLendCounter--;
00545   DosPostEventSem(pOS2Surface->hevPixelArrayCameBack);
00546 
00547   DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
00548 }
00549 
00550 static cairo_int_status_t _cairo_os2_surface_get_extents(void *abstract_surface,
00551                                                          cairo_rectangle_t *rectangle)
00552 {
00553   cairo_os2_surface_t *pOS2Surface;
00554 
00555   pOS2Surface = (cairo_os2_surface_t *) abstract_surface;
00556   if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
00557   {
00558     /* Invalid parameter (wrong surface)! */
00559     return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
00560   }
00561 
00562   rectangle->x = 0;
00563   rectangle->y = 0;
00564   rectangle->width  = pOS2Surface->bmi2BitmapInfo.cx;
00565   rectangle->height = pOS2Surface->bmi2BitmapInfo.cy;
00566 
00567   return CAIRO_STATUS_SUCCESS;
00568 }
00569 
00570 cairo_surface_t *cairo_os2_surface_create(HPS hpsClientWindow,
00571                                           int iWidth, int iHeight)
00572 {
00573   cairo_os2_surface_t *pOS2Surface;
00574   int rc;
00575 
00576   /* Check the size of the window */
00577   if (
00578       (iWidth<=0) ||
00579       (iHeight<=0)
00580      )
00581   {
00582     /* Invalid window size! */
00583     _cairo_error(CAIRO_STATUS_NO_MEMORY);
00584     return (cairo_surface_t *) &_cairo_surface_nil;
00585   }
00586 
00587 
00588   pOS2Surface = (cairo_os2_surface_t *) malloc(sizeof(cairo_os2_surface_t));
00589   if (!pOS2Surface)
00590   {
00591     /* Not enough memory! */
00592     _cairo_error(CAIRO_STATUS_NO_MEMORY);
00593     return (cairo_surface_t *) &_cairo_surface_nil;
00594   }
00595 
00596   /* Initialize the OS/2 specific parts of the surface! */
00597 
00598   /* Create mutex semaphore */
00599   rc = DosCreateMutexSem(NULL,
00600                          &(pOS2Surface->hmtxUsePrivateFields),
00601                          0,
00602                          FALSE);
00603   if (rc!=NO_ERROR)
00604   {
00605     /* Could not create mutex semaphore! */
00606     _cairo_error(CAIRO_STATUS_NO_MEMORY);
00607     return (cairo_surface_t *) &_cairo_surface_nil;
00608   }
00609 
00610   /* Save PS handle */
00611   pOS2Surface->hpsClientWindow = hpsClientWindow;
00612 
00613   /* Defaults */
00614   pOS2Surface->hwndClientWindow = NULLHANDLE;
00615   pOS2Surface->bBlitAsChanges = TRUE;
00616   pOS2Surface->iPixelArrayLendCounter = 0;
00617   rc = DosCreateEventSem(NULL,
00618                          &(pOS2Surface->hevPixelArrayCameBack),
00619                          0,
00620                          FALSE);
00621 
00622   if (rc!=NO_ERROR)
00623   {
00624     /* Could not create event semaphore! */
00625     DosCloseMutexSem(pOS2Surface->hmtxUsePrivateFields);
00626     free(pOS2Surface);
00627     _cairo_error(CAIRO_STATUS_NO_MEMORY);
00628     return (cairo_surface_t *) &_cairo_surface_nil;
00629   }
00630 
00631   /* Prepare BITMAPINFO2 structure for our buffer */
00632   memset(&(pOS2Surface->bmi2BitmapInfo), 0, sizeof(pOS2Surface->bmi2BitmapInfo));
00633   pOS2Surface->bmi2BitmapInfo.cbFix = sizeof(BITMAPINFOHEADER2);
00634   pOS2Surface->bmi2BitmapInfo.cx = iWidth;
00635   pOS2Surface->bmi2BitmapInfo.cy = iHeight;
00636   pOS2Surface->bmi2BitmapInfo.cPlanes = 1;
00637   pOS2Surface->bmi2BitmapInfo.cBitCount = 32;
00638 
00639   /*
00640   pOS2Surface->bmi2BitmapInfo.ulCompression = BCA_UNCOMP;
00641   pOS2Surface->bmi2BitmapInfo.cbImage = 0;
00642   pOS2Surface->bmi2BitmapInfo.cxResolution = 70;
00643   pOS2Surface->bmi2BitmapInfo.cyResolution = 70;
00644   pOS2Surface->bmi2BitmapInfo.cclrUsed = 0;
00645   pOS2Surface->bmi2BitmapInfo.cclrImportant = 0;
00646   pOS2Surface->bmi2BitmapInfo.usUnits = BRU_METRIC;
00647   pOS2Surface->bmi2BitmapInfo.usReserved = 0;
00648   pOS2Surface->bmi2BitmapInfo.usRecording = BRA_BOTTOMUP;
00649   pOS2Surface->bmi2BitmapInfo.usRendering = BRH_NOTHALFTONED;
00650   pOS2Surface->bmi2BitmapInfo.cSize1 = 0;
00651   pOS2Surface->bmi2BitmapInfo.cSize2 = 0;
00652   pOS2Surface->bmi2BitmapInfo.ulColorEncoding = BCE_RGB;
00653   pOS2Surface->bmi2BitmapInfo.ulIdentifier = 0;
00654   */
00655 
00656   /* Allocate memory for pixels */
00657   pOS2Surface->pchPixels = (unsigned char *) malloc(iWidth * iHeight * 4);
00658   if (!(pOS2Surface->pchPixels))
00659   {
00660     /* Not enough memory for the pixels! */
00661     DosCloseEventSem(pOS2Surface->hevPixelArrayCameBack);
00662     DosCloseMutexSem(pOS2Surface->hmtxUsePrivateFields);
00663     free(pOS2Surface);
00664     _cairo_error(CAIRO_STATUS_NO_MEMORY);
00665     return (cairo_surface_t *) &_cairo_surface_nil;
00666   }
00667 
00668   /* This is possibly not needed, malloc'd space is
00669    * usually zero'd out!
00670    */
00671   /*
00672    memset(pOS2Surface->pchPixels, 0x00, swpTemp.cx * swpTemp.cy * 4);
00673    */
00674 
00675   /* Create image surface from pixel array */
00676   pOS2Surface->pImageSurface = (cairo_image_surface_t *)
00677     cairo_image_surface_create_for_data(pOS2Surface->pchPixels,
00678                                         CAIRO_FORMAT_RGB24,
00679                                         iWidth,      /* Width */
00680                                         iHeight,     /* Height */
00681                                         iWidth * 4); /* Rowstride */
00682 
00683   if (pOS2Surface->pImageSurface->base.status)
00684   {
00685     /* Could not create image surface! */
00686     free(pOS2Surface->pchPixels);
00687     DosCloseEventSem(pOS2Surface->hevPixelArrayCameBack);
00688     DosCloseMutexSem(pOS2Surface->hmtxUsePrivateFields);
00689     free(pOS2Surface);
00690     _cairo_error (CAIRO_STATUS_NO_MEMORY);
00691     return (cairo_surface_t *) &_cairo_surface_nil;
00692   }
00693 
00694   /* Initialize base surface */
00695   _cairo_surface_init(&pOS2Surface->base, &cairo_os2_surface_backend);
00696 
00697   /* All done! */
00698   return (cairo_surface_t *)pOS2Surface;
00699 }
00700 
00701 
00702 int  cairo_os2_surface_window_resized(cairo_surface_t *pSurface,
00703                                       int iNewWidth, int iNewHeight,
00704                                       int iTimeOut)
00705 {
00706   cairo_os2_surface_t *pOS2Surface;
00707   unsigned char *pchNewPixels;
00708   int rc;
00709   cairo_image_surface_t *pNewImageSurface;
00710 
00711   pOS2Surface = (cairo_os2_surface_t *) pSurface;
00712   if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
00713   {
00714     /* Invalid parameter (wrong surface)! */
00715     return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
00716   }
00717 
00718   if ((iNewWidth<=0) || (iNewHeight<=0))
00719   {
00720     /* Invalid size! */
00721     return CAIRO_STATUS_NO_MEMORY;
00722   }
00723 
00724   /* Allocate memory for new stuffs */
00725   pchNewPixels = (unsigned char *) malloc(iNewWidth * iNewHeight * 4);
00726   if (!pchNewPixels)
00727   {
00728     /* Not enough memory for the pixels!
00729      * Everything remains the same!
00730      */
00731     return CAIRO_STATUS_NO_MEMORY;
00732   }
00733 
00734   /* This is possibly not needed, malloc'd space is usually
00735    * already zero'd out!
00736    */
00737   /*
00738    memset(pchNewPixels, 0x00, iNewWidth * iNewHeight * 4);
00739    */
00740 
00741   /* Create image surface from new pixel array */
00742   pNewImageSurface = (cairo_image_surface_t *)
00743     cairo_image_surface_create_for_data(pchNewPixels,
00744                                         CAIRO_FORMAT_RGB24,
00745                                         iNewWidth,      /* Width */
00746                                         iNewHeight,     /* Height */
00747                                         iNewWidth * 4); /* Rowstride */
00748 
00749   if (pNewImageSurface->base.status)
00750   {
00751     /* Could not create image surface!
00752      * Everything remains the same!
00753      */
00754     free(pchNewPixels);
00755     return CAIRO_STATUS_NO_MEMORY;
00756   }
00757 
00758 
00759   /* Okay, new memory allocated, so it's time to swap old buffers
00760    * to new ones!
00761    */
00762 
00763   if (DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT)!=NO_ERROR)
00764   {
00765     /* Could not get mutex!
00766      * Everything remains the same!
00767      */
00768     cairo_surface_destroy((cairo_surface_t *) pNewImageSurface);
00769     free(pchNewPixels);
00770     return CAIRO_STATUS_NO_MEMORY;
00771   }
00772 
00773   /* We have to make sure that we won't destroy a surface which
00774    * is lent to some other code (Cairo is drawing into it)!
00775    */
00776   while (pOS2Surface->iPixelArrayLendCounter>0)
00777   {
00778     ULONG ulPostCount;
00779     DosResetEventSem(pOS2Surface->hevPixelArrayCameBack, &ulPostCount);
00780     DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
00781     /* Wait for somebody to return the pixels! */
00782     rc = DosWaitEventSem(pOS2Surface->hevPixelArrayCameBack, iTimeOut);
00783     if (rc!=NO_ERROR)
00784     {
00785       /* Either timeout or something wrong... Exit. */
00786       cairo_surface_destroy((cairo_surface_t *) pNewImageSurface);
00787       free(pchNewPixels);
00788       return CAIRO_STATUS_NO_MEMORY;
00789     }
00790     /* Okay, grab mutex and check counter again! */
00791     if (DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT)!=NO_ERROR)
00792     {
00793       /* Could not get mutex!
00794        * Everything remains the same!
00795        */
00796       cairo_surface_destroy((cairo_surface_t *) pNewImageSurface);
00797       free(pchNewPixels);
00798       return CAIRO_STATUS_NO_MEMORY;
00799     }
00800   }
00801 
00802   /* Destroy old image surface */
00803   cairo_surface_destroy((cairo_surface_t *) (pOS2Surface->pImageSurface));
00804   /* Destroy old pixel buffer */
00805   free(pOS2Surface->pchPixels);
00806   /* Set new image surface */
00807   pOS2Surface->pImageSurface = pNewImageSurface;
00808   /* Set new pixel buffer */
00809   pOS2Surface->pchPixels = pchNewPixels;
00810   /* Change bitmap2 structure */
00811   pOS2Surface->bmi2BitmapInfo.cx = iNewWidth;
00812   pOS2Surface->bmi2BitmapInfo.cy = iNewHeight;
00813 
00814   /* Okay, things have been changed successfully! */
00815   DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
00816   return CAIRO_STATUS_SUCCESS;
00817 }
00818 
00819 void cairo_os2_surface_repaint_window(cairo_surface_t *pSurface,
00820                                       HPS hpsBeginPaint,
00821                                       PRECTL prclBeginPaintRect)
00822 {
00823   cairo_os2_surface_t *pOS2Surface;
00824   RECTL rclTemp;
00825 
00826   pOS2Surface = (cairo_os2_surface_t *) pSurface;
00827   if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
00828   {
00829     /* Invalid parameter (wrong surface)! */
00830     return;
00831   }
00832 
00833   /* Manage defaults (NULLs) */
00834   if (hpsBeginPaint == NULL)
00835       hpsBeginPaint = pOS2Surface->hpsClientWindow;
00836 
00837   if (prclBeginPaintRect == NULL)
00838   {
00839     /* Update the whole window! */
00840     rclTemp.xLeft = 0;
00841     rclTemp.xRight = pOS2Surface->bmi2BitmapInfo.cx;
00842     rclTemp.yTop = pOS2Surface->bmi2BitmapInfo.cy;
00843     rclTemp.yBottom = 0;
00844   } else
00845   {
00846     /* Use the rectangle we got passed as parameter! */
00847     rclTemp.xLeft = prclBeginPaintRect->xLeft;
00848     rclTemp.xRight = prclBeginPaintRect->xRight;
00849     rclTemp.yTop = pOS2Surface->bmi2BitmapInfo.cy - prclBeginPaintRect->yBottom;
00850     rclTemp.yBottom = pOS2Surface->bmi2BitmapInfo.cy - prclBeginPaintRect->yTop ;
00851   }
00852 
00853   /* Get mutex, we'll work with the pixel array! */
00854   if (DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT)!=NO_ERROR)
00855   {
00856     /* Could not get mutex! */
00857     return;
00858   }
00859 
00860   if ((pOS2Surface->bDirtyAreaPresent) &&
00861       (pOS2Surface->rclDirtyArea.xLeft == rclTemp.xLeft) &&
00862       (pOS2Surface->rclDirtyArea.xRight == rclTemp.xRight) &&
00863       (pOS2Surface->rclDirtyArea.yTop == rclTemp.yTop) &&
00864       (pOS2Surface->rclDirtyArea.yBottom == rclTemp.yBottom))
00865   {
00866     /* Aha, this call was because of a dirty area, so in this case we
00867      * have to blit the pixels from the screen to the surface!
00868      */
00869     pOS2Surface->bDirtyAreaPresent = 0;
00870     _cairo_os2_surface_get_pixels_from_screen(pOS2Surface,
00871                                               hpsBeginPaint,
00872                                               &rclTemp);
00873   } else
00874   {
00875     /* Okay, we have the surface, have the HPS
00876      * (might be from WinBeginPaint() or from WinGetPS() )
00877      * Now blit there the stuffs!
00878      */
00879     _cairo_os2_surface_blit_pixels(pOS2Surface,
00880                                    hpsBeginPaint,
00881                                    &rclTemp);
00882   }
00883   /* Done! */
00884   DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
00885 }
00886 
00887 static cairo_status_t _cairo_os2_surface_finish(void *abstract_surface)
00888 {
00889   cairo_os2_surface_t *pOS2Surface;
00890 
00891   pOS2Surface = (cairo_os2_surface_t *) abstract_surface;
00892   if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
00893   {
00894     /* Invalid parameter (wrong surface)! */
00895     return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
00896   }
00897 
00898   DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT);
00899 
00900   /* Destroy old image surface */
00901   cairo_surface_destroy((cairo_surface_t *) (pOS2Surface->pImageSurface));
00902   /* Destroy old pixel buffer */
00903   free(pOS2Surface->pchPixels);
00904   DosCloseMutexSem(pOS2Surface->hmtxUsePrivateFields);
00905   DosCloseEventSem(pOS2Surface->hevPixelArrayCameBack);
00906 
00907   /* The memory itself will be free'd by the cairo_surface_destroy()
00908    * who called us.
00909    */
00910 
00911   return CAIRO_STATUS_SUCCESS;
00912 }
00913 
00914 void cairo_os2_surface_set_HWND(cairo_surface_t *pSurface,
00915                                 HWND hwndClientWindow)
00916 {
00917   cairo_os2_surface_t *pOS2Surface;
00918 
00919   pOS2Surface = (cairo_os2_surface_t *) pSurface;
00920   if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
00921   {
00922     /* Invalid parameter (wrong surface)! */
00923     return;
00924   }
00925 
00926   if (DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT)!=NO_ERROR)
00927   {
00928     /* Could not get mutex! */
00929     return;
00930   }
00931 
00932   pOS2Surface->hwndClientWindow = hwndClientWindow;
00933 
00934   DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
00935 }
00936 
00937 void cairo_os2_surface_set_blit_as_changes(cairo_surface_t *pSurface,
00938                                            int bBlitAsChanges)
00939 {
00940   cairo_os2_surface_t *pOS2Surface;
00941 
00942   pOS2Surface = (cairo_os2_surface_t *) pSurface;
00943   if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
00944   {
00945     /* Invalid parameter (wrong surface)! */
00946     return;
00947   }
00948 
00949   pOS2Surface->bBlitAsChanges = bBlitAsChanges;
00950 }
00951 
00952 int cairo_os2_surface_get_blit_as_changes(cairo_surface_t *pSurface)
00953 {
00954   cairo_os2_surface_t *pOS2Surface;
00955 
00956   pOS2Surface = (cairo_os2_surface_t *) pSurface;
00957   if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
00958   {
00959     /* Invalid parameter (wrong surface)! */
00960     return 0;
00961   }
00962 
00963   return pOS2Surface->bBlitAsChanges;
00964 }
00965 
00966 static cairo_status_t _cairo_os2_surface_mark_dirty_rectangle(void *surface,
00967                                                               int   x,
00968                                                               int   y,
00969                                                               int   width,
00970                                                               int   height)
00971 {
00972   cairo_os2_surface_t *pOS2Surface;
00973   RECTL rclToBlit;
00974 
00975   pOS2Surface = (cairo_os2_surface_t *) surface;
00976   if ((!pOS2Surface) || (pOS2Surface->base.backend != &cairo_os2_surface_backend))
00977   {
00978     /* Invalid parameter (wrong surface)! */
00979     return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
00980   }
00981 
00982   /* Get mutex, we'll work with the pixel array! */
00983   if (DosRequestMutexSem(pOS2Surface->hmtxUsePrivateFields, SEM_INDEFINITE_WAIT)!=NO_ERROR)
00984   {
00985     /* Could not get mutex! */
00986     return CAIRO_STATUS_NO_MEMORY;
00987   }
00988 
00989   /* Check for defaults */
00990   if (width<0)
00991     width = pOS2Surface->bmi2BitmapInfo.cx;
00992   if (height<0)
00993     height = pOS2Surface->bmi2BitmapInfo.cy;
00994 
00995   if (pOS2Surface->hwndClientWindow)
00996   {
00997     /* We know the HWND, so let's invalidate the window region,
00998      * so the application will redraw itself, using the
00999      * cairo_os2_surface_repaint_window() API from its own PM thread.
01000      * From that function we'll note that it's not a redraw but a
01001      * dirty-rectangle deal stuff, so we'll handle the things from
01002      * there.
01003      *
01004      * This is the safe method, which should be preferred every time.
01005      */
01006 
01007     rclToBlit.xLeft = x;
01008     rclToBlit.xRight = x + width; /* Noninclusive */
01009     rclToBlit.yTop = pOS2Surface->bmi2BitmapInfo.cy - (y);
01010     rclToBlit.yBottom = pOS2Surface->bmi2BitmapInfo.cy - (y + height); /* Noninclusive */
01011 
01012 #if 0
01013     if (pOS2Surface->bDirtyAreaPresent)
01014     {
01015       /* Yikes, there is already a dirty area which should be
01016        * cleaned up, but we'll overwrite it. Sorry.
01017        * TODO: Something clever should be done here.
01018        */
01019     }
01020 #endif
01021 
01022     /* Set up dirty area reminder stuff */
01023     memcpy(&(pOS2Surface->rclDirtyArea), &rclToBlit, sizeof(RECTL));
01024     pOS2Surface->bDirtyAreaPresent = 1;
01025 
01026     /* Invalidate window area */
01027     WinInvalidateRect(pOS2Surface->hwndClientWindow,
01028                       &rclToBlit,
01029                       FALSE);
01030   } else
01031   {
01032     /* We don't know the HWND, so try to blit the pixels from here!
01033      * Please note that it can be problematic if this is not the PM thread!
01034      *
01035      * It can cause internal PM stuffs to be scewed up, for some reason.
01036      * Please always tell the HWND to the surface using the
01037      * cairo_os2_surface_set_HWND() API, and call cairo_os2_surface_repaint_window()
01038      * from your WM_PAINT, if it's possible!
01039      */
01040 
01041     rclToBlit.xLeft = x;
01042     rclToBlit.xRight = x + width; /* Noninclusive */
01043     rclToBlit.yBottom = y;
01044     rclToBlit.yTop = y + height; /* Noninclusive */
01045     /* Now get the pixels from the screen! */
01046     _cairo_os2_surface_get_pixels_from_screen(pOS2Surface,
01047                                               pOS2Surface->hpsClientWindow,
01048                                               &rclToBlit);
01049   }
01050 
01051   /* Done! */
01052   DosReleaseMutexSem(pOS2Surface->hmtxUsePrivateFields);
01053 
01054   return CAIRO_STATUS_SUCCESS;
01055 }
01056 
01057 static const cairo_surface_backend_t cairo_os2_surface_backend = {
01058     NULL, /* create_similar */
01059     _cairo_os2_surface_finish,
01060     _cairo_os2_surface_acquire_source_image,
01061     _cairo_os2_surface_release_source_image,
01062     _cairo_os2_surface_acquire_dest_image,
01063     _cairo_os2_surface_release_dest_image,
01064     NULL, /* clone_similar */
01065     NULL, /* composite */
01066     NULL, /* fill_rectangles */
01067     NULL, /* composite_trapezoids */
01068     NULL, /* copy_page */
01069     NULL, /* show_page */
01070     NULL, /* set_clip_region */
01071     NULL, /* intersect_clip_path */
01072     _cairo_os2_surface_get_extents,
01073     NULL, /* show_glyphs */
01074     NULL, /* fill_path */
01075     NULL, /* get_font_options */
01076     NULL, /* flush */
01077     _cairo_os2_surface_mark_dirty_rectangle
01078 };