Back to index

plt-scheme  4.2.1
WindowDC.cc
Go to the documentation of this file.
00001 /*                                                      -*- C++ -*-
00002  *
00003  * Purpose: device context to draw drawables
00004  *          (windows and pixmaps, even if pixmaps are covered by wxMemoryDC)
00005  *
00006  * Authors: Markus Holzem and Julian Smart
00007  *
00008  * Copyright: (C) 2004-2009 PLT Scheme Inc.
00009  * Copyright: (C) 1995, AIAI, University of Edinburgh (Julian)
00010  * Copyright: (C) 1995, GNU (Markus)
00011  *
00012  * This program is free software; you can redistribute it and/or modify
00013  * it under the terms of the GNU General Public License as published by
00014  * the Free Software Foundation; either version 2 of the License, or
00015  * (at your option) any later version.
00016  *
00017  * This program is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  * GNU General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU General Public License
00023  * along with this program; if not, write to the Free Software
00024  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00025  * 02110-1301 USA.
00026  */
00027 
00028 #ifdef __GNUG__
00029 #pragma implementation "WindowDC.h"
00030 #endif
00031 
00032 #define  Uses_XLib
00033 #define  Uses_wxWindowDC
00034 #define  Uses_wxMemoryDC
00035 #define  Uses_wxList
00036 #include "wx.h"
00037 
00038 #ifdef USE_GL
00039 # include <GL/glx.h>
00040 # include <X11/Xcms.h>
00041 #endif
00042 #include "../../../wxcommon/wxGLConfig.h"
00043 
00044 #ifdef WX_USE_XRENDER
00045 # include <X11/Xcms.h>
00046 # include <X11/extensions/Xrender.h>
00047 # ifdef WX_USE_XFT
00048 #  include <X11/Xft/Xft.h>
00049 # endif
00050 #endif
00051 #include <X11/Intrinsic.h>
00052 
00053 #include "../wx_cairo.h"
00054 
00055 #define  UseXtRegions
00056 #include "wx_rgn.h"
00057 
00058 #include <math.h>
00059 #include <string.h>
00060 
00061 extern "C" { 
00062 #include "XWidgets/wxAllocColor.h"
00063 #include "XWidgets/xwTabString.h"
00064 extern int wx_alloc_color_is_fast;
00065 extern int wx_simple_r_start, wx_simple_g_start, wx_simple_b_start;
00066 };
00067 #include "wx_visual.h"
00068 
00069 // constant to convert radian to degree
00070 #define RAD2DEG 57.2957795131
00071 
00072 // shift between wxWindows RGB- and XColor RGB-values
00073 // (necessary because the values specify an intensity)
00074 #define SHIFT (8*(sizeof(short int)-sizeof(char)))
00075 
00076 // translate defines from wxDefines.h to XLib constants
00077 static int join_style[] = { JoinBevel, JoinMiter, JoinRound };
00078 static int cap_style[]  = { CapRound, CapProjecting, CapButt, CapNotLast };
00079 static int fill_rule[]  = { EvenOddRule, WindingRule };
00080 
00081 #ifdef WX_USE_CAIRO
00082 static cairo_line_join_t c_join_style[] = { CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_JOIN_MITER, CAIRO_LINE_JOIN_ROUND };
00083 static cairo_line_cap_t c_cap_style[]  = { CAIRO_LINE_CAP_ROUND, CAIRO_LINE_CAP_SQUARE, CAIRO_LINE_CAP_BUTT, CAIRO_LINE_CAP_BUTT };
00084 #endif
00085 
00086 // hatches, used for stippling in any DC
00087 #include <DeviceContexts/bdiag.xbm>
00088 #include <DeviceContexts/fdiag.xbm>
00089 #include <DeviceContexts/cdiag.xbm>
00090 #include <DeviceContexts/horiz.xbm>
00091 #include <DeviceContexts/verti.xbm>
00092 #include <DeviceContexts/cross.xbm>
00093 #define  num_hatches 6
00094 
00095 // This normalizes the graphics code to behave inm a standard way when
00096 // WX_STANDARD_GRAPHICS is 1.
00097 #if WX_STANDARD_GRAPHICS
00098 #define WX_GC_CF 1
00099 #else
00100 #define WX_GC_CF 0
00101 #endif
00102 
00103 #define IS_COLOR (DEPTH > 1)
00104 
00105 static Pixmap* hatch_bitmaps = NULL;
00106 
00107 #undef GETCOLORMAP
00108 #define GETCOLORMAP(x) wx_default_colormap
00109 
00110 #define wxMINI_SIZE 8
00111 
00112 #define wxPI 3.141592653589793
00113 
00114 //-----------------------------------------------------------------------------
00115 // create and destroy wxWindowDC
00116 //-----------------------------------------------------------------------------
00117 
00118 wxWindowDC::wxWindowDC(void) : wxDC()
00119 {
00120     __type = wxTYPE_DC_CANVAS;
00121 
00122     device = wxDEVICE_CANVAS;
00123 
00124     X = new wxWindowDC_Xintern; // allocate space for X data
00125 
00126     PEN_GC = BRUSH_GC = TEXT_GC = BG_GC = NULL;
00127     USER_REG = EXPOSE_REG = CURRENT_REG = NULL;
00128     DPY = NULL;
00129     SCN = NULL;
00130     DRAWABLE = 0;
00131     DRAW_WINDOW = 0;
00132     WIDTH = HEIGHT = DEPTH = 0;
00133 
00134     X->get_pixel_image_cache = NULL;
00135 
00136     if (!hatch_bitmaps) {
00137        Display *dpy = wxAPP_DISPLAY;
00138        Window  win  = RootWindow(dpy, DefaultScreen(dpy));
00139        wxREGGLOB(hatch_bitmaps);
00140        hatch_bitmaps = new WXGC_ATOMIC Pixmap[num_hatches];
00141        hatch_bitmaps[0] = XCreateBitmapFromData(dpy, win, bdiag_bits,
00142                                            bdiag_width, bdiag_height);
00143        hatch_bitmaps[1] = XCreateBitmapFromData(dpy, win, cdiag_bits,
00144                                            cdiag_width, cdiag_height);
00145        hatch_bitmaps[2] = XCreateBitmapFromData(dpy, win, fdiag_bits,
00146                                            fdiag_width, fdiag_height);
00147        hatch_bitmaps[3] = XCreateBitmapFromData(dpy, win, cross_bits,
00148                                            cross_width, cross_height);
00149        hatch_bitmaps[4] = XCreateBitmapFromData(dpy, win, horiz_bits,
00150                                            horiz_width, horiz_height);
00151        hatch_bitmaps[5] = XCreateBitmapFromData(dpy, win, verti_bits,
00152                                            verti_width, verti_height);
00153     }
00154 
00155     current_background_color->CopyFrom(wxWHITE);
00156     current_brush = wxWHITE_BRUSH;
00157     current_brush->Lock(1);
00158     current_pen = wxBLACK_PEN;
00159     current_pen->Lock(1);
00160     current_font = wxNORMAL_FONT;
00161 
00162     need_x_set_font = 1;
00163 }
00164 
00165 wxWindowDC::~wxWindowDC(void)
00166 {
00167     if (current_pen) current_pen->Lock(-1);
00168     if (current_brush) current_brush->Lock(-1);
00169     if (clipping) --clipping->locked;
00170 
00171     Destroy();
00172 
00173 #ifdef USE_GL
00174     X->wx_gl = NULL;
00175 #endif
00176 }
00177 
00178 #ifdef USE_GL
00179 wxGL *wxWindowDC::GetGL()
00180 {
00181   wxGL *gl;
00182 
00183   if (X->wx_gl)
00184     return X->wx_gl;
00185 
00186   gl = new wxGL();
00187   X->wx_gl = gl;
00188 
00189   if (DRAWABLE) {
00190     gl->Reset(X->gl_cfg, (long)DRAWABLE, __type == wxTYPE_DC_MEMORY);
00191   }
00192 
00193   return gl;
00194 }
00195 
00196 void wxWindowDC::SetGLConfig(wxGLConfig *cfg)
00197 {
00198   if (cfg)
00199     cfg = cfg->Clone();
00200   X->gl_cfg = cfg;
00201 }
00202 #endif
00203 
00204 //-----------------------------------------------------------------------------
00205 // drawing methods
00206 //-----------------------------------------------------------------------------
00207 
00208 static wxBitmap *ScaleBitmap(wxBitmap *src, 
00209                           int tw, int th,
00210                           double xsrc, double ysrc, double w, double h, 
00211                           Display *dpy, 
00212                           wxBitmap **_tmp, int *retval,
00213                           int forceMono, unsigned long whiteVal)
00214 {
00215   int sw, sh, i, j, ti, tj, xs, ys, mono;
00216   unsigned long pixel;
00217   wxBitmap *tmp;
00218   double scale_x, scale_y;
00219 
00220   *retval = TRUE;
00221 
00222   xs = (int)xsrc;
00223   ys = (int)ysrc;
00224   
00225   sw = src->GetWidth();
00226   sh = src->GetHeight();
00227 
00228   if (xs > sw)
00229     return NULL;
00230   if (ys > sh)
00231     return NULL;
00232 
00233   if (sw > w)
00234     sw = (int)w;
00235   if (sh > h)
00236     sh = (int)h;
00237 
00238   scale_x = (double)tw / sw;
00239   scale_y = (double)th / sh;
00240 
00241   mono = (src->GetDepth() == 1);
00242   if (forceMono && !mono)
00243     mono = 1;
00244   else
00245     forceMono = 0;
00246   tmp = new wxBitmap(tw, th, mono);
00247   *_tmp = tmp;
00248       
00249   if (tmp->Ok()) {
00250     XImage *simg, *timg;
00251     XGCValues values;
00252     GC agc;
00253     Pixmap spm, tpm;
00254     
00255     if (src->selectedTo)
00256       src->selectedTo->EndSetPixel();
00257     
00258     spm = GETPIXMAP(src);
00259     simg = XGetImage(dpy, spm, xs, ys, sw, sh, AllPlanes, ZPixmap);
00260     tpm = GETPIXMAP(tmp);
00261     timg = XGetImage(dpy, tpm, 0, 0, tw, th, AllPlanes, ZPixmap);
00262 
00263     for (ti = 0; ti < tw; ti++) {
00264       for (tj = 0; tj < th; tj++) {
00265        i = (int)(ti / scale_x);
00266        j = (int)(tj / scale_y);
00267        pixel = XGetPixel(simg, i, j);
00268        if (forceMono) {
00269          if (pixel == whiteVal)
00270            pixel = 0;
00271          else
00272            pixel = 1;
00273        }
00274        XPutPixel(timg, ti, tj, pixel);
00275       }
00276     }
00277 
00278     agc = XCreateGC(dpy, tpm, 0, &values);
00279     if (agc) {
00280       XPutImage(dpy, tpm, agc, timg, 0, 0, 0, 0, tw, th);
00281       XFreeGC(dpy, agc);
00282       *retval = 1;
00283     } else
00284       *retval = 0;
00285 
00286     XDestroyImage(simg);
00287     XDestroyImage(timg);
00288 
00289     xsrc = ysrc = 0;
00290     src = tmp;
00291 
00292     if (!*retval) {
00293       DELETE_OBJ tmp;
00294       *retval = FALSE;
00295       return NULL;
00296     }
00297   } else {
00298     DELETE_OBJ tmp;
00299     *retval = FALSE;
00300     return NULL;
00301   }
00302 
00303   return src;
00304 }
00305 
00306 static wxBitmap *IntersectBitmapRegion(GC agc, Region user_reg, Region expose_reg, wxBitmap *bmask, 
00307                                    Region *_free_rgn,
00308                                    int *_tx, int *_ty,
00309                                    int *_scaled_width, int *_scaled_height,
00310                                    double *_xsrc, double *_ysrc,
00311                                    Display *dpy, unsigned long whiteVal)
00312 {
00313   int overlap;
00314   Region free_rgn = *_free_rgn, rgn = NULL;
00315   int tx = *_tx, ty = *_ty;
00316   int scaled_width = *_scaled_width, scaled_height = *_scaled_height;
00317   double xsrc = *_xsrc, ysrc = *_ysrc;
00318 
00319   if (user_reg || expose_reg) {
00320     if (user_reg && expose_reg) {
00321       rgn = XCreateRegion();
00322       free_rgn = rgn;
00323       XIntersectRegion(expose_reg, user_reg, rgn);
00324     } else if (user_reg)
00325       rgn = user_reg;
00326     else
00327       rgn = expose_reg;
00328 
00329     if (bmask) {
00330       overlap = XRectInRegion(rgn, tx, ty, scaled_width, scaled_height);
00331 
00332       if (overlap == RectangleIn) {
00333        /* Overwriting the region later will be fine. */
00334        rgn = NULL;
00335       } else if (overlap == RectangleOut) {
00336        /* Mask will have no effect - all drawing is masked anyway */
00337        bmask = NULL;
00338       } else {
00339        /* This is the difficult case: mask bitmap and region combine. */
00340        XRectangle encl;
00341        long tx2, ty2, sw2, sh2;
00342 
00343        /* Common case: rgn is a sub-rectangle of the target: */
00344        XClipBox(rgn, &encl);
00345        tx2 = max(encl.x, tx);
00346        ty2 = max(encl.y, ty);
00347        sw2 = min(encl.x + encl.width, tx + scaled_width) - tx2;
00348        sh2 = min(encl.y + encl.height, ty + scaled_height) - ty2;
00349        
00350        if (XRectInRegion(rgn, tx2, ty2, sw2, sh2) == RectangleIn) {
00351          xsrc += (tx2 - tx);
00352          ysrc += (ty2 - ty);
00353          tx = tx2;
00354          ty = ty2;
00355          scaled_width = sw2;
00356          scaled_height = sh2;
00357          /* clipping is essentially manual, now: */
00358          rgn = NULL;
00359        } else {
00360          /* This is as complex as it gets. */
00361          /* We create a new region with the pixels of the bitmap. */
00362          Pixmap bpm;
00363          XImage *simg;
00364          Region bmrgn;
00365          int mi, mj;
00366          
00367          bpm = GETPIXMAP(bmask);
00368          simg = XGetImage(dpy, bpm, (long)xsrc, (long)ysrc, scaled_width, scaled_height, AllPlanes, ZPixmap);
00369          
00370          bmrgn = XCreateRegion();
00371 
00372          if (bmask->GetDepth() == 1)
00373            whiteVal = 0;
00374          
00375          for (mj = 0; mj < scaled_height; mj++) {
00376            encl.y = mj + ty;
00377            encl.height = 1;
00378            encl.width = 0;
00379            for (mi = 0; mi < scaled_width; mi++) {
00380              if (XGetPixel(simg, mi + (long)xsrc, mj + (long)ysrc) == whiteVal) {
00381               if (encl.width) {
00382                 XUnionRectWithRegion(&encl, bmrgn, bmrgn);
00383                 encl.width = 0;
00384               }
00385              } else {
00386               if (!encl.width)
00387                 encl.x = mi + tx;
00388               encl.width++;
00389              }
00390            }
00391 
00392            if (encl.width)
00393              XUnionRectWithRegion(&encl, bmrgn, bmrgn);
00394          }
00395          
00396          if (!free_rgn) {
00397            free_rgn = XCreateRegion();
00398            XUnionRegion(free_rgn, rgn, free_rgn);
00399            rgn = free_rgn;
00400          }
00401 
00402          /* Insert the bitmap-based region with the old one: */
00403          XIntersectRegion(bmrgn, rgn, rgn);
00404          XDestroyRegion(bmrgn);
00405 
00406          XDestroyImage(simg);
00407 
00408          bmask = NULL; /* done via rgn */
00409        }
00410       }
00411     }
00412   }
00413 
00414   if (rgn)
00415     XSetRegion(dpy, agc, rgn);
00416 
00417   if (bmask) {
00418     Pixmap mpm;
00419     int monoized = 0;
00420 
00421     if (bmask->GetDepth() != 1) {
00422       int ok;
00423       wxBitmap *tmp;
00424       monoized = 1;
00425       bmask = ScaleBitmap(bmask, bmask->GetWidth(), bmask->GetHeight(), 
00426                        0, 0, 
00427                        bmask->GetWidth(), bmask->GetHeight(),
00428                        dpy, &tmp, &ok,
00429                        1, whiteVal);
00430       mpm = GETPIXMAP(bmask);
00431       bmask = tmp;
00432     } else
00433       mpm = GETPIXMAP(bmask);
00434 
00435     XSetClipMask(dpy, agc, mpm);
00436     XSetClipOrigin(dpy, agc, tx - (long)xsrc, ty - (long)ysrc);
00437 
00438     if (!monoized)
00439       bmask = NULL; /* => no special mask to free */
00440   }
00441   
00442   *_free_rgn = free_rgn;
00443   *_tx = tx;
00444   *_ty = ty;
00445   *_scaled_width = scaled_width;
00446   *_scaled_height = scaled_height,
00447   *_xsrc = xsrc;
00448   *_ysrc = ysrc;
00449 
00450   return bmask;
00451 }
00452 
00453 #ifdef WX_USE_XRENDER
00454 static int xrender_here = -1;
00455 
00456 int wxXRenderHere(void)
00457 {
00458   if (xrender_here < 0) {
00459     /* Check whether Xrender is present at run time */
00460     int event_base, error_base;
00461     if (XRenderQueryExtension(wxAPP_DISPLAY, &event_base, &error_base) &&
00462        (XRenderFindVisualFormat(wxAPP_DISPLAY, wxAPP_VISUAL) != 0)) {
00463       xrender_here = 1;
00464     } else
00465       xrender_here = 0;
00466   }
00467 
00468   return xrender_here;
00469 }
00470 
00471 #define WX_RENDER_CAN_SCALE 1
00472 #if RENDER_MAJOR < 1
00473 # if RENDER_MINOR < 6
00474 #  undef WX_RENDER_CAN_SCALE
00475 #  define WX_RENDER_CAN_SCALE 0
00476 # endif
00477 #endif
00478 
00479 #ifndef WX_USE_XFT
00480 # define WX_XR_PICTURE
00481 #else
00482 # ifndef XFT_MAJOR
00483 /* No XftDrawPicture, so still use direct Xrender interface */
00484 #  define WX_OLD_XFT
00485 #  define WX_XR_PICTURE
00486 # endif
00487 #endif
00488 
00489 static XRenderPictFormat *format, *mask_format, *alpha_format;
00490 
00491 long wxMakeXrenderPicture(Drawable d, int color)
00492 {
00493   /* Create format records, if not done already: */
00494   if (!format) {
00495     XRenderPictFormat pf;
00496     
00497     format = XRenderFindVisualFormat(wxAPP_DISPLAY, wxAPP_VISUAL);
00498     
00499     pf.type = PictTypeDirect;
00500     pf.depth = 1;
00501     pf.direct.alpha = 0;
00502     pf.direct.alphaMask = 1;
00503     mask_format = XRenderFindFormat (wxAPP_DISPLAY,
00504                                  (PictFormatType|PictFormatDepth|PictFormatAlpha|PictFormatAlphaMask),
00505                                  &pf,
00506                                  0);
00507 
00508     pf.type = PictTypeDirect;
00509     pf.depth = 8;
00510     pf.direct.alpha = 0;
00511     pf.direct.alphaMask = 0xFF;
00512     alpha_format = XRenderFindFormat (wxAPP_DISPLAY,
00513                                   (PictFormatType|PictFormatDepth|PictFormatAlpha|PictFormatAlphaMask),
00514                                   &pf,
00515                                   0);
00516   }
00517 
00518   return (long)XRenderCreatePicture(wxAPP_DISPLAY,
00519                                 d,
00520                                 color ? format : mask_format,
00521                                 0,
00522                                 NULL);
00523 }
00524 
00525 long wxMakePicture(Drawable d, int color)
00526 {
00527 #ifdef WX_USE_XFT
00528   if (color) {
00529     return (long)XftDrawCreate(wxAPP_DISPLAY, d, wxAPP_VISUAL, wx_default_colormap);
00530   } else 
00531     return (long)XftDrawCreateBitmap(wxAPP_DISPLAY, d);
00532 #else
00533   return wxMakeXrenderPicture(d, color);
00534 #endif
00535 }
00536 
00537 void wxWindowDC::InitPicture() 
00538 {
00539   if (!X->picture) {
00540     unsigned long p;
00541     p = wxMakePicture(DRAWABLE, Colour);
00542     X->picture = p;
00543     InitPictureClip();
00544   }
00545 }
00546 
00547 void wxWindowDC::InitPictureClip()
00548 {
00549 # ifdef WX_USE_XFT
00550   if (CURRENT_REG)
00551     XftDrawSetClip(XFTDRAW, CURRENT_REG);
00552 # endif
00553 }
00554 
00555 void wxFreePicture(long p) {
00556 # ifdef WX_USE_XFT
00557   if (p) {
00558     XftDrawDestroy((XftDraw *)p);
00559   }
00560 # else
00561   if (p) {
00562     XRenderFreePicture(wxAPP_DISPLAY, (Picture)p);
00563   }
00564 # endif
00565 }
00566 #endif
00567 
00568 #ifndef WX_RENDER_CAN_SCALE
00569 # define WX_RENDER_CAN_SCALE 0
00570 #endif
00571 
00572 Bool wxWindowDC::Blit(double xdest, double ydest, double w, double h, wxBitmap *src,
00573                     double xsrc, double ysrc, int rop, wxColor *dcolor, wxBitmap *mask)
00574 {
00575     Bool retval = FALSE;
00576     wxPen *savePen, *apen;
00577     wxColor *saveBack;
00578     int scaled_width;
00579     int scaled_height;
00580     int tx, ty;
00581     wxBitmap *tmp = NULL, *tmp_mask = NULL;
00582     int should_xrender = 0;
00583 
00584     if (!DRAWABLE) // ensure that a drawable has been associated
00585       return FALSE;
00586     
00587     if (!src->Ok())
00588       return FALSE;
00589 
00590     if (src->selectedTo)
00591       src->selectedTo->EndSetPixel();
00592     if (mask && mask->selectedTo)
00593       mask->selectedTo->EndSetPixel();
00594 
00595 #ifdef WX_USE_XRENDER
00596     /* Decide whether to use Xrender before scaling...
00597 
00598        Non-monochrome masks require the Xrender extension. We expect
00599        that Xrender it's also better when we have a monochrome mask.
00600 
00601        Use Xrender extension when:
00602 
00603          - It's available at compile time and run time
00604         - There's a mask or scale
00605         - One of:
00606              * the rop is ignored (because the src is not mono)
00607              * the rop is wxSOLID (not wxSTIPPLE, which means "opaque")
00608         - One of:
00609              * the color is ignored (because the src is not mono)
00610             * the color is black/unspecified
00611 
00612       Under other circumstances, it doesn't work right. */
00613     
00614     
00615     
00616     should_xrender= (wxXRenderHere()
00617                    && (mask 
00618                       || (WX_RENDER_CAN_SCALE && ((user_scale_x != 1.0) || (user_scale_y != 1.0))))
00619                    && ((src->GetDepth() > 1)
00620                       || ((rop == wxSOLID)
00621                           && (!dcolor || (!dcolor->Red() && !dcolor->Green() && !dcolor->Blue())))));
00622 
00623 #endif
00624 
00625     tx = (int)XLOG2DEV(xdest);
00626     ty = (int)YLOG2DEV(ydest);
00627 
00628     w = ((src->GetWidth()  < w) ? src->GetWidth() : w);
00629     h = ((src->GetHeight() < h) ? src->GetHeight() : h);
00630 
00631     scaled_width = (int)XLOG2DEV(xdest + w) - tx;
00632     scaled_height = (int)YLOG2DEV(ydest + h) - ty;
00633 
00634     /* Handle scaling by creating a new, temporary bitmap: */
00635     if ((!should_xrender || !WX_RENDER_CAN_SCALE)
00636        && ((scaled_width != (int)w) || (scaled_height != (int)h))) {
00637       int retval;
00638       src = ScaleBitmap(src, scaled_width, scaled_height, xsrc, ysrc, w, h, DPY, &tmp, &retval, 0, 0);
00639       if (!src)
00640        return retval;
00641       if (mask) {
00642        mask = ScaleBitmap(mask, scaled_width, scaled_height, xsrc, ysrc, w, h, DPY, &tmp_mask, &retval, 
00643                         !should_xrender, wx_white_pixel);
00644        if (!mask) {
00645          DELETE_OBJ tmp;
00646          return retval;
00647        }
00648       }
00649 
00650       /* Temp bitmaps use only the relevant section: */
00651       xsrc = 0;
00652       ysrc = 0;
00653     }
00654 
00655     xsrc = floor(xsrc);
00656     ysrc = floor(ysrc);
00657     
00658 #ifdef WX_USE_XRENDER
00659     if (should_xrender) {
00660       /* Using Xrender... */
00661       Picture destp, srcp, maskp;
00662       wxBitmap *free_bmp = NULL;
00663       int mono_src;
00664 # ifndef WX_XR_PICTURE
00665       XftDraw *maskd = NULL;
00666 # endif
00667 
00668       mono_src = (src->GetDepth() == 1);
00669 
00670       /* Create an Xrender picture for each X pixmap.
00671         With old XFT version, give up on caching Picture. */
00672 # ifdef WX_OLD_XFT
00673       destp = wxMakeXrenderPicture(DRAWABLE, Colour);
00674 # else
00675       if (!X->picture)
00676        InitPicture();
00677       destp = PICTURE;
00678 # endif
00679 
00680 # ifdef WX_OLD_XFT
00681       {
00682        int sd;
00683        Pixmap spm;
00684        spm = GETPIXMAP(src);
00685        sd = src->GetDepth();
00686        srcp = wxMakeXrenderPicture(spm, sd != 1);
00687       }
00688 # else
00689       {
00690        long p;
00691        p = src->GetPicture();
00692        srcp = TO_PICTURE(p);
00693       }
00694 # endif
00695 
00696       /* Mask case is more difficult if it's not 1 bit: */
00697       if (mask) {
00698        if (mask->GetDepth() == 1) {
00699          /* Easy: */
00700 # ifdef WX_OLD_XFT
00701          Pixmap mpm;
00702          mpm = GETPIXMAP(mask);
00703          maskp = wxMakeXrenderPicture(mpm, 0);
00704 # else
00705          long p;
00706          p = mask->GetPicture();
00707          maskp = TO_PICTURE(p);
00708 # endif
00709        } else {
00710          /* Need an 8-bit alpha (grayscale) mask. */
00711          wxBitmap *bm;
00712 
00713          bm = mask->GetMaskBit();
00714          if (bm) {
00715            Pixmap bpm;
00716            
00717            bpm = GETPIXMAP(bm);
00718 
00719 # ifdef WX_XR_PICTURE
00720            maskp = XRenderCreatePicture(wxAPP_DISPLAY,
00721                                     bpm,
00722                                     alpha_format,
00723                                     0,
00724                                     NULL);
00725 # else
00726            maskd = XftDrawCreateAlpha(wxAPP_DISPLAY,
00727                                    bpm,
00728                                    8);
00729            maskp = TO_PICTURE(maskd);
00730 # endif
00731            
00732            free_bmp = bm;
00733          } else
00734            maskp = 0;
00735        }
00736       } else
00737        maskp = 0;
00738 
00739 # ifdef WX_XR_PICTURE
00740       /* Need to install clipping region, if any: */
00741       if (CURRENT_REG) {
00742        XRenderSetPictureClipRegion(wxAPP_DISPLAY, destp, CURRENT_REG);
00743       }
00744 # endif
00745 
00746 # if WX_RENDER_CAN_SCALE
00747       if ((scaled_width != (int)w) || (scaled_height != (int)h)) {
00748        XTransform xform;
00749        int ih = (int)h, iw = (int)w;
00750 
00751        xform.matrix[0][0] = scaled_height * iw;
00752        xform.matrix[0][1] = 0;
00753        xform.matrix[0][2] = 0;
00754 
00755        xform.matrix[1][0] = 0;
00756        xform.matrix[1][1] = scaled_width * ih; 
00757        xform.matrix[1][2] = 0;
00758 
00759        xform.matrix[2][0] = 0;
00760        xform.matrix[2][1] = 0;
00761        xform.matrix[2][2] = scaled_width * scaled_height; 
00762 
00763        XRenderSetPictureTransform(wxAPP_DISPLAY, srcp, &xform);
00764        if (maskp)
00765          XRenderSetPictureTransform(wxAPP_DISPLAY, maskp, &xform);
00766       }
00767 # endif
00768 
00769       /* This is the actual blit. */
00770       XRenderComposite(wxAPP_DISPLAY,
00771                      (mask || mono_src) ? PictOpOver : PictOpSrc,
00772                      srcp,
00773                      mask ? maskp : (mono_src ? srcp : 0),
00774                      destp,
00775                      (long)xsrc, (long)ysrc,
00776                      (long)xsrc, (long)ysrc,
00777                      tx, ty,
00778                      scaled_width,
00779                      scaled_height);
00780       
00781       retval = 1; /* or so we assume */
00782 
00783       /* Free temporary data (old Xft) */
00784 # ifdef WX_OLD_XFT
00785       XRenderFreePicture(wxAPP_DISPLAY, destp);
00786       XRenderFreePicture(wxAPP_DISPLAY, srcp);
00787       srcp = 0;
00788       if (!free_bmp) {
00789        XRenderFreePicture(wxAPP_DISPLAY, maskp);
00790        maskp = 0;
00791       }
00792 # else
00793 #  ifdef WX_XR_PICTURE
00794       if (CURRENT_REG) {
00795        XRenderPictureAttributes attribs;
00796        attribs.clip_mask = None;
00797        XRenderChangePicture(wxAPP_DISPLAY, destp, CPClipMask, &attribs);
00798       }
00799 #  endif
00800 # endif
00801 
00802       /* Free temporary data (all modes) */
00803       if (free_bmp) {
00804 # ifdef WX_XR_PICTURE
00805        XRenderFreePicture(wxAPP_DISPLAY, maskp);
00806 # else
00807        XftDrawDestroy(maskd);      
00808 # endif
00809        maskp = 0;
00810       }
00811 
00812 # if WX_RENDER_CAN_SCALE
00813       if ((srcp || maskp) 
00814          && ((scaled_width != (int)w) || (scaled_height != (int)h))) {
00815        XTransform xform;
00816 
00817        xform.matrix[0][0] = 1;
00818        xform.matrix[0][1] = 0;
00819        xform.matrix[0][2] = 0;
00820 
00821        xform.matrix[1][0] = 0;
00822        xform.matrix[1][1] = 1;
00823        xform.matrix[1][2] = 0;
00824 
00825        xform.matrix[2][0] = 0;
00826        xform.matrix[2][1] = 0;
00827        xform.matrix[2][2] = 1;
00828 
00829        if (srcp)
00830          XRenderSetPictureTransform(wxAPP_DISPLAY, srcp, &xform);
00831        if (maskp)
00832          XRenderSetPictureTransform(wxAPP_DISPLAY, maskp, &xform);
00833       }
00834 # endif
00835     } else {
00836 #endif
00837       /* Non-Xrender mode... */
00838 
00839       if (src->GetDepth() > 1) {
00840        /* This is color to mono/color.
00841           Neither rop nor dcolor matter, so use GCBlit. */
00842        retval = GCBlit(xdest, ydest, w, h, src, xsrc, ysrc, mask);
00843       } else {
00844 
00845        /* This is mono to mono/color */
00846 
00847        FreeGetPixelCache();
00848 
00849        savePen = current_pen;
00850        saveBack = new wxColour(current_background_color);
00851        /* Pen GC used for blit: */
00852        apen = wxThePenList->FindOrCreatePen(dcolor ? dcolor : wxBLACK, 0, rop);
00853        SetPen(apen);
00854 
00855        if (DRAWABLE && src->Ok()) {
00856          Region free_rgn = NULL;
00857 
00858          if (mask)
00859            tmp_mask = IntersectBitmapRegion(PEN_GC, EXPOSE_REG, USER_REG, mask,
00860                                         &free_rgn,
00861                                         &tx, &ty,
00862                                         &scaled_width, &scaled_height,
00863                                         &xsrc, &ysrc,
00864                                         DPY, wx_white_pixel);
00865 
00866          // Check if we're copying from a mono bitmap
00867          retval = TRUE;
00868          if ((rop == wxSOLID) || (rop == wxXOR)) {
00869            /* Seems like the easiest way to implement transparent backgrounds is to
00870               use a stipple. */
00871            XGCValues values;
00872            unsigned long mask = GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin;
00873            values.stipple = GETPIXMAP(src);
00874            values.fill_style = FillStippled;
00875            values.ts_x_origin = ((tx - (long)xsrc) % src->GetWidth());
00876            values.ts_y_origin = ((ty - (long)ysrc) % src->GetHeight());
00877            XChangeGC(DPY, PEN_GC, mask, &values);
00878            XFillRectangle(DPY, DRAWABLE, PEN_GC, tx, ty, scaled_width, scaled_height);
00879 
00880            /* Restore pen: */
00881            values.fill_style = FillSolid;
00882            XChangeGC(DPY, PEN_GC, GCFillStyle, &values);
00883          } else {
00884            /* Opaque (i.e., white pixels transferred as background) */
00885            Pixmap pm;
00886            pm = GETPIXMAP(src);
00887            XCopyPlane(DPY, pm, DRAWABLE, PEN_GC,
00888                      (long)xsrc, (long)ysrc,
00889                      scaled_width, scaled_height,
00890                      tx, ty, 1);
00891          }
00892          
00893          /* restore pen: */
00894          if (mask)
00895            SetCanvasClipping();
00896          
00897          if (free_rgn)
00898            XDestroyRegion(free_rgn);
00899        }
00900 
00901        SetPen(savePen);
00902        SetBackground(saveBack);
00903       }
00904 #ifdef WX_USE_XRENDER
00905     }
00906 #endif
00907     
00908     if (tmp) {
00909       DELETE_OBJ tmp;
00910     }
00911     if (tmp_mask) {
00912       DELETE_OBJ tmp_mask;
00913     }
00914 
00915     return retval; // #f => something wrong with the drawables
00916 }
00917 
00918 Bool wxWindowDC::GCBlit(double xdest, double ydest, double w, double h, wxBitmap *src,
00919                      double xsrc, double ysrc, wxBitmap *bmask)
00920 {
00921   /* A non-allocating (of collectable memory) blit, but may allocate
00922      when bmask is non-NULL.  Note that there's no rop or color. We do
00923      the simplest thing (wxSOLID with black) always. */
00924   Bool retval = FALSE;
00925   int scaled_width;
00926   int scaled_height;
00927   GC agc;
00928 
00929     if (!DRAWABLE) // ensure that a drawable has been associated
00930       return FALSE;
00931     
00932     if (!src->Ok())
00933       return FALSE;
00934 
00935     FreeGetPixelCache();
00936 
00937     if (src->selectedTo)
00938       src->selectedTo->EndSetPixel();
00939     
00940     xsrc = floor(xsrc);
00941     ysrc = floor(ysrc);
00942 
00943     scaled_width = src->GetWidth()  < XLOG2DEVREL(w) ? src->GetWidth()  : XLOG2DEVREL(w);
00944     scaled_height = src->GetHeight() < YLOG2DEVREL(h) ? src->GetHeight() : YLOG2DEVREL(h);
00945 
00946     if (DRAWABLE && src->Ok()) {
00947       XGCValues values;
00948       int mask = 0;
00949       Region free_rgn = (Region)NULL;
00950       int tx, ty;
00951       wxBitmap *tmp_mask;
00952 
00953       tx = XLOG2DEV(xdest);
00954       ty = YLOG2DEV(ydest);
00955 
00956       if ((DEPTH == 1) && (src->GetDepth() > 1)) {
00957        /* May need to flip 1 & 0... */
00958        if (wx_black_pixel == 1) {
00959          mask = GCFunction;
00960          values.function = GXcopyInverted;
00961        }
00962       }
00963 
00964       agc = XCreateGC(DPY, DRAWABLE, mask, &values);
00965       tmp_mask = IntersectBitmapRegion(agc, EXPOSE_REG, USER_REG, bmask, 
00966                                    &free_rgn,
00967                                    &tx, &ty,
00968                                    &scaled_width, &scaled_height,
00969                                    &xsrc, &ysrc,
00970                                    DPY, wx_white_pixel);
00971          
00972       retval = TRUE;
00973       if ((src->GetDepth() == 1) || (DEPTH == 1)) {
00974        /* mono to color/mono  or  color/mono to mono */
00975        Pixmap pm;
00976        pm = GETPIXMAP(src);
00977        XCopyPlane(DPY, pm, DRAWABLE, agc,
00978                  (long)xsrc, (long)ysrc,
00979                  scaled_width, scaled_height,
00980                  tx, ty, 1);
00981       } else if (src->GetDepth() == (int)DEPTH) {
00982        /* color to color */
00983        Pixmap pm;
00984        pm = GETPIXMAP(src);
00985        XCopyArea(DPY, pm, DRAWABLE, agc,
00986                 (long)xsrc, (long)ysrc,
00987                 scaled_width, scaled_height,
00988                 tx, ty);
00989       } else
00990        retval = FALSE;
00991 
00992       XFreeGC(DPY, agc);
00993 
00994       if (free_rgn)
00995        XDestroyRegion(free_rgn);
00996 
00997       if (tmp_mask)
00998        DELETE_OBJ tmp_mask;
00999     }
01000 
01001     return retval; // !retval => something is wrong with the drawables
01002 }
01003 
01004 #ifdef WX_USE_XRENDER
01005 static void SetToGray(XRenderColor *col, Pixel bg_pixel)
01006 {
01007   wxColour *c;
01008   int a, v;
01009 
01010   c = ((bg_pixel == wxGREY_PIXEL) ? wxGREY : wxBUTTON_COLOR);
01011 
01012   a = 0xD0;
01013   col->alpha = a << 8;
01014 
01015   /* Pre-multiply alpha. In the end, we want to shift the
01016      result by 8, so we skip the division by 255 that would
01017      scale alpha (since 255 is close enough to 256). */
01018   v = c->Red();
01019   col->red = v * a;
01020   v = c->Green();
01021   col->green = v * a;
01022   v = c->Blue();
01023   col->blue = v * a;
01024 }
01025 #endif
01026 
01027 void doDrawBitmapLabel(Display *dpy, 
01028                      Pixmap pixmap, Pixmap maskmap,
01029                      Drawable drawable, GC agc,
01030                      int x, int y, int width, int height, 
01031                      int depth, int mask_depth,
01032                      Region reg,
01033                      GC gray_gc,
01034                      Pixel bg_pixel)
01035 {
01036 #ifdef WX_USE_XRENDER
01037   if (maskmap && (mask_depth > 1)) {
01038     Picture dest, src, mask;
01039 
01040     dest = (Picture)wxMakeXrenderPicture(drawable, 1);
01041     src = (Picture)wxMakeXrenderPicture(pixmap, (depth > 1));
01042     mask = XRenderCreatePicture(wxAPP_DISPLAY,
01043                             maskmap,
01044                             alpha_format,
01045                             0,
01046                             NULL);
01047 
01048     XRenderSetPictureClipRegion(wxAPP_DISPLAY, dest, reg);
01049 
01050     XRenderComposite(wxAPP_DISPLAY,
01051                    PictOpOver,
01052                    src,
01053                    mask,
01054                    dest,
01055                    0, 0,
01056                    0, 0,
01057                    x, y, width, height);
01058 
01059     if (gray_gc) {
01060       XRenderColor col;
01061 
01062       SetToGray(&col, bg_pixel);
01063 
01064       XRenderFillRectangle(wxAPP_DISPLAY, PictOpOver, dest, &col,
01065                         x, y, width, height);
01066     }
01067 
01068     XRenderFreePicture(dpy, dest);
01069     XRenderFreePicture(wxAPP_DISPLAY, src);
01070     XRenderFreePicture(wxAPP_DISPLAY, mask);
01071     return;
01072   }
01073 #endif
01074    
01075   if (maskmap && (mask_depth == 1)) {
01076     XSetClipMask(dpy, agc, maskmap);
01077     XSetClipOrigin(dpy, agc, x, y);
01078   }
01079   
01080   if (depth == 1) {
01081     XCopyPlane(dpy, pixmap, drawable, agc,
01082               0, 0, width, height, x, y, 1);
01083   } else {
01084     XCopyArea(dpy, pixmap, drawable, agc,
01085              0, 0, width, height, x, y);
01086   }
01087   
01088   if (maskmap && (mask_depth == 1)) {
01089     XSetClipMask(dpy, agc, None);
01090     XSetClipOrigin(dpy, agc, 0, 0);
01091   }
01092 
01093   if (gray_gc) {
01094 #ifdef WX_USE_XRENDER
01095     if (wxXRenderHere()) {
01096       Picture dest;
01097       XRenderColor col;
01098       
01099       dest = (Picture)wxMakeXrenderPicture(drawable, 1);
01100       XRenderSetPictureClipRegion(wxAPP_DISPLAY, dest, reg);
01101 
01102       SetToGray(&col, bg_pixel);
01103       
01104       XRenderFillRectangle(wxAPP_DISPLAY, PictOpOver, dest, &col,
01105                         x, y, width, height);
01106       
01107       XRenderFreePicture(dpy, dest);
01108       return;
01109     }
01110 #endif
01111     XSetRegion(dpy, gray_gc, reg);
01112     XFillRectangle(dpy, drawable, gray_gc, x, y, width, height);
01113     XSetClipMask(dpy, gray_gc, None);
01114   }
01115 }
01116 
01117 extern "C" {
01118   void wxDrawBitmapLabel(Display *dpy, 
01119                       Pixmap pixmap, Pixmap maskmap,
01120                       Drawable drawable, GC agc,
01121                       int x, int y, int width, int height, 
01122                       int depth, int mask_depth,
01123                       Region reg, GC gray_gc, Pixel bg) {
01124     return doDrawBitmapLabel(dpy, pixmap, maskmap,
01125                           drawable, agc,
01126                           x, y, width, height, 
01127                           depth, mask_depth,
01128                           reg, gray_gc, bg);
01129   }
01130 };
01131 
01132 void wxWindowDC::Clear(void)
01133 {
01134   unsigned int w, h;
01135   Window wdummy; int sdummy; unsigned int udummy;
01136   
01137   if (!DRAWABLE) // ensure that a drawable has been associated
01138     return;
01139   
01140   FreeGetPixelCache();
01141   
01142   XGetGeometry(DPY, DRAWABLE, &wdummy, &sdummy, &sdummy,
01143               &w, &h, &udummy, &udummy);
01144   
01145 #ifdef WX_USE_CAIRO
01146   if (anti_alias) {
01147     wxColour *c;
01148     int r, g, b;
01149     
01150     InitCairoDev();
01151 
01152     c = current_background_color;
01153     r = c->Red();
01154     g = c->Green();
01155     b = c->Blue();
01156     cairo_set_source_rgba(CAIRO_DEV, 
01157                           r / 255.0, g / 255.0, b / 255.0,
01158                           current_alpha);
01159 
01160     cairo_new_path(CAIRO_DEV);
01161     cairo_move_to(CAIRO_DEV, 0, 0);
01162     cairo_line_to(CAIRO_DEV, w, 0);
01163     cairo_line_to(CAIRO_DEV, w, h);
01164     cairo_line_to(CAIRO_DEV, 0, h);
01165     cairo_fill(CAIRO_DEV);
01166 
01167     return;
01168   }
01169 #endif
01170  
01171   XFillRectangle(DPY, DRAWABLE, BG_GC, 0, 0, w, h);
01172 }
01173 
01174 void wxWindowDC::DrawArc(double x, double y, double w, double h, double start, double end)
01175 {
01176   int xx, yy, ww, hh;
01177   double xw, yh;
01178   double degrees1, degrees2;
01179   int alpha1, alpha2;
01180 
01181   if (!DRAWABLE) // ensure that a drawable has been associated
01182     return;
01183   
01184   FreeGetPixelCache();
01185 
01186 #ifdef WX_USE_CAIRO
01187   if (anti_alias) {
01188     InitCairoDev();
01189 
01190     start = -start;
01191     end = -end;
01192 
01193     if (SetCairoBrush()) {
01194       double xx, yy, ww, hh;
01195 
01196       xx = SmoothingXFormXB(x);
01197       yy = SmoothingXFormYB(y);
01198       ww = SmoothingXFormW(w, x);
01199       hh = SmoothingXFormH(h, y);
01200 
01201       cairo_save(CAIRO_DEV);
01202       cairo_translate(CAIRO_DEV, xx, yy);
01203       cairo_scale(CAIRO_DEV, ww, hh);
01204       cairo_new_path(CAIRO_DEV);
01205       cairo_move_to(CAIRO_DEV, 0.5, 0.5);
01206       cairo_arc_negative(CAIRO_DEV, 0.5, 0.5, 0.5, start, end);
01207       cairo_fill(CAIRO_DEV);
01208       cairo_restore(CAIRO_DEV);
01209     }
01210     
01211     
01212     if (SetCairoPen()) {
01213       double xx, yy, ww, hh;
01214       cairo_matrix_p m;
01215 
01216       xx = SmoothingXFormX(x);
01217       yy = SmoothingXFormY(y);
01218       ww = SmoothingXFormWL(w, x);
01219       hh = SmoothingXFormHL(h, y);
01220       
01221       cairo_set_matrix_create(m);
01222       cairo_current_matrix (CAIRO_DEV, m);
01223       cairo_translate(CAIRO_DEV, xx, yy);
01224       cairo_scale(CAIRO_DEV, ww, hh);
01225       cairo_new_path(CAIRO_DEV);
01226       cairo_arc_negative(CAIRO_DEV, 0.5, 0.5, 0.5, start, end);
01227       cairo__set_matrix(CAIRO_DEV, m);
01228       cairo_stroke(CAIRO_DEV);
01229       cairo_matrix_destroy(m);
01230     }
01231 
01232     return;
01233   }
01234 #endif
01235 
01236   xw = x + w, yh = y + h;
01237   
01238   xx = XLOG2DEV(x); yy = YLOG2DEV(y);
01239   ww = XLOG2DEV(xw) - xx; hh = YLOG2DEV(yh) - yy;
01240   
01241   degrees1 = start * RAD2DEG;
01242   degrees2 = end * RAD2DEG;
01243   alpha1 = int(degrees1 * 64.0);
01244   alpha2 = int((degrees2 - degrees1) * 64.0);
01245   while (alpha2 <= 0) {
01246     alpha2 += 360*64;
01247   }
01248   while (alpha1 > 360*64) {
01249     alpha1 -= 360*64;
01250   }
01251   
01252   if (current_brush && current_brush->GetStyle() != wxTRANSPARENT)
01253     XFillArc(DPY,DRAWABLE,BRUSH_GC,xx,yy,ww,hh,alpha1,alpha2);
01254   if (current_pen && current_pen->GetStyle() != wxTRANSPARENT)
01255     XDrawArc(DPY,DRAWABLE,PEN_GC,xx,yy,ww,hh,alpha1,alpha2);
01256 }
01257 
01258 void wxWindowDC::DrawEllipse(double x, double y, double w, double h)
01259 {
01260   int x1, y1, w1, h1;
01261   double xw, yh;
01262 
01263   if (!DRAWABLE) // ensure that a drawable has been associated
01264     return;
01265   
01266   FreeGetPixelCache();
01267 
01268 #ifdef WX_USE_CAIRO
01269   if (anti_alias) {
01270     DrawArc(x, y, w, h, 0, 2 * wxPI);
01271     return;
01272   }
01273 #endif
01274 
01275   xw = x + w, yh = y + h;
01276   
01277   x1 = XLOG2DEV(x);
01278   y1 = YLOG2DEV(y);
01279   w1 = XLOG2DEV(xw) - x1;
01280   h1 = YLOG2DEV(yh) - y1;
01281   
01282   if (current_brush && current_brush->GetStyle() != wxTRANSPARENT)
01283     XFillArc(DPY, DRAWABLE, BRUSH_GC, x1, y1,
01284             w1 - WX_GC_CF, h1 - WX_GC_CF, 0, 64*360);
01285   if (current_pen && current_pen->GetStyle() != wxTRANSPARENT)
01286     XDrawArc(DPY, DRAWABLE, PEN_GC, x1, y1,
01287             w1 - WX_GC_CF, h1 - WX_GC_CF, 0, 64*360);
01288 }
01289 
01290 void wxWindowDC::DrawLine(double x1, double y1, double x2, double y2)
01291 {
01292     if (!DRAWABLE) // ensure that a drawable has been associated
01293        return;
01294 
01295     FreeGetPixelCache();
01296 
01297     if (current_pen && current_pen->GetStyle() != wxTRANSPARENT) {
01298 #ifdef WX_USE_CAIRO
01299       if (anti_alias) {
01300        double xx1, yy1, xx2, yy2;
01301 
01302        InitCairoDev();
01303        
01304        SetCairoPen();
01305 
01306        xx1 = SmoothingXFormX(x1);
01307        yy1 = SmoothingXFormY(y1);
01308        xx2 = SmoothingXFormX(x2);
01309        yy2 = SmoothingXFormY(y2);
01310 
01311        cairo_new_path(CAIRO_DEV);
01312        cairo_move_to(CAIRO_DEV, xx1, yy1);
01313        cairo_line_to(CAIRO_DEV, xx2, yy2);
01314        cairo_stroke(CAIRO_DEV);
01315       } else
01316 #endif
01317        XDrawLine(DPY, DRAWABLE, PEN_GC,
01318                 XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2));
01319     }
01320 }
01321 
01322 void wxWindowDC::DrawLines(int n, wxPoint pts[], double xoff, double yoff)
01323 {
01324   XPoint *xpts;
01325   int i;
01326 
01327   if (!DRAWABLE) // ensure that a drawable has been associated
01328     return;
01329 
01330   if (!current_pen || (current_pen->GetStyle() == wxTRANSPARENT))
01331     return;
01332 
01333   if (n < 2)
01334     return;
01335 
01336   FreeGetPixelCache();
01337   
01338 #ifdef WX_USE_CAIRO
01339   if (anti_alias) {
01340     int i;
01341 
01342     InitCairoDev();
01343     
01344     SetCairoPen();
01345 
01346     cairo_new_path(CAIRO_DEV);
01347     cairo_move_to(CAIRO_DEV, SmoothingXFormX(pts[0].x + xoff), SmoothingXFormY(pts[0].y + yoff));
01348     for (i = 1; i < n; i++) {
01349       cairo_line_to(CAIRO_DEV, SmoothingXFormX(pts[i].x + xoff), SmoothingXFormY(pts[i].y + yoff));
01350     }
01351     cairo_stroke(CAIRO_DEV);    
01352 
01353     return;
01354   }
01355 #endif
01356 
01357   xpts = new WXGC_ATOMIC XPoint[n];
01358   for (i=0; i<n; ++i) {
01359     short x, y;
01360     x = XLOG2DEV(pts[i].x + xoff);
01361     xpts[i].x = x;
01362     y = YLOG2DEV(pts[i].y + yoff);
01363     xpts[i].y = y;
01364   }
01365   XDrawLines(DPY, DRAWABLE, PEN_GC, xpts, n, 0);
01366 }
01367 
01368 void wxWindowDC::DrawPoint(double x, double y)
01369 {
01370     if (!DRAWABLE) // ensure that a drawable has been associated
01371        return;
01372 
01373     FreeGetPixelCache();
01374     
01375     if (current_pen && current_pen->GetStyle() != wxTRANSPARENT)
01376        XDrawPoint(DPY, DRAWABLE, PEN_GC, XLOG2DEV(x), YLOG2DEV(y));
01377 }
01378 
01379 void wxWindowDC::DrawPolygon(int n, wxPoint pts[], double xoff, double yoff,
01380                           int fill)
01381 {
01382   XPoint *xpts;
01383 
01384   if (!DRAWABLE) // ensure that a drawable has been associated
01385     return;
01386 
01387   FreeGetPixelCache();
01388 
01389 #ifdef WX_USE_CAIRO
01390   if (anti_alias) {
01391     InitCairoDev();
01392 
01393     if (SetCairoBrush()) {
01394       int i;     
01395 
01396       if (fill == wxODDEVEN_RULE)
01397        cairo_set_fill_rule(CAIRO_DEV, CAIRO_FILL_RULE_EVEN_ODD);
01398       
01399       cairo_new_path(CAIRO_DEV);
01400       cairo_move_to(CAIRO_DEV, SmoothingXFormX(pts[0].x + xoff), SmoothingXFormY(pts[0].y + yoff));
01401       for (i = 1; i < n; i++) {
01402        cairo_line_to(CAIRO_DEV, SmoothingXFormX(pts[i].x + xoff), SmoothingXFormY(pts[i].y + yoff));
01403       }
01404       cairo_fill(CAIRO_DEV); 
01405 
01406       if (fill == wxODDEVEN_RULE)
01407        cairo_set_fill_rule(CAIRO_DEV, CAIRO_FILL_RULE_WINDING);
01408     }
01409 
01410     if (SetCairoPen()) {
01411       int i;
01412 
01413       cairo_new_path(CAIRO_DEV);
01414       cairo_move_to(CAIRO_DEV, SmoothingXFormX(pts[0].x + xoff), SmoothingXFormY(pts[0].y + yoff));
01415       for (i = 1; i < n; i++) {
01416        cairo_line_to(CAIRO_DEV, SmoothingXFormX(pts[i].x + xoff), SmoothingXFormY(pts[i].y + yoff));
01417       }
01418       cairo_close_path(CAIRO_DEV);
01419       cairo_stroke(CAIRO_DEV);
01420     }
01421 
01422     return;
01423   }
01424 #endif
01425   
01426   xpts = new WXGC_ATOMIC XPoint[n+1];
01427   for (int i=0; i<n; ++i) {
01428     short x, y;
01429     x = XLOG2DEV(pts[i].x + xoff);
01430     xpts[i].x = x;
01431     y = YLOG2DEV(pts[i].y + yoff);
01432     xpts[i].y = y;
01433   }
01434   xpts[n].x = xpts[0].x; // close figure
01435   xpts[n].y = xpts[0].y;
01436   if (current_brush && current_brush->GetStyle() != wxTRANSPARENT) {
01437     XSetFillRule(DPY, BRUSH_GC, fill_rule[fill]);
01438     XFillPolygon(DPY, DRAWABLE, BRUSH_GC, xpts, n, Complex, 0);
01439   }
01440   if (current_pen && current_pen->GetStyle() != wxTRANSPARENT)
01441     XDrawLines(DPY, DRAWABLE, PEN_GC, xpts, n+1, 0);
01442 }
01443 
01444 void wxWindowDC::DrawRectangle(double x, double y, double w, double h)
01445 {
01446     int x1, y1, w1, h1;
01447     double xw, yh;
01448 
01449     if (!DRAWABLE) // ensure that a drawable has been associated
01450        return;
01451 
01452     FreeGetPixelCache();
01453     
01454 #ifdef WX_USE_CAIRO
01455     if (anti_alias) {
01456       double xx, yy, ww, hh;
01457 
01458       InitCairoDev();
01459       if (SetCairoBrush()) {
01460        xx = SmoothingXFormXB(x);
01461        yy = SmoothingXFormYB(y);
01462        ww = SmoothingXFormW(w, x);
01463        hh = SmoothingXFormH(h, y);
01464 
01465        cairo_new_path(CAIRO_DEV);
01466        cairo_move_to(CAIRO_DEV, xx, yy);
01467        cairo_line_to(CAIRO_DEV, xx+ww, yy);
01468        cairo_line_to(CAIRO_DEV, xx+ww, yy+hh);
01469        cairo_line_to(CAIRO_DEV, xx, yy+hh);
01470        cairo_fill(CAIRO_DEV);    
01471       }
01472 
01473       if (SetCairoPen()) {
01474        xx = SmoothingXFormX(x);
01475        yy = SmoothingXFormY(y);
01476        ww = SmoothingXFormWL(w, x);
01477        hh = SmoothingXFormHL(h, y);
01478       
01479        cairo_new_path(CAIRO_DEV);
01480        cairo_move_to(CAIRO_DEV, xx, yy);
01481        cairo_line_to(CAIRO_DEV, xx+ww, yy);
01482        cairo_line_to(CAIRO_DEV, xx+ww, yy+hh);
01483        cairo_line_to(CAIRO_DEV, xx, yy+hh);
01484        cairo_close_path(CAIRO_DEV);
01485        cairo_stroke(CAIRO_DEV);
01486       }
01487 
01488       return;
01489     }
01490 #endif
01491 
01492     xw = x + w, yh = y + h;
01493    
01494     x1 = XLOG2DEV(x);
01495     y1 = YLOG2DEV(y);
01496     w1 = XLOG2DEV(xw) - x1;
01497     h1 = YLOG2DEV(yh) - y1;
01498 
01499     if (current_brush && current_brush->GetStyle() != wxTRANSPARENT)
01500       XFillRectangle(DPY, DRAWABLE, BRUSH_GC, x1, y1, w1, h1);
01501     if (current_pen && current_pen->GetStyle() != wxTRANSPARENT)
01502       XDrawRectangle(DPY, DRAWABLE, PEN_GC, x1, y1, w1 - WX_GC_CF, h1 - WX_GC_CF);
01503 }
01504 
01505 void wxWindowDC::DrawRoundedRectangle(double x, double y, double w, double h,
01506                                   double radius)
01507 {
01508   int xx, yy, ww, hh, rr, dd;
01509   double xw, yh;
01510 
01511     if (!DRAWABLE) // ensure that a drawable has been associated
01512        return;
01513 
01514     FreeGetPixelCache();
01515     
01516     if (radius < 0.0)
01517       radius = - radius * ((w < h) ? w : h);
01518 
01519 #ifdef WX_USE_CAIRO
01520     if (anti_alias) {
01521       double xx, yy, ww, hh, rr, rr2;
01522 
01523       InitCairoDev();
01524       if (SetCairoBrush()) {
01525        xx = SmoothingXFormXB(x);
01526        yy = SmoothingXFormYB(y);
01527        ww = SmoothingXFormW(w, x);
01528        hh = SmoothingXFormH(h, y);
01529 
01530        rr = SmoothingXFormW(radius, 0);
01531        rr2 = SmoothingXFormH(radius, 0);
01532        if (rr2 < rr)
01533          rr = rr2;
01534 
01535        cairo_move_to(CAIRO_DEV, xx, yy + rr);
01536        cairo_line_to(CAIRO_DEV, xx, yy + hh - rr);
01537        cairo_arc_negative(CAIRO_DEV, xx + rr, yy + hh - rr, rr, wxPI, 0.5 * wxPI);
01538        cairo_line_to(CAIRO_DEV, xx + ww - rr, yy + hh);
01539        cairo_arc_negative(CAIRO_DEV, xx + ww - rr, yy + hh - rr, rr, 0.5 * wxPI, 0);
01540        cairo_line_to(CAIRO_DEV, xx + ww, yy + rr);
01541        cairo_arc_negative(CAIRO_DEV, xx + ww - rr, yy + rr, rr, 2 * wxPI, 1.5 * wxPI);
01542        cairo_line_to(CAIRO_DEV, xx + rr, yy);
01543        cairo_arc_negative(CAIRO_DEV, xx + rr, yy + rr, rr, 1.5 * wxPI, wxPI);
01544        cairo_line_to(CAIRO_DEV, xx, yy + rr);
01545        cairo_fill(CAIRO_DEV);    
01546       }
01547 
01548       if (SetCairoPen()) {
01549        xx = SmoothingXFormX(x);
01550        yy = SmoothingXFormY(y);
01551        ww = SmoothingXFormWL(w, x);
01552        hh = SmoothingXFormHL(h, y);
01553 
01554        rr = SmoothingXFormWL(radius, 0);
01555        rr2 = SmoothingXFormHL(radius, 0);
01556        if (rr2 < rr)
01557          rr = rr2;
01558 
01559        cairo_move_to(CAIRO_DEV, xx, yy + rr);
01560        cairo_line_to(CAIRO_DEV, xx, yy + hh - rr);
01561        cairo_arc_negative(CAIRO_DEV, xx + rr, yy + hh - rr, rr, wxPI, 0.5 * wxPI);
01562        cairo_line_to(CAIRO_DEV, xx + ww - rr, yy + hh);
01563        cairo_arc_negative(CAIRO_DEV, xx + ww - rr, yy + hh - rr, rr, 0.5 * wxPI, 0);
01564        cairo_line_to(CAIRO_DEV, xx + ww, yy + rr);
01565        cairo_arc_negative(CAIRO_DEV, xx + ww - rr, yy + rr, rr, 2 * wxPI, 1.5 * wxPI);
01566        cairo_line_to(CAIRO_DEV, xx + rr, yy);
01567        cairo_arc_negative(CAIRO_DEV, xx + rr, yy + rr, rr, 1.5 * wxPI, wxPI);
01568        cairo_line_to(CAIRO_DEV, xx, yy + rr);
01569        cairo_close_path(CAIRO_DEV);
01570        cairo_stroke(CAIRO_DEV);
01571       }
01572 
01573       return;
01574     }
01575 #endif
01576 
01577     xw = x + w, yh = y + h;
01578     
01579     xx = XLOG2DEV(x);       yy = YLOG2DEV(y);
01580     ww = XLOG2DEV(xw) - xx; hh = YLOG2DEV(yh) - yy;
01581     if (scale_x < scale_y)
01582       rr = XLOG2DEVREL(radius);
01583     else
01584       rr = YLOG2DEVREL(radius);
01585     dd = 2 * rr;
01586 
01587     if (current_brush && current_brush->GetStyle() != wxTRANSPARENT) {
01588        XFillRectangle(DPY, DRAWABLE, BRUSH_GC, xx+rr, yy, ww-dd, hh);
01589        XFillRectangle(DPY, DRAWABLE, BRUSH_GC, xx, yy+rr, ww, hh-dd);
01590        XFillArc(DPY, DRAWABLE, BRUSH_GC, xx, yy, dd - WX_GC_CF, dd - WX_GC_CF, 90*64, 90*64);
01591        XFillArc(DPY, DRAWABLE, BRUSH_GC, xx+ww-dd, yy, dd - WX_GC_CF, dd - WX_GC_CF, 0, 90*64);
01592        XFillArc(DPY, DRAWABLE, BRUSH_GC, xx+ww-dd, yy+hh-dd, dd - WX_GC_CF, dd - WX_GC_CF,
01593                270*64, 90*64);
01594        XFillArc(DPY, DRAWABLE, BRUSH_GC, xx, yy+hh-dd, dd - WX_GC_CF, dd - WX_GC_CF, 180*64, 90*64);
01595     }
01596     if (current_pen && current_pen->GetStyle() != wxTRANSPARENT){
01597         ww -= WX_GC_CF;
01598         hh -= WX_GC_CF;
01599        XDrawLine(DPY, DRAWABLE, PEN_GC, xx+rr, yy, xx+ww-rr, yy);
01600        XDrawLine(DPY, DRAWABLE, PEN_GC, xx+rr, yy+hh, xx+ww-rr, yy+hh);
01601        XDrawLine(DPY, DRAWABLE, PEN_GC, xx, yy+rr, xx, yy+hh-rr);
01602        XDrawLine(DPY, DRAWABLE, PEN_GC, xx+ww, yy+rr, xx+ww, yy+hh-rr);
01603        XDrawArc(DPY, DRAWABLE, PEN_GC, xx, yy, dd, dd, 90*64, 90*64);
01604        XDrawArc(DPY, DRAWABLE, PEN_GC, xx+ww-dd, yy, dd, dd, 0, 90*64);
01605        XDrawArc(DPY, DRAWABLE, PEN_GC, xx+ww-dd, yy+hh-dd, dd, dd,
01606                270*64, 90*64);
01607        XDrawArc(DPY, DRAWABLE, PEN_GC, xx, yy+hh-dd, dd, dd, 180*64, 90*64);
01608     }
01609 }
01610 
01611 void wxWindowDC::DrawPath(wxPath *p, double xoff, double yoff, int fill)
01612 {
01613   double **ptss;
01614   int *lens, cnt, i, total_cnt, j, k, ix, iy;
01615   XPoint *xpts;
01616 
01617   if (!DRAWABLE) // ensure that a drawable has been associated
01618     return;
01619 
01620   FreeGetPixelCache();
01621 
01622 #ifdef WX_USE_CAIRO
01623   if (anti_alias) {
01624 
01625     InitCairoDev();
01626     if (SetCairoBrush()) {
01627       if (fill == wxODDEVEN_RULE)
01628        cairo_set_fill_rule(CAIRO_DEV, CAIRO_FILL_RULE_EVEN_ODD);
01629 
01630       if (AlignSmoothing()) {
01631        double pw;
01632        pw = GetPenSmoothingOffset();
01633        p->Install((long)CAIRO_DEV, xoff, yoff, 
01634                  device_origin_x, device_origin_y, user_scale_x, user_scale_y, 
01635                  TRUE, pw, pw);
01636       } else
01637        p->Install((long)CAIRO_DEV, xoff, yoff, 0, 0, 1, 1, FALSE, 0, 0);
01638       cairo_fill(CAIRO_DEV);
01639 
01640       if (fill == wxODDEVEN_RULE)
01641        cairo_set_fill_rule(CAIRO_DEV, CAIRO_FILL_RULE_WINDING);
01642     }
01643 
01644     if (SetCairoPen()) {
01645       if (AlignSmoothing()) {
01646        double pw;
01647        pw = GetPenSmoothingOffset();
01648        p->Install((long)CAIRO_DEV, xoff, yoff, 
01649                  device_origin_x, device_origin_y, user_scale_x, user_scale_y, 
01650                  TRUE, pw, pw);
01651       } else
01652        p->Install((long)CAIRO_DEV, xoff, yoff, 0, 0, 1, 1, FALSE, 0, 0);
01653       cairo_stroke(CAIRO_DEV);
01654     }
01655 
01656     return;
01657   }
01658 #endif
01659 
01660   cnt = p->ToPolygons(&lens, &ptss, user_scale_x, user_scale_y);
01661 
01662   if (!cnt)
01663     return;
01664 
01665   total_cnt = 0;
01666   for (i = 0; i < cnt; i++) {
01667     total_cnt += (lens[i] / 2) + 1;
01668   }
01669   
01670   xpts = new WXGC_ATOMIC XPoint[total_cnt];
01671 
01672   for (i = 0, k = 0; i < cnt; i++) {
01673     for (j = 0; j < lens[i]; j += 2) {
01674       ix = XLOG2DEV(ptss[i][j]+xoff);
01675       iy = YLOG2DEV(ptss[i][j+1]+yoff);
01676       xpts[k].x = ix;
01677       xpts[k].y = iy;
01678       k++;
01679     }
01680     ix = XLOG2DEV(ptss[i][0]+xoff);
01681     iy = YLOG2DEV(ptss[i][1]+yoff);
01682     xpts[k].x = ix;
01683     xpts[k].y = iy;
01684     k++;
01685   }
01686 
01687   if (current_brush && current_brush->GetStyle() != wxTRANSPARENT) {
01688     XSetFillRule(DPY, BRUSH_GC, fill_rule[fill]);
01689     if (cnt == 1) {
01690       XFillPolygon(DPY, DRAWABLE, BRUSH_GC, xpts, total_cnt, Complex, 0);
01691     } else {
01692       Region rgn = 0, rgn1;
01693 
01694       for (i = 0, k = 0; i < cnt; i++) {
01695        j = (lens[i] / 2) + 1;
01696        rgn1 = XPolygonRegion(xpts XFORM_OK_PLUS k, j, fill_rule[fill]);
01697        if (rgn) {
01698          /* Xoring implements the even-odd rule */
01699          XXorRegion(rgn, rgn1, rgn);
01700          XDestroyRegion(rgn1);
01701        } else {
01702          rgn = rgn1;
01703        }
01704        k += j;
01705       }
01706 
01707       if (CURRENT_REG)
01708        XIntersectRegion(rgn, CURRENT_REG, rgn);
01709 
01710       XSetRegion(DPY, BRUSH_GC, rgn);
01711       XFillRectangle(DPY, DRAWABLE, BRUSH_GC, 0, 0, 32000, 32000);
01712 
01713       if (CURRENT_REG)
01714        XSetRegion(DPY, BRUSH_GC, CURRENT_REG);
01715       else
01716        XSetClipMask(DPY, BRUSH_GC, None);
01717 
01718       XDestroyRegion(rgn);
01719     }      
01720   }
01721   if (current_pen && current_pen->GetStyle() != wxTRANSPARENT) {
01722     for (i = 0, k = 0; i < cnt; i++) {
01723       j = (lens[i] / 2) + 1;
01724       if ((i + 1 == cnt) && p->IsOpen())
01725        --j;
01726       XDrawLines(DPY, DRAWABLE, PEN_GC, xpts XFORM_OK_PLUS k, j, 0);
01727       k += j;
01728     }
01729   }
01730 }
01731 
01732 //-----------------------------------------------------------------------------
01733 // drawing tools
01734 //-----------------------------------------------------------------------------
01735 
01736 void wxWindowDC::SetBackground(wxColour *c)
01737 {
01738   int style;
01739   unsigned long pixel;
01740 
01741   if (!DRAWABLE)
01742     return;
01743   
01744   if (c != current_background_color)
01745     current_background_color->CopyFrom(c);
01746   
01747   pixel = current_background_color->GetPixel(current_cmap, IS_COLOR, 0);
01748   
01749   if (DRAW_WINDOW)
01750     XSetWindowBackground(DPY, DRAW_WINDOW, pixel);
01751   XSetForeground(DPY, BG_GC, pixel);
01752   XSetBackground(DPY, PEN_GC, pixel);
01753   XSetBackground(DPY, BRUSH_GC, pixel);
01754   
01755   // use the correct pixel values for XOR
01756   
01757   style = current_pen->GetStyle();
01758   if ((style >= wxXOR_DOT) && (style <= wxXOR_DOT_DASH))
01759     style = wxXOR;
01760   if (current_pen && ((style == wxXOR) || (style == wxCOLOR)))
01761     ResetPen(current_pen);
01762   
01763   if (current_brush && (current_brush->GetStyle() == wxXOR))
01764     ResetBrush(current_brush);
01765 }
01766 
01767 void wxWindowDC::SetBrush(wxBrush *brush)
01768 {
01769   if (brush == current_brush)
01770     return;
01771 
01772   ResetBrush(brush);
01773 }
01774     
01775 void wxWindowDC::ResetBrush(wxBrush *brush)
01776 {
01777   XGCValues     values;
01778   unsigned long mask;
01779   wxBitmap *bm;
01780   unsigned long pixel;
01781   int bstyle;
01782 
01783   if (!DRAWABLE)
01784     return;
01785 
01786   if (current_brush) current_brush->Lock(-1);
01787 
01788   if (!(current_brush = brush)) // nothing to do without brush
01789     return;
01790 
01791   if (current_brush) current_brush->Lock(1);
01792 
01793   // for XChangeGC
01794   mask = GCFillStyle | GCForeground | GCFunction;
01795 
01796   values.fill_style = FillSolid;
01797   bstyle = brush->GetStyle();
01798   if (bstyle == wxCOLOR) {
01799     pixel = wxCTL_HIGHLIGHT_PIXEL;
01800   } else {
01801     wxColour *bcol;
01802     bcol = brush->GetColour();
01803     pixel = bcol->GetPixel(current_cmap, IS_COLOR, 1);
01804   }
01805   if (bstyle == wxXOR) {
01806     XGCValues values_req;
01807     XGetGCValues(DPY, BRUSH_GC, GCBackground, &values_req);
01808     values.foreground = pixel ^ values_req.background;
01809     values.function = GXxor;
01810   } else if (bstyle == wxCOLOR) {
01811     values.foreground = pixel;
01812     values.function = GXorReverse;
01813   } else {
01814     values.foreground = pixel;
01815     values.function = GXcopy;
01816   }
01817 
01818   bm = brush->GetStipple();
01819   if (bm && !bm->Ok())
01820     bm = NULL;
01821 
01822   if (bm) {
01823     Pixmap stipple = (Pixmap)0; // for FillStippled
01824     Pixmap tile    = (Pixmap)0; // for FillTiled
01825     if (bm->GetDepth() == 1) {
01826       if (bm->selectedTo) bm->selectedTo->EndSetPixel();
01827       stipple = GETPIXMAP(bm);
01828       values.fill_style = ((brush->GetStyle()==wxSTIPPLE) ? FillOpaqueStippled : FillStippled);
01829     } else if (bm->GetDepth() == (signed)DEPTH) {
01830       if (bm->selectedTo) bm->selectedTo->EndSetPixel();
01831       tile = GETPIXMAP(bm);
01832       values.fill_style = FillTiled;
01833     } // else wrong depth
01834     if (stipple) {
01835       values.stipple = stipple;
01836       mask |= GCStipple;
01837     }
01838     if (tile) {
01839       values.tile = tile;
01840       mask |= GCTile;
01841       values.foreground = wx_black_pixel;
01842       values.function = GXcopy;
01843     }
01844   } else {
01845     int style;
01846     style = brush->GetStyle();
01847     if (wxIS_HATCH(style)) {
01848       Pixmap stipple = (Pixmap)0; // for FillStippled
01849       stipple = hatch_bitmaps[style-wxFIRST_HATCH];
01850       values.fill_style = FillStippled;
01851       if (stipple) {
01852        values.stipple = stipple;
01853        mask |= GCStipple;
01854       }
01855     }
01856   }
01857   XChangeGC(DPY, BRUSH_GC, mask, &values);
01858 }
01859 
01860 void wxWindowDC::SetColourMap(wxColourMap *new_cmap)
01861 {
01862   current_cmap = new_cmap ? new_cmap : wxAPP_COLOURMAP;
01863   
01864   if (DRAW_WINDOW) {
01865     Window w;
01866     Colormap cm;
01867     w = DRAW_WINDOW;
01868     cm = CMAP;
01869     XSetWindowColormap(DPY, w, cm);
01870   }
01871 }
01872 
01873 static wxDash dashdefs[4][4] = {
01874   { 2, 5, 0, 0 }, // wxDOT
01875   { 4, 8, 0, 0 }, // wxLONG_DASH
01876   { 4, 4, 0, 0 }, // wxSHORT_DASH
01877   { 6, 6, 2, 6 }  // wxDOT_DASH
01878 };
01879 static int    num_dashes[] = { 2, 2, 2, 4 };     
01880 
01881 void wxWindowDC::SetPen(wxPen *pen)
01882 {
01883   if (pen == current_pen)
01884     return;
01885 
01886   ResetPen(pen);
01887 }
01888 
01889 void wxWindowDC::ResetPen(wxPen *pen)
01890 {
01891   XGCValues     values;
01892   unsigned long mask;
01893   wxBitmap *bm;
01894   int scale;
01895   int style, doXor, js, cs, pw;
01896   unsigned long pixel;
01897 
01898     if (!DRAWABLE) /* MATTHEW: [5] */
01899       return;
01900 
01901     if (current_pen) current_pen->Lock(-1);
01902     
01903     if (!(current_pen = pen)) // nothing to do without pen
01904       return;
01905 
01906     if (current_pen) current_pen->Lock(1);
01907 
01908     // for XChangeGC
01909     mask = (GCCapStyle  | GCFillStyle | GCForeground
01910            | GCJoinStyle | GCLineStyle | GCLineWidth
01911            | GCFunction);
01912 
01913     cs = pen->GetCap();
01914     values.cap_style  = cap_style[cs];
01915     values.fill_style = FillSolid;
01916     js = pen->GetJoin();
01917     values.join_style = join_style[js];
01918     values.line_style = LineSolid;
01919     pw = pen->GetWidth();
01920     scale = XLOG2DEVREL(pw);
01921     values.line_width = scale;
01922     style = pen->GetStyle();
01923     if (style == wxCOLOR) {
01924       pixel = wxCTL_HIGHLIGHT_PIXEL;
01925     } else {
01926       wxColour *pcol;
01927       pcol = pen->GetColour();
01928       pixel = pcol->GetPixel(current_cmap, IS_COLOR, 1);
01929     }
01930     doXor = 0;
01931 
01932     switch (style) {
01933     case wxXOR:
01934       doXor = 1;
01935       break;
01936     case wxXOR_DOT:
01937     case wxXOR_SHORT_DASH:
01938     case wxXOR_LONG_DASH:
01939     case wxXOR_DOT_DASH:
01940       doXor = 1;
01941       style -= (wxXOR_DOT - wxDOT);
01942       break;
01943     }
01944 
01945     if (doXor) {
01946       XGCValues values_req;
01947       XGetGCValues(DPY, PEN_GC, GCBackground, &values_req);
01948       values.foreground = pixel ^ values_req.background;
01949       values.function = GXxor;
01950     } else if (style == wxCOLOR) {
01951       values.foreground = pixel;
01952       values.function = GXorReverse;
01953     } else {
01954       values.foreground = pixel;
01955       values.function = GXcopy;
01956     }
01957 
01958     bm = pen->GetStipple();
01959     if (bm && !bm->Ok())
01960       bm = NULL;
01961 
01962     if (bm) {
01963       Pixmap stipple = (Pixmap)0; // for FillStippled
01964       Pixmap tile    = (Pixmap)0; // for FillTiled
01965       if (bm->GetDepth() == 1) {
01966        if (bm->selectedTo) bm->selectedTo->EndSetPixel();
01967        stipple = GETPIXMAP(bm);
01968        values.fill_style = FillStippled;
01969       } else if (bm->GetDepth() == (signed)DEPTH) {
01970        if (bm->selectedTo) bm->selectedTo->EndSetPixel();
01971        tile = GETPIXMAP(bm);
01972        values.fill_style = FillTiled;
01973       } // else wrong depth
01974       if (stipple) {
01975        values.stipple = stipple;
01976        mask |= GCStipple;
01977       }
01978       if (tile) {
01979        values.tile = tile;
01980        mask |= GCTile;
01981        values.foreground = wx_black_pixel;
01982        values.function = GXcopy;
01983       }
01984     } else {
01985       if (wxIS_DASH(style) || style==wxUSER_DASH) {
01986        int           num_dash;
01987        wxDash        *dashdef, *scaleddef;
01988        if (style==wxUSER_DASH) {
01989          num_dash = pen->GetDashes(&dashdef);
01990        } else {
01991          num_dash = num_dashes[style-wxFIRST_DASH];
01992          dashdef  = dashdefs[style-wxFIRST_DASH];
01993        }
01994        if ((scaleddef = new WXGC_ATOMIC wxDash[num_dash])) {
01995          int dscale = scale, i;
01996          if (!dscale) dscale = 1;
01997          for (i = 0; i < num_dash; i++) {
01998            scaleddef[i] = dscale * dashdef[i];
01999          }
02000          XSetDashes(DPY, PEN_GC, 0, (char*)scaleddef, num_dash);
02001        } else { // not enough memory to scale
02002          XSetDashes(DPY, PEN_GC, 0, (char*)dashdef, num_dash);
02003        }
02004        values.line_style = LineOnOffDash;
02005       }
02006     }
02007     XChangeGC(DPY, PEN_GC, mask, &values);
02008 }
02009 
02010 void wxWindowDC::TryColour(wxColour *src, wxColour *dest)
02011 {
02012   XColor xcol;
02013 
02014   if (!DRAWABLE)
02015     return;
02016 
02017   xcol.pixel = src->GetPixel(current_cmap, IS_COLOR, 1);
02018 
02019   if (IS_COLOR) {
02020     Colormap cm;
02021     cm = GETCOLORMAP(current_cmap);
02022     wxQueryColor(wxAPP_DISPLAY, cm, &xcol);
02023     
02024     dest->Set(xcol.red >> SHIFT, xcol.green >> SHIFT, xcol.blue >> SHIFT);
02025   } else if (xcol.pixel == 1) { /* not wx_black_pixel */
02026     dest->Set(0, 0, 0);
02027   } else {
02028     dest->Set(255, 255, 255);
02029   }
02030 }
02031 
02032 
02033 void wxWindowDC::FillPrivateColor(wxColour *c)
02034 {
02035   XColor xcol;
02036   int free = 0;
02037   XGCValues values;
02038   int mask = 0;
02039   GC agc;
02040   double w, h;
02041   Colormap cm;
02042 
02043   if (!DRAWABLE)
02044     return;
02045 
02046   xcol.red = c->Red() << SHIFT;
02047   xcol.green = c->Green() << SHIFT;
02048   xcol.blue = c->Blue() << SHIFT;
02049 
02050   cm = GETCOLORMAP(current_cmap);
02051 
02052   if (XAllocColor(wxAPP_DISPLAY, cm, &xcol) == 1) {
02053     wxQueryColor(wxAPP_DISPLAY, cm, &xcol);
02054     c->Set(xcol.red >> SHIFT, xcol.green >> SHIFT, xcol.blue >> SHIFT);
02055     free = 1;
02056   } else {
02057     xcol.pixel = wx_black_pixel;
02058     c->Set(0, 0, 0);
02059   }
02060 
02061   values.foreground = xcol.pixel;
02062   values.fill_style = FillSolid;
02063   mask |= GCForeground | GCFillStyle;
02064 
02065   agc = XCreateGC(DPY, DRAWABLE, mask, &values);
02066   
02067   GetSize(&w, &h);
02068 
02069   XFillRectangle(DPY, DRAWABLE, agc, 0, 0, (int)w, (int)h);
02070 
02071   XFreeGC(DPY, agc);
02072 
02073   if (free)
02074     XFreeColors(wxAPP_DISPLAY, cm, &xcol.pixel, 1, 0);
02075 }
02076 
02077 //-----------------------------------------------------------------------------
02078 // text and font methods
02079 //-----------------------------------------------------------------------------
02080 
02081 #ifdef WX_USE_XFT
02082 
02083 static int symbol_map[] = { 0, 0, 0, 0, 0, 0, 0, 0,
02084                          0, 0, 0, 0, 0, 0, 0, 0,
02085                          0, 0, 0, 0, 0, 0, 0, 0,
02086                          0, 0, 0, 0, 0, 0, 0, 0,
02087                          0, 0, 8704, 0, 8707, 0, 0, 8717,
02088                          0, 0, 8727, 0, 0, 8722, 0, 0,
02089                          0, 0, 0, 0, 0, 0, 0, 0,
02090                          0, 0, 0, 0, 0, 0, 0, 0,
02091                          8773, 913, 914, 935, 916, 917, 934, 915,
02092                          919, 921, 977, 922, 923, 924, 925, 927,
02093                          928, 920, 929, 931, 932, 933, 962, 937,
02094                          926, 936, 918, 0, 8756, 0, 8869, 0,
02095                          0, 945, 946, 967, 948, 949, 966, 947,
02096                          951, 953, 981, 954, 955, 956, 957, 959,
02097                          960, 952, 961, 963, 964, 965, 982, 969,
02098                          958, 968, 950, 0, 0, 0, 8764, 0,
02099                          0, 0, 0, 0, 0, 0, 0, 0,
02100                          0, 0, 0, 0, 0, 0, 0, 0,
02101                          0, 0, 0, 0, 0, 0, 0, 0,
02102                          0, 0, 0, 0, 0, 0, 0, 0,
02103                          0, 978, 8242, 8804, 8260, 8734, 402, 9827,
02104                          9830, 9829, 9824, 8596, 8592, 8593, 8594, 8595,
02105                          0, 177, 8243, 8805, 215, 8733, 8706, 8729,
02106                          247, 8800, 8801, 8776, 8230, 9168, /* 9135 */8212, 8629,
02107                          8501, 8465, 8476, 8472, 8855, 8853, 8709, 8745,
02108                          8746, 8835, 8839, 8836, 8834, 8838, 8712, 8713,
02109                          8736, 8711, 174, 169, 8482, 8719, 8730, 8901,
02110                          172, 8743, 8744, 8660, 8656, 8657, 8658, 8659,
02111                          9674, 9001, 174, 169, 8482, 8721, 9115, 9116,
02112                          9117, 9121, 9122, 9123, 9127, 9128, 9129, 9130,
02113                          8364, 9002, 8747, 8992, 9134, 8993, 9118, 9119,
02114                          9120, 9124, 9125, 9126, 9131, 9132, 9133, 0 };
02115 
02116 static unsigned int *XlateSym(unsigned int *text, int dt, int textlen, unsigned int *buf, int buflen)
02117 {
02118   int i, v;
02119   unsigned int *us;
02120 
02121   if (text != buf) {
02122     if (buflen <= textlen)
02123       us = new WXGC_ATOMIC unsigned[textlen];
02124     else
02125       us = buf;
02126     memcpy(us, text + (dt * sizeof(int)), textlen * sizeof(unsigned int));
02127   } else {
02128     us = text;
02129     if (dt)
02130       memmove(us, us + (dt * sizeof(int)), textlen * sizeof(unsigned int));
02131   }
02132 
02133   for (i = 0; i < textlen; i++) {
02134     v = us[i];
02135     if ((v < 256) && symbol_map[v])
02136       v = symbol_map[v];
02137     us[i] = v;
02138   }
02139 
02140   return us;
02141 }
02142 
02143 #endif
02144 
02145 extern "C" {
02146   int scheme_utf8_decode(const unsigned char *s, int start, int len, 
02147                       unsigned int *us, int dstart, int dlen,
02148                       long *ipos, char utf16, int permissive);
02149   int scheme_utf8_decode_all(const unsigned char *s, int len, unsigned int *us, 
02150                           int permissive);
02151 };
02152 
02153 static unsigned int *convert_to_drawable_format(const char *s, int ds, long *_ulen, unsigned int *buf, int bufsize, 
02154                                           int isUnicode, int non_xft)
02155 {
02156   unsigned int *us;
02157   long ulen = *_ulen;
02158 
02159   if (isUnicode) {
02160     us = (unsigned int *)s;
02161     if (ulen < 0) {
02162       for (ulen = ds; us[ulen]; ulen++) {
02163       }
02164       ulen -= ds;
02165     }
02166     if (ds) {
02167       if (ulen <= bufsize)
02168        us = buf;
02169       else
02170        us = new WXGC_ATOMIC unsigned[ulen];
02171       memcpy(us, s + (ds * sizeof(int)), ulen * sizeof(unsigned int));
02172     }
02173   } else {
02174     int length;
02175 
02176     if (ulen < 0)
02177       length = strlen(s XFORM_OK_PLUS ds);
02178     else
02179       length = ulen;
02180     
02181     ulen = scheme_utf8_decode((const unsigned char *)s, ds, ds + length, NULL, 0, -1, NULL, 0, '?');
02182     if (ulen <= bufsize)
02183       us = buf;
02184     else
02185       us = new WXGC_ATOMIC unsigned[ulen];
02186     ulen = scheme_utf8_decode((const unsigned char *)s, ds, ds + length, us, 0, -1, NULL, 0, '?');
02187   }
02188 
02189   if (non_xft) {
02190     /* Squash 32-bit encoding into 16-bit encoding.
02191        Since we overwrite the array, it's important
02192        to start at position 0 and go up: */
02193     int i, v;
02194     XChar2b *dest;
02195     
02196     if (isUnicode) {
02197       if (2 * ulen <= bufsize)
02198        dest = (XChar2b *)buf;
02199       else
02200        dest = new WXGC_ATOMIC XChar2b[ulen];
02201     } else
02202       dest = (XChar2b *)us;
02203 
02204     for (i = 0; i < ulen; i++) {
02205       if (us[i] > 0xFFFF)
02206        v = '?';
02207       else
02208        v = us[i];
02209       dest[i].byte2 = v & 0xff;
02210       dest[i].byte1 = v >> 8;
02211     }
02212 
02213     us = (unsigned int *)dest;
02214   }
02215 
02216   *_ulen = ulen;
02217   
02218   return us;
02219 }
02220 
02221 #define WX_CVT_BUF_SIZE 1024
02222 #ifdef WX_USE_XFT
02223 # define WX_XFT_ONLY(x) x
02224 #else
02225 # define WX_XFT_ONLY(x) 1
02226 #endif
02227 static unsigned int cvt_buf[WX_CVT_BUF_SIZE];
02228 
02229 /* Xft measurements use a `short'. Avoid string lengths that are
02230    likely to overflow it. */
02231 #define MAX_TEXT_LENGTH_FOR_MEASURE 100
02232 
02233 void wxWindowDC::DrawText(char *orig_text, double x, double y, 
02234                        Bool combine, Bool isUnicode, int dt,
02235                        double angle)
02236 {
02237   XFontStruct *fontinfo;
02238 #ifdef WX_USE_XFT
02239   wxFontStruct *xfontinfo;
02240 #endif
02241   double       cx, cy;
02242   int         ascent;
02243   int         dev_x;
02244   int         dev_y;
02245   long        textlen;
02246   double       e_scale_x, e_scale_y;
02247   double       ca, sa;
02248   unsigned int *text;
02249   
02250 
02251   if (!DRAWABLE) // ensure that a drawable has been associated
02252     return;
02253 
02254   if (!current_font) // a font must be associated for drawing
02255     return;
02256 
02257   /* e_scale_x and e_scale_y are the effective font scales
02258      considering that the font is rotated before scaled,
02259      and the horizontal and vertical scales can be different.
02260      The angle of the text is also affected if the scales
02261      are different; sa and ca are the effective sin and cos
02262      of the angle of the stretched/squashed baseline */
02263   if (angle == 0.0) {
02264     e_scale_x = scale_x;
02265     e_scale_y = scale_y;
02266     sa = 0.0;
02267     ca = 1.0;
02268   } else {
02269     ca = cos(angle);
02270     sa = sin(angle);
02271     if (scale_x == scale_y) {
02272       e_scale_x = scale_x;
02273       e_scale_y = scale_y;
02274     } else {
02275       double a2;
02276       e_scale_x = sqrt(((scale_x * ca) * (scale_x * ca)) + ((scale_y * sa) * (scale_y * sa)));
02277       e_scale_y = sqrt(((scale_y * ca) * (scale_y * ca)) + ((scale_x * sa) * (scale_x * sa)));
02278       a2 = atan2(sa * scale_y, ca * scale_x);
02279       ca = cos(a2);
02280       sa = sin(a2);
02281     }
02282   }
02283   
02284 #ifdef WX_USE_XFT
02285   InitPicture();
02286   xfontinfo = (wxFontStruct*)current_font->GetInternalAAFont(scale_x, scale_y, angle);
02287   if (xfontinfo)
02288     fontinfo = NULL;
02289   else
02290 #endif
02291     fontinfo = (XFontStruct *)current_font->GetInternalFont(e_scale_x, e_scale_y, 0.0);
02292 
02293   dev_x = XLOG2DEV(x);
02294   dev_y = YLOG2DEV(y);
02295 
02296   {
02297     double tw, th, td, ts;
02298     GetTextExtent(orig_text, &tw, &th, &td, &ts, current_font, combine, isUnicode, dt, -1);
02299     cx = (tw * e_scale_x);
02300     cy = (th * e_scale_y);
02301     ascent = (int)((th - td) * e_scale_y);
02302   }
02303 
02304   textlen = -1;
02305   text = convert_to_drawable_format(orig_text, dt, &textlen, cvt_buf, WX_CVT_BUF_SIZE, 
02306                                 isUnicode, WX_XFT_ONLY(!xfontinfo));
02307   dt = 0;
02308 
02309 # ifdef WX_USE_XFT
02310   if (xfontinfo) {
02311     if ((current_font->GetFamily() == wxSYMBOL)) {
02312       text = XlateSym(text, dt, textlen, cvt_buf, WX_CVT_BUF_SIZE);
02313       dt = 0;
02314     }
02315   }
02316 #endif
02317 
02318 #ifdef WX_USE_XFT
02319   if (xfontinfo) {
02320     int xasc;
02321     int v;
02322     XftColor col;
02323     /* Note: Xft wants colors with pre-multiplied alpha,
02324        according to my experiments. */
02325     col.pixel = current_text_fg->GetPixel();
02326     v = current_text_fg->Red();
02327     v = (int)(v * current_alpha);
02328     col.color.red = (v << 8) | v;
02329     v = current_text_fg->Green();
02330     v = (int)(v * current_alpha);
02331     col.color.green = (v << 8) | v;
02332     v = current_text_fg->Blue();
02333     v = (int)(v * current_alpha);
02334     col.color.blue = (v << 8) | v;
02335     col.color.alpha = (int)(current_alpha * 0xFFFF);
02336 
02337     if ((angle == 0.0) && (current_text_bgmode == wxSOLID)) {
02338       /* For B & W target, XftDrawRect doesn't seem to work right. */
02339       int rw;
02340       rw = (int)floor((x * scale_x) + device_origin_x + cx) - dev_x;
02341       if (Colour) {
02342        XftColor bg;
02343        bg.pixel = current_text_bg->GetPixel();
02344        v = current_text_bg->Red();
02345        v = (int)(v * current_alpha);
02346        bg.color.red = (v << 8) | v;
02347        v = current_text_bg->Green();
02348        v = (int)(v * current_alpha);
02349        bg.color.green = (v << 8) | v;
02350        v = current_text_bg->Blue();
02351        v = (int)(v * current_alpha);
02352        bg.color.blue = (v << 8) | v;
02353        bg.color.alpha = (int)(current_alpha * 0xFFFF);
02354        XftDrawRect(XFTDRAW, &bg, dev_x, dev_y, rw, xfontinfo->ascent + xfontinfo->descent);
02355       } else {
02356        unsigned long pixel;
02357        pixel = current_text_fg->GetPixel(current_cmap, IS_COLOR, 0);
02358        XSetForeground(DPY, TEXT_GC, pixel);
02359        XFillRectangle(DPY, DRAWABLE, TEXT_GC, dev_x, dev_y, rw, xfontinfo->ascent + xfontinfo->descent);
02360        pixel = current_text_fg->GetPixel(current_cmap, IS_COLOR, 1);
02361        XSetForeground(DPY, TEXT_GC, pixel);
02362       }
02363     }
02364 
02365     if (angle != 0.0) {
02366       xasc = (int)((double)ascent * sa);
02367       ascent = (int)((double)ascent * ca);
02368     } else
02369       xasc = 0;
02370 
02371     {
02372       wxFontStruct *this_time, *this_time_no_rotate, *no_rotate;
02373       int partlen, try_sub;
02374 
02375       try_sub = 1;
02376 
02377       while(textlen) {
02378        int nowlen;
02379        nowlen = textlen;
02380        if (nowlen > MAX_TEXT_LENGTH_FOR_MEASURE) {
02381          nowlen = MAX_TEXT_LENGTH_FOR_MEASURE;
02382        }
02383 
02384        if (angle != 0.0)
02385          no_rotate = (wxFontStruct*)current_font->GetInternalAAFont(e_scale_x, e_scale_y, 0.0);
02386        else
02387          no_rotate = xfontinfo;
02388 
02389        if (try_sub) {
02390          int index = 1, cval;
02391          partlen = 1;
02392          this_time = xfontinfo;
02393          this_time_no_rotate = no_rotate;
02394          while (1) {
02395            cval = text[dt];
02396            if (!XftGlyphExists(DPY, this_time, cval)) {
02397              this_time = (wxFontStruct*)current_font->GetNextAASubstitution(index, cval, scale_x, scale_y, angle);
02398              if (!this_time) {
02399               this_time = xfontinfo;
02400               this_time_no_rotate = no_rotate;
02401               break;
02402              }
02403              if (angle != 0.0)
02404               this_time_no_rotate = (wxFontStruct*)current_font->GetNextAASubstitution(index, cval, e_scale_x, e_scale_y, 0.0);
02405              else
02406               this_time_no_rotate = this_time;
02407               index++;
02408            } else
02409              break;
02410          }
02411          
02412          /* Get a longer range that won't need a substitution */
02413          if (this_time == xfontinfo) {
02414            while (partlen < nowlen) {
02415              cval = text[dt + partlen];
02416              if (((this_time != xfontinfo)
02417                  && XftGlyphExists(DPY, xfontinfo, cval))
02418                 || !XftGlyphExists(DPY, this_time, cval))
02419               break;
02420              partlen++;
02421            }
02422          }
02423        } else {
02424          partlen = nowlen;
02425          this_time = xfontinfo;
02426          this_time_no_rotate = no_rotate;
02427        }
02428 
02429        XftDrawString32(XFTDRAW, &col, this_time, dev_x+xasc, dev_y+ascent, ((XftChar32 *)text) + dt, partlen);
02430 
02431        if (partlen < textlen) {
02432          XGlyphInfo overall;
02433          double w;
02434          XftTextExtents32(DPY, this_time_no_rotate, ((XftChar32 *)text) + dt, partlen, &overall);
02435          w = overall.xOff;
02436          if (angle != 0.0) {
02437            xasc += (int)((double)w * ca);
02438            ascent -= (int)((double)w * sa);
02439          } else
02440            xasc += (int)w;
02441        }
02442 
02443        textlen -= partlen;
02444        dt += partlen;
02445       }
02446     }
02447   } else
02448 #endif
02449     {
02450       if ((angle == 0.0) && (current_text_bgmode == wxSOLID)) {
02451        if (need_x_set_font) {
02452          XSetFont(DPY, TEXT_GC, fontinfo->fid);
02453          need_x_set_font = 0;
02454        }
02455        XDrawImageString16(DPY, DRAWABLE, TEXT_GC, dev_x, dev_y+ascent, (XChar2b *)text + dt, textlen);
02456       } else {
02457        if (angle != 0.0) {
02458          double offset;
02459          double quadrant, pie = 3.14159;
02460          int the_x, the_y, i;
02461          XFontStruct *zfontinfo;
02462          XChar2b *text2b;
02463          
02464          zfontinfo = fontinfo;
02465          fontinfo = (XFontStruct *)current_font->GetInternalFont(scale_x, scale_y, angle);
02466          XSetFont(DPY, TEXT_GC, fontinfo->fid);
02467 
02468          quadrant = fmod(angle, 2 * pie);
02469          if (quadrant < 0)
02470            quadrant += (2 * pie);
02471          
02472          dev_y += (int)((double)ascent * ca);
02473          dev_x += (int)((double)ascent * sa);
02474 
02475          offset = 0.0;
02476          text2b = (XChar2b *)text;
02477          for (i = 0; i < textlen; i++) {
02478            int char_metric_offset;
02479 
02480            char_metric_offset = ((text2b[dt].byte1 - zfontinfo->min_byte1)
02481                               * (zfontinfo->max_char_or_byte2 - zfontinfo->min_char_or_byte2 + 1)
02482                               - zfontinfo->min_char_or_byte2
02483                               + text2b[dt].byte2);
02484            
02485            the_x = (int)((double)dev_x + offset * ca);
02486            the_y = (int)((double)dev_y - offset * sa);
02487            
02488            XDrawString16(DPY, DRAWABLE, TEXT_GC, the_x, the_y, text2b + dt, 1);
02489            dt++;
02490                   
02491            offset += (double)(zfontinfo->per_char ?
02492                             zfontinfo->per_char[char_metric_offset].width :
02493                             zfontinfo->min_bounds.width);
02494          }
02495 
02496          XSetFont(DPY, TEXT_GC, zfontinfo->fid);
02497        } else {
02498          if (need_x_set_font) {
02499            XSetFont(DPY, TEXT_GC, fontinfo->fid);
02500            need_x_set_font = 0;
02501          }
02502          XDrawString16(DPY, DRAWABLE, TEXT_GC, dev_x, dev_y+ascent, ((XChar2b *)text) + dt, textlen);
02503        }
02504       }
02505     }
02506 }
02507 
02508 double wxWindowDC::GetCharHeight(void)
02509 {
02510   double w, h, descent, topspace;
02511 
02512   if (!current_font) // no font
02513     return YDEV2LOGREL(12);
02514 
02515   GetTextExtent("x", &w, &h, &descent, &topspace, current_font, 0, 0, 0);
02516 
02517   return h;
02518 }
02519 
02520 double wxWindowDC::GetCharWidth(void)
02521 {
02522   double w, h, descent, topspace;
02523 
02524   if (!current_font) // no font
02525     return YDEV2LOGREL(12);
02526 
02527   GetTextExtent("x", &w, &h, &descent, &topspace, current_font, 0, 0, 0);
02528 
02529   return w;
02530 }
02531 
02532 void wxGetTextExtent(Display *dpy, double scale_x, double scale_y,
02533                    const char *orig_s, double *_w, double *_h, double *_descent,
02534                    double *_topspace, wxFont *font_to_use,
02535                    Bool combine, Bool isUnicode, int dt, int len)
02536 {
02537   int         ascent, descent, space = 0;
02538   long        textlen;
02539   XFontStruct *fontinfo;
02540 #ifdef WX_USE_XFT
02541   wxFontStruct *xfontinfo;
02542 #endif
02543   double w, h;
02544   unsigned *s;
02545 
02546 #ifdef WX_USE_XFT
02547   xfontinfo = (wxFontStruct*)font_to_use->GetInternalAAFont(scale_x, scale_y);
02548   if (xfontinfo)
02549     fontinfo = NULL;
02550   else
02551 #endif
02552     fontinfo = (XFontStruct*)font_to_use->GetInternalFont(scale_x, scale_y);
02553 
02554   textlen = len;
02555   s = convert_to_drawable_format(orig_s, dt, &textlen, cvt_buf, WX_CVT_BUF_SIZE, 
02556                              isUnicode, WX_XFT_ONLY(!xfontinfo));
02557   dt = 0;
02558 
02559 # ifdef WX_USE_XFT
02560   if (xfontinfo) {
02561     XGlyphInfo overall;
02562     wxFontStruct *this_time;
02563     int partlen, try_sub;
02564     
02565     if ((font_to_use->GetFamily() == wxSYMBOL)) {
02566       s = XlateSym(s, dt, textlen, cvt_buf, WX_CVT_BUF_SIZE);
02567       dt = 0;
02568     }
02569     try_sub = 1;
02570 
02571     w = 0;
02572 
02573     while (textlen) {
02574       int nowlen;
02575       nowlen = textlen;
02576       if (nowlen > MAX_TEXT_LENGTH_FOR_MEASURE) {
02577        nowlen = MAX_TEXT_LENGTH_FOR_MEASURE;
02578       }
02579 
02580       if (try_sub) {
02581        int index = 1, cval;
02582        partlen = 1;
02583        this_time = xfontinfo;
02584        
02585        while (1) {
02586          cval = s[dt];
02587          if (!XftGlyphExists(dpy, this_time, cval)) {
02588            this_time = (wxFontStruct*)font_to_use->GetNextAASubstitution(index++, cval, scale_x, scale_y, 0.0);
02589            if (!this_time) {
02590              this_time = xfontinfo;
02591              break;
02592            }
02593          } else
02594            break;
02595        }
02596 
02597        /* Get a longer range that won't need a substitution */
02598        if (this_time == xfontinfo) {
02599          while (partlen < nowlen) {
02600            cval = s[dt + partlen];
02601            if (((this_time != xfontinfo)
02602                && XftGlyphExists(dpy, xfontinfo, cval))
02603               || !XftGlyphExists(dpy, this_time, cval))
02604              break;
02605            partlen++;
02606          }
02607        }
02608       } else {
02609        partlen = nowlen;
02610        this_time = xfontinfo;
02611       }
02612       
02613       XftTextExtents32(dpy, this_time, ((XftChar32 *)s) + dt, partlen, &overall);
02614       w += overall.xOff;
02615 
02616       textlen -= partlen;
02617       dt += partlen;
02618     }
02619 
02620     ascent = xfontinfo->ascent;
02621     descent = xfontinfo->descent;
02622     space = xfontinfo->height - xfontinfo->ascent - xfontinfo->descent;
02623     if (space < 0)
02624       space = -space; /* This means that we're computing the space wrong! */
02625   } else
02626 #endif
02627     {
02628       int direction;
02629       XCharStruct overall;
02630 
02631       XTextExtents16(fontinfo, (XChar2b *)s + dt, textlen,
02632                    &direction, &ascent, &descent, &overall);
02633       w = overall.width;
02634     }
02635 
02636   *_w = w;
02637   h = ascent + descent;
02638   *_h = h;
02639   if (_descent) {
02640     double d;
02641     d = descent;
02642     *_descent = d;
02643   }
02644   if (_topspace)
02645     *_topspace = space;
02646 }
02647 
02648 void wxWindowDC::GetTextExtent(const char *orig_s, double *_w, double *_h, double *_descent,
02649                             double *_topspace, wxFont *_font,
02650                             Bool combine, Bool isUnicode, int dt, int len)
02651 {
02652   wxFont *font_to_use;
02653   double v;
02654 
02655   if (!DRAWABLE) // ensure that a drawable has been associated
02656     return;
02657 
02658   font_to_use = _font ? _font : current_font;
02659   if (!font_to_use) {
02660     wxError("set a font before calling GetTextExtent", "wxWindowDC");
02661     if (_w)
02662       *_w = -1.0;
02663     if (_h)
02664       *_h = -1.0;
02665     return;
02666   }
02667 
02668   wxGetTextExtent(DPY, scale_x, scale_y,
02669                 orig_s, _w, _h, _descent, _topspace, 
02670                 font_to_use, combine, isUnicode, dt, len);
02671 
02672   if (_w) {
02673     v = XDEV2LOGREL((int)*_w);
02674     *_w = v;
02675   }
02676   if (_h) {
02677     v = YDEV2LOGREL((int)*_h);
02678     *_h = v;
02679   }
02680   if (_descent) {
02681     v = YDEV2LOGREL((int)*_descent);
02682     *_descent = v;
02683   }
02684   if (_topspace) {
02685     v = YDEV2LOGREL((int)*_topspace);
02686     *_topspace = v;
02687   }
02688 }
02689 
02690 Bool wxWindowDC::GlyphAvailable(int c, wxFont *font)
02691 {
02692   if (!font)
02693     font = current_font;
02694 
02695   return font->ScreenGlyphAvailable(c);
02696 }
02697 
02698 void wxWindowDC::SetFont(wxFont *font)
02699 {
02700   if (!DRAWABLE)
02701     return;
02702 
02703   if (!(current_font = font)) // nothing to do without a font
02704     return;
02705 
02706   need_x_set_font = 1;
02707 }
02708 
02709 void wxWindowDC::SetTextForeground(wxColour *col)
02710 {
02711     unsigned long pixel;
02712 
02713     if (!DRAWABLE)
02714        return;
02715 
02716     if (!col)
02717       return;
02718     if (col != current_text_fg)
02719       current_text_fg->CopyFrom(col);
02720     pixel = current_text_fg->GetPixel(current_cmap, IS_COLOR, 1);
02721     XSetForeground(DPY, TEXT_GC, pixel);
02722 }
02723 
02724 void wxWindowDC::SetTextBackground(wxColour *col)
02725 {
02726     unsigned long pixel;
02727 
02728     if (!DRAWABLE) /* MATTHEW: [5] */
02729        return;
02730 
02731     if (!col)
02732       return;
02733     if (col != current_text_bg)
02734       current_text_bg->CopyFrom(col);
02735     pixel = current_text_bg->GetPixel(current_cmap, IS_COLOR, 0);
02736     XSetBackground(DPY, TEXT_GC, pixel);
02737 }
02738 
02739 int wxCanvasDC::CacheFontMetricsKey()
02740 {
02741   if ((scale_x == 1.0)
02742       && (scale_y == 1.0))
02743     return 1;
02744   return 0;
02745 }
02746 
02747 //-----------------------------------------------------------------------------
02748 // clipping region
02749 //-----------------------------------------------------------------------------
02750 
02751 static Region empty_rgn;
02752 
02753 void wxWindowDC::SetClippingRect(double x, double y, double w, double h)
02754 {
02755   wxRegion *r;
02756   r = new wxRegion(this);
02757   r->SetRectangle(x, y, w, h);
02758 
02759   SetClippingRegion(r);
02760 }
02761 
02762 void wxWindowDC::SetClippingRegion(wxRegion *r)
02763 {
02764   if (clipping)
02765     --clipping->locked;
02766 
02767   clipping = r;
02768 
02769   if (clipping)
02770     clipping->locked++;
02771 
02772   if (r) {
02773     if (r->rgn) {
02774       USER_REG = r->rgn;
02775     } else {
02776       /* NULL r->rgn means empty region */
02777       if (!empty_rgn)
02778        empty_rgn = XCreateRegion();
02779       USER_REG = empty_rgn;
02780     }
02781   } else
02782     USER_REG = NULL;
02783   SetCanvasClipping();
02784 }
02785 
02786 wxRegion *wxWindowDC:: GetClippingRegion()
02787 {
02788   return clipping;
02789 }
02790 
02791 void wxWindowDC::GetSize(double *w, double *h)
02792 {
02793   Window wdummy; int sdummy; unsigned int udummy, width, height;
02794 
02795   if (DRAWABLE) {
02796     XGetGeometry(DPY, DRAWABLE, &wdummy, &sdummy, &sdummy,
02797                &width, &height, &udummy, &DEPTH);
02798     
02799     *w = width;
02800     *h = height;
02801   } else {
02802     *w = *h = 0;
02803   }
02804 }
02805 
02806 //-----------------------------------------------------------------------------
02807 // methods unique to wxWindowDC
02808 //-----------------------------------------------------------------------------
02809 
02810 void wxWindowDC::Initialize(wxWindowDC_Xinit* init)
02811 {
02812     Drawable GC_drawable; // necessary create a GC (needed for depth,...)
02813     wxFont *font;
02814     XGCValues values;
02815     unsigned long mask;
02816     int width, height;
02817 
02818     DPY = init->dpy; SCN = init->scn;
02819 
02820     if (init->drawable) {
02821       Window wdummy; int sdummy; unsigned int udummy;
02822       // I have a specified drawable -> get width, height, and depth
02823       GC_drawable = DRAWABLE = init->drawable;
02824       XGetGeometry(DPY, DRAWABLE, &wdummy, &sdummy, &sdummy,
02825                  &WIDTH, &HEIGHT, &udummy, &DEPTH);
02826     } else {
02827       GC_drawable = wxAPP_ROOT; // defaults to root
02828       DEPTH = wxDisplayDepth(); // depth is display depth
02829     }
02830     Colour = (DEPTH != 1); // accept everything else than depth one as colour display
02831     if (!Colour && anti_alias)
02832       anti_alias = 0;
02833 
02834 #ifdef WX_USE_XRENDER
02835     X->picture = 0;
02836 #endif
02837 
02838     values.foreground = wx_black_pixel;
02839     values.background = wx_white_pixel;
02840     values.graphics_exposures = FALSE;
02841     values.line_width = 1;
02842     mask = GCForeground | GCBackground | GCGraphicsExposures | GCLineWidth;
02843     PEN_GC   = XCreateGC(DPY, GC_drawable, mask, &values);
02844     TEXT_GC  = XCreateGC(DPY, GC_drawable, mask, &values);
02845     values.foreground = wx_white_pixel;
02846     values.background = wx_black_pixel;
02847     BG_GC    = XCreateGC(DPY, GC_drawable, mask, &values);
02848     BRUSH_GC = XCreateGC(DPY, GC_drawable, mask, &values);
02849 
02850     // set drawing tools
02851     SetTextForeground(current_text_fg);
02852     SetTextBackground(current_text_bg);
02853     SetBackground(current_background_color); 
02854     ResetBrush(current_brush);
02855     ResetPen(current_pen);
02856 
02857     font = current_font;
02858     current_font = NULL;
02859     SetFont(font ? font : wxNORMAL_FONT);
02860 
02861     // set display scaling
02862     width  = WidthOfScreen(SCN);
02863     height = HeightOfScreen(SCN);
02864     mm_to_pix_x = ((double)width)  / ((double)WidthMMOfScreen(SCN));
02865     mm_to_pix_y = ((double)height) / ((double)HeightMMOfScreen(SCN));
02866 }
02867 
02868 void wxWindowDC::Destroy(void)
02869 {
02870 #ifdef WX_USE_CAIRO
02871     ReleaseCairoDev();
02872 #endif
02873 
02874     if (PEN_GC)    XFreeGC(DPY, PEN_GC);
02875     if (BRUSH_GC)  XFreeGC(DPY, BRUSH_GC);
02876     if (TEXT_GC)   XFreeGC(DPY, TEXT_GC);
02877     if (BG_GC)     XFreeGC(DPY, BG_GC);
02878     PEN_GC = BRUSH_GC = TEXT_GC = BG_GC = NULL;
02879 
02880     if (CURRENT_REG) XDestroyRegion(CURRENT_REG);
02881     if (EXPOSE_REG) XDestroyRegion(EXPOSE_REG);
02882     CURRENT_REG = USER_REG = EXPOSE_REG = NULL;
02883 
02884 #ifdef WX_USE_XRENDER
02885     wxFreePicture(X->picture);
02886     X->picture = 0;
02887 #endif
02888 #ifdef USE_GL
02889     if (X->wx_gl) {
02890       X->wx_gl->Reset(NULL, 0, 0);
02891     }
02892 #endif
02893 }
02894 
02895 void wxWindowDC::SetCanvasClipping(void)
02896 {
02897     if (!DRAWABLE)
02898        return;
02899 
02900 #ifdef WX_USE_CAIRO
02901     X->reset_cairo_clip = 1;
02902 #endif
02903 
02904     if (CURRENT_REG)
02905        XDestroyRegion(CURRENT_REG);
02906     if (USER_REG || EXPOSE_REG) {
02907        CURRENT_REG = XCreateRegion();
02908        XIntersectRegion(EXPOSE_REG ? EXPOSE_REG : USER_REG,
02909                       USER_REG ? USER_REG : EXPOSE_REG,
02910                       CURRENT_REG);
02911        XSetRegion(DPY, PEN_GC, CURRENT_REG);
02912        XSetRegion(DPY, BRUSH_GC, CURRENT_REG);
02913        XSetRegion(DPY, BG_GC, CURRENT_REG);
02914        XSetRegion(DPY, TEXT_GC, CURRENT_REG);
02915 #ifdef WX_USE_XFT
02916        if (XFTDRAW)
02917          XftDrawSetClip(XFTDRAW, CURRENT_REG);
02918 #endif
02919     } else {
02920        CURRENT_REG = NULL;
02921        XSetClipMask(DPY, PEN_GC, None);
02922        XSetClipMask(DPY, BRUSH_GC, None);
02923        XSetClipMask(DPY, BG_GC, None);
02924        XSetClipMask(DPY, TEXT_GC, None);
02925 #ifdef WX_USE_XFT
02926        if (XFTDRAW)
02927          XftDrawSetClip(XFTDRAW, None);
02928 #endif
02929     }
02930 }
02931 
02932 Bool wxWindowDC::Ok(void)
02933 {
02934   return !!DRAWABLE;
02935 }
02936 
02937 
02938 Bool wxWindowDC::GetPixel(double x, double y, wxColour * col)
02939 {
02940   int i, j;
02941   Bool mini = 1;
02942   unsigned int w, h;
02943 
02944   if (!DRAWABLE)
02945     return FALSE;
02946 
02947   i = XLOG2DEV(x);
02948   j = YLOG2DEV(y);
02949 
02950   w = X->width;
02951   h = X->height;
02952 
02953   if (i < 0 || (unsigned int)i >= w
02954       || j < 0 || (unsigned int)j >= h)
02955     return FALSE;
02956 
02957 #define NUM_GETPIX_CACHE_COLORS 256
02958 
02959   if (X->get_pixel_image_cache
02960       && ((i < X->cache_dx)
02961          || (i >= X->cache_dx + X->get_pixel_image_cache->width)
02962          || (j < X->cache_dy)
02963          || (j >= X->cache_dy + X->get_pixel_image_cache->height))) {
02964     /* Turns out that getting a small part wasn't such a
02965        good idea. Go into whole-image mode. */
02966     EndSetPixel();
02967     mini = 0;
02968   }
02969 
02970   if (!X->get_pixel_image_cache) {
02971     BeginSetPixel(mini, i, j);
02972 
02973     if (X->get_pixel_image_cache->depth == 1) {
02974       XColor *get_pixel_color_cache;
02975       
02976       get_pixel_color_cache = X->get_pixel_color_cache;
02977       
02978       get_pixel_color_cache[0].pixel = 1;
02979       get_pixel_color_cache[0].red = 0;
02980       get_pixel_color_cache[0].green = 0;
02981       get_pixel_color_cache[0].blue = 0;
02982 
02983       get_pixel_color_cache[1].pixel = 0;
02984       get_pixel_color_cache[1].red = 255;
02985       get_pixel_color_cache[1].green = 255;
02986       get_pixel_color_cache[1].blue = 255;
02987       
02988       X->get_pixel_cache_pos = 2;
02989     }
02990   }
02991 
02992   {
02993     int r, g, b;
02994     GetPixelFast(i, j, &r, &g, &b);
02995     col->Set(r, g, b);
02996   }
02997 
02998   return TRUE;
02999 }
03000 
03001 void wxWindowDC::BeginSetPixel(int mini, int near_i, int near_j)
03002 {
03003   unsigned int w, h, dx, dy, ni = (unsigned int)near_i, nj = (unsigned int)near_j;
03004 
03005   if (!DRAWABLE)
03006     return;
03007 
03008   if (X->get_pixel_image_cache)
03009     return;
03010 
03011   w = X->width;
03012   h = X->height;
03013 
03014   if (X->is_window) {
03015     /* Disallow: */
03016     return;
03017   }
03018 
03019   if (mini) {
03020     /* To lessen the cost of localized get-pixel and set-pixel
03021        in a large bitmap, we first try to get a small piece
03022        of the bitmap in "mini" mode. If we need more, then we'll
03023        jump to "whole-image" mode. */
03024     if (w > wxMINI_SIZE) {
03025       if (ni < (wxMINI_SIZE / 2))
03026        dx = 0;
03027       else if ((ni + (wxMINI_SIZE / 2)) > w)
03028        dx = w - wxMINI_SIZE;
03029       else
03030        dx = ni - (wxMINI_SIZE / 2);
03031       w = wxMINI_SIZE;
03032     } else
03033       dx = 0;
03034     if (h > wxMINI_SIZE) {
03035       if (nj < (wxMINI_SIZE / 2))
03036        dy = 0;
03037       else if ((nj + (wxMINI_SIZE / 2)) > h)
03038        dy = h - wxMINI_SIZE;
03039       else
03040        dy = nj - (wxMINI_SIZE / 2);
03041       h = wxMINI_SIZE;
03042     } else
03043       dy = 0;
03044   } else {
03045     dx = 0;
03046     dy = 0;
03047   }
03048 
03049   {
03050     XImage *img;
03051     img = XGetImage(DPY, DRAWABLE, dx, dy, w, h, AllPlanes, ZPixmap);
03052     X->get_pixel_image_cache = img;
03053   }
03054   
03055   X->get_pixel_cache_pos = 0;
03056   X->get_pixel_cache_full = FALSE;
03057   if (!wx_alloc_color_is_fast || (X->get_pixel_image_cache->depth == 1)) {
03058     XColor *cols;
03059     cols = new WXGC_ATOMIC XColor[NUM_GETPIX_CACHE_COLORS];
03060     X->get_pixel_color_cache = cols;
03061 
03062     if (X->get_pixel_image_cache->depth == 1) {
03063       cols[0].pixel = 1;
03064       cols[0].red = 0;
03065       cols[0].green = 0;
03066       cols[0].blue = 0;
03067 
03068       cols[1].pixel = 0;
03069       cols[1].red = 255;
03070       cols[1].green = 255;
03071       cols[1].blue = 255;
03072       X->get_pixel_cache_pos = 2;
03073     }
03074   }
03075   X->set_a_pixel = FALSE;
03076   X->cache_dx = dx;
03077   X->cache_dy = dy;
03078 }
03079 
03080 void wxWindowDC::EndSetPixel()
03081 {
03082   if (!X->get_pixel_image_cache)
03083     return;
03084 
03085   if (X->set_a_pixel) {
03086     int w, h, dx, dy;
03087     w = X->get_pixel_image_cache->width;
03088     h = X->get_pixel_image_cache->height;
03089     dx = X->cache_dx;
03090     dy = X->cache_dy;
03091     
03092     XPutImage(DPY, DRAWABLE, PEN_GC, X->get_pixel_image_cache, 0, 0, dx, dy, w, h);
03093   }
03094 
03095   if (X->get_pixel_image_cache) {
03096     XDestroyImage(X->get_pixel_image_cache);
03097     X->get_pixel_image_cache = NULL;
03098     X->get_pixel_color_cache = NULL;
03099   }
03100 }
03101 
03102 void wxWindowDC::SetPixel(double x, double y, wxColour * col)
03103 {
03104   int i, j;
03105   int w, h;
03106   int red, green, blue;
03107 
03108   i = XLOG2DEV(x);
03109   j = YLOG2DEV(y);
03110 
03111   BeginSetPixel(1, i, j);
03112 
03113   if (i < 0 || i >= (int)X->width
03114       || j < 0 || j >= (int)X->height)
03115     return;
03116 
03117   w = X->get_pixel_image_cache->width;
03118   h = X->get_pixel_image_cache->height;
03119 
03120   if (X->get_pixel_image_cache
03121       && ((i < X->cache_dx)
03122          || (i >= X->cache_dx + w)
03123          || (j < X->cache_dy)
03124          || (j >= X->cache_dy + h))) {
03125     /* Turns out that getting a small part wasn't such a
03126        good idea. Go into whole-image mode. */
03127     EndSetPixel();
03128     BeginSetPixel(0, i, j);
03129   }
03130 
03131   if (!X->get_pixel_image_cache)
03132     return;
03133 
03134   red = col->Red();
03135   green = col->Green();
03136   blue = col->Blue();
03137 
03138   X->set_a_pixel = TRUE;
03139 
03140   SetPixelFast(i - X->cache_dx, j - X->cache_dy, red, green, blue);
03141 }
03142 
03143 Bool wxWindowDC::BeginSetPixelFast(int x, int y, int w, int h)
03144 {
03145   if (BeginGetPixelFast(x, y, w, h)) {
03146     X->set_a_pixel = TRUE;
03147     return TRUE;
03148   } else
03149     return FALSE;
03150 }
03151 
03152 void wxWindowDC::EndSetPixelFast()
03153 {
03154 }
03155 
03156 void wxWindowDC::SetPixelFast(int i, int j, int red, int green, int blue)
03157 {
03158   int k;
03159   unsigned long pixel;
03160   XImage *get_pixel_image_cache;
03161 
03162   get_pixel_image_cache = X->get_pixel_image_cache;
03163 
03164   if (get_pixel_image_cache->depth == 1) {
03165     if ((red == 255) && (green == 255) && (blue == 255))
03166       pixel = 0;
03167     else
03168       pixel = 1;
03169   } else {
03170     if (wx_alloc_color_is_fast == 2) {
03171       pixel = ((red << wx_simple_r_start) 
03172               | (green << wx_simple_g_start)
03173               | (blue << wx_simple_b_start));
03174     } else {
03175       XColor xcol;
03176 
03177       if (!wx_alloc_color_is_fast) {
03178        int get_pixel_cache_pos;
03179        XColor *get_pixel_color_cache;
03180        Bool get_pixel_cache_full;
03181 
03182        get_pixel_cache_pos = X->get_pixel_cache_pos;
03183        get_pixel_color_cache = X->get_pixel_color_cache;
03184        get_pixel_cache_full = X->get_pixel_cache_full;
03185 
03186        for (k = get_pixel_cache_pos; k--; ) {
03187          if ((get_pixel_color_cache[k].red == red)
03188              && (get_pixel_color_cache[k].green == green)
03189              && (get_pixel_color_cache[k].blue == blue)) {
03190            pixel = get_pixel_color_cache[k].pixel;
03191            goto put;
03192          }
03193        }
03194       
03195        if (get_pixel_cache_full) {
03196          for (k = NUM_GETPIX_CACHE_COLORS; k-- > get_pixel_cache_pos; ) {
03197            if ((get_pixel_color_cache[k].red == red)
03198               && (get_pixel_color_cache[k].green == green)
03199               && (get_pixel_color_cache[k].blue == blue)) {
03200              pixel = get_pixel_color_cache[k].pixel;
03201              goto put;
03202            }
03203          }
03204        }
03205       }
03206 
03207       xcol.red = red << 8;
03208       xcol.green = green << 8;
03209       xcol.blue = blue << 8;
03210       
03211       {
03212        Colormap cm;
03213        cm = GETCOLORMAP(current_cmap);
03214        wxAllocColor(DPY, cm, &xcol);
03215       }
03216       
03217       pixel = xcol.pixel;
03218     }
03219     
03220     if (!wx_alloc_color_is_fast) {
03221       int get_pixel_cache_pos;
03222       XColor *get_pixel_color_cache;
03223 
03224       get_pixel_cache_pos = X->get_pixel_cache_pos;
03225       get_pixel_color_cache = X->get_pixel_color_cache;
03226 
03227       get_pixel_color_cache[get_pixel_cache_pos].pixel = pixel;
03228       get_pixel_color_cache[get_pixel_cache_pos].red = red;
03229       get_pixel_color_cache[get_pixel_cache_pos].green = green;
03230       get_pixel_color_cache[get_pixel_cache_pos].blue = blue;
03231       
03232       if (++(X->get_pixel_cache_pos) >= NUM_GETPIX_CACHE_COLORS) {
03233        X->get_pixel_cache_pos = 0;
03234        X->get_pixel_cache_full = TRUE;
03235       }
03236     }
03237   }
03238 
03239  put:
03240   pixel = XPutPixel(get_pixel_image_cache, i, j, pixel);  
03241 }
03242 
03243 void wxWindowDC::FreeGetPixelCache(void)
03244 {
03245   if (X->get_pixel_image_cache) 
03246     EndSetPixel();
03247 }
03248 
03249 Bool wxWindowDC::BeginGetPixelFast(int x, int y, int w, int h)
03250 {
03251   if ((x >= 0) && (y >= 0)
03252       && ((unsigned int)(x + w) <= X->width)
03253       && ((unsigned int)(y + h) <= X->height)) {
03254 
03255     /* Possible improvement: get only the revelant section of the
03256        bitmap into the image cache, instead of always the entire
03257        image. (In that case, use offsets in the fast Get and Put
03258        operations.) */
03259 
03260     if (X->get_pixel_image_cache
03261         && (X->cache_dx
03262             || X->cache_dy
03263             || (X->get_pixel_image_cache->width < (int)X->width)
03264             || (X->get_pixel_image_cache->height < (int)X->height))) {
03265       /* Need to get out of mini mode */
03266       EndSetPixel();
03267     }
03268 
03269     BeginSetPixel(0, 0, 0);
03270     return TRUE;
03271   } else
03272     return FALSE;
03273 }
03274 
03275 void wxWindowDC::EndGetPixelFast()
03276 {
03277 }
03278 
03279 void wxWindowDC::GetPixelFast(int i, int j, int *r, int *g, int *b)
03280 {
03281   unsigned long pixel;
03282 
03283   pixel = XGetPixel(X->get_pixel_image_cache, i, j);
03284 
03285   if ((wx_alloc_color_is_fast == 2) 
03286       && (X->get_pixel_image_cache->depth != 1)) {
03287     *r = ((pixel >> wx_simple_r_start) & 0xFF);
03288     *g = ((pixel >> wx_simple_g_start) & 0xFF);
03289     *b = ((pixel >> wx_simple_b_start) & 0xFF);
03290   } else {
03291     XColor xcol;
03292 
03293     if (!wx_alloc_color_is_fast
03294        || (X->get_pixel_image_cache->depth == 1)) {
03295       int get_pixel_cache_pos, k;
03296       XColor *get_pixel_color_cache;
03297       Bool get_pixel_cache_full;
03298 
03299       get_pixel_cache_pos = X->get_pixel_cache_pos;
03300       get_pixel_color_cache = X->get_pixel_color_cache;
03301       get_pixel_cache_full = X->get_pixel_cache_full;
03302 
03303       for (k = get_pixel_cache_pos; k--; ) {
03304        if (get_pixel_color_cache[k].pixel == pixel) {
03305          *r = get_pixel_color_cache[k].red;
03306          *g = get_pixel_color_cache[k].green;
03307          *b = get_pixel_color_cache[k].blue;
03308          return;
03309        }
03310       }
03311 
03312       if (get_pixel_cache_full) {
03313        for (k = NUM_GETPIX_CACHE_COLORS; k-- > get_pixel_cache_pos; ) {
03314          if (get_pixel_color_cache[k].pixel == pixel) {
03315            *r = get_pixel_color_cache[k].red;
03316            *g = get_pixel_color_cache[k].green;
03317            *b = get_pixel_color_cache[k].blue;
03318            return;
03319          }
03320        }
03321       }
03322     }
03323   
03324     xcol.pixel = pixel;
03325     {
03326       Colormap cm;
03327       cm = GETCOLORMAP(current_cmap);
03328       wxQueryColor(wxAPP_DISPLAY, cm, &xcol);
03329     }
03330 
03331     if (!wx_alloc_color_is_fast) {
03332       int get_pixel_cache_pos;
03333       XColor *get_pixel_color_cache;
03334     
03335       get_pixel_cache_pos = X->get_pixel_cache_pos;
03336       get_pixel_color_cache = X->get_pixel_color_cache;
03337 
03338       get_pixel_color_cache[get_pixel_cache_pos].pixel = pixel;
03339       get_pixel_color_cache[get_pixel_cache_pos].red = xcol.red >> SHIFT;
03340       get_pixel_color_cache[get_pixel_cache_pos].green = xcol.green >> SHIFT;
03341       get_pixel_color_cache[get_pixel_cache_pos].blue = xcol.blue >> SHIFT;
03342     
03343       if (++get_pixel_cache_pos >= NUM_GETPIX_CACHE_COLORS) {
03344        get_pixel_cache_pos = 0;
03345        X->get_pixel_cache_full = TRUE;
03346       }
03347 
03348       X->get_pixel_cache_pos = get_pixel_cache_pos;
03349     }
03350 
03351     *r = (xcol.red >> SHIFT);
03352     *g = (xcol.green >> SHIFT);
03353     *b = (xcol.blue >> SHIFT);
03354   }
03355 }
03356 
03357 /********************************************************************/
03358 /*                              GL                                  */
03359 /********************************************************************/
03360 
03361 // OpenGL
03362 #ifdef USE_GL
03363 static wxGL *current_gl_context = NULL;
03364 static int gl_registered, display_has_glx;
03365 
03366 static XVisualInfo *null_visual;
03367 static int null_visual_set = 0;
03368 
03369 typedef int (*X_Err_Handler)(Display*, XErrorEvent*);
03370 static int errorFlagged;
03371 static int FlagError(Display*, XErrorEvent*)
03372 {
03373   errorFlagged = 1;
03374   return 0;
03375 }
03376 
03377 static XVisualInfo *GetWindowVisual(wxGLConfig *cfg, Boolean offscreen)
03378 {
03379   XVisualInfo *vi = NULL;
03380   Visual *vis;
03381   GC_CAN_IGNORE XVisualInfo *visi, tmpl, *suggested_vi;
03382   int n, i, ac;
03383   GC_CAN_IGNORE int gl_attribs[20];
03384   X_Err_Handler old_handler;
03385 
03386   if (!gl_registered) {
03387     int a, b, c;
03388 
03389     wxREGGLOB(current_gl_context); 
03390     gl_registered = 1;
03391 
03392     if (XQueryExtension(wxAPP_DISPLAY, "GLX", &a, &b, &c)) {
03393       display_has_glx = 1;
03394     }
03395   }
03396 
03397   if (!display_has_glx)
03398     return NULL;
03399 
03400   if (!cfg)
03401     cfg = new wxGLConfig();
03402 
03403   /* Many parts of the MrEd drawing system rely on using the
03404      default colormap everywhere. So we need a GL visual that
03405      will have the same colormap. Get the default visual, then
03406      get a list of attribute-equivalent visuals, then find the'
03407      ones with the right GL properties... */
03408 
03409   while (1) {
03410     ac = 0;
03411     gl_attribs[ac++] = GLX_RGBA;
03412     if (!offscreen && cfg->doubleBuffered)
03413       gl_attribs[ac++] = GLX_DOUBLEBUFFER;
03414     if (cfg->depth) {
03415       gl_attribs[ac++] = GLX_DEPTH_SIZE;
03416       gl_attribs[ac++] = cfg->depth;
03417     }
03418     if (cfg->stencil) {
03419       gl_attribs[ac++] = GLX_STENCIL_SIZE;
03420       gl_attribs[ac++] = cfg->stencil;
03421     }
03422     if (cfg->accum) {
03423       gl_attribs[ac++] = GLX_ACCUM_RED_SIZE;
03424       gl_attribs[ac++] = cfg->accum;
03425       gl_attribs[ac++] = GLX_ACCUM_GREEN_SIZE;
03426       gl_attribs[ac++] = cfg->accum;
03427       gl_attribs[ac++] = GLX_ACCUM_BLUE_SIZE;
03428       gl_attribs[ac++] = cfg->accum;
03429       gl_attribs[ac++] = GLX_ACCUM_ALPHA_SIZE;
03430       gl_attribs[ac++] = cfg->accum;
03431     }
03432     if (cfg->stereo) {
03433       gl_attribs[ac++] = GLX_STEREO;
03434     }
03435 #if defined(GL_ARB_multisample) && defined (GLX_SAMPLES_ARB)
03436     if (cfg->multisample) {
03437       gl_attribs[ac++] = GLX_SAMPLES_ARB;
03438       gl_attribs[ac++] = cfg->multisample;
03439     }
03440 #else
03441 # if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) && defined(GLX_SAMPLES_SGIS)
03442     if (cfg->multisample) {
03443       gl_attribs[ac++] = GLX_SAMPLES_SGIS;
03444       gl_attribs[ac++] = cfg->multisample;
03445     }
03446 # endif
03447 #endif    
03448     
03449     gl_attribs[ac] = None;
03450     
03451     XSync(wxAPP_DISPLAY, FALSE);
03452     old_handler = XSetErrorHandler(FlagError);
03453     errorFlagged = 0;
03454     
03455     suggested_vi = glXChooseVisual(wxAPP_DISPLAY, XScreenNumberOfScreen(wxAPP_SCREEN), gl_attribs);
03456     if (errorFlagged) {
03457       suggested_vi = NULL;
03458       errorFlagged = 0;
03459     }
03460 
03461     XSetErrorHandler(old_handler);
03462 
03463     /* If we got a vi, stop. Otherwise, try changing
03464        the config until we find one. */
03465     if (suggested_vi)
03466       break;
03467     else if (cfg->multisample) {
03468       cfg = cfg->Clone();
03469       cfg->multisample = 0;
03470     } else
03471       break;
03472   }
03473     
03474   vis = wxAPP_VISUAL;
03475     
03476   tmpl.visualid = XVisualIDFromVisual(vis);
03477   visi = XGetVisualInfo(wxAPP_DISPLAY, VisualIDMask, &tmpl, &n);
03478   memcpy(&tmpl, visi, sizeof(tmpl));
03479   XFree(visi);
03480 
03481   /* Equivalent visuals: */
03482   visi = XGetVisualInfo(wxAPP_DISPLAY, 
03483                      (VisualScreenMask
03484                       | VisualDepthMask
03485                       | VisualClassMask
03486                       | VisualRedMaskMask
03487                       | VisualGreenMaskMask
03488                       | VisualBlueMaskMask
03489                       | VisualColormapSizeMask
03490                       | VisualBitsPerRGBMask),
03491                      &tmpl, &n);
03492 
03493   XSync(wxAPP_DISPLAY, FALSE);
03494   old_handler = XSetErrorHandler(FlagError);
03495 
03496   /* Search for double-buffered and single-buffered: */
03497 
03498   for (i = 0; i < n; i++) {
03499     if (suggested_vi) {
03500       if (visi[i].visualid == suggested_vi->visualid) {
03501        vi = suggested_vi;
03502        break;
03503       }
03504     }
03505   }
03506   
03507   /* The vi returned by XGetVisualInfo doesn't match our colormap.
03508      Manually search. */
03509   if (i >= n) {
03510     int pts, max_pts = 0;
03511     int min_aux_match = 1000;
03512     int min_sten_match = 1000;
03513     int min_depth_match = 1000;
03514          
03515     for (i = 0; i < n; i++) {
03516       int v;
03517       glXGetConfig(wxAPP_DISPLAY, visi + i, GLX_USE_GL, &v);
03518       if (v && !errorFlagged) {
03519        glXGetConfig(wxAPP_DISPLAY, visi + i, GLX_LEVEL, &v);
03520        if (!v && !errorFlagged)  {
03521          glXGetConfig(wxAPP_DISPLAY, visi + i, GLX_STEREO, &v);
03522          if ((!v == cfg->stereo) && !errorFlagged)  {
03523            glXGetConfig(wxAPP_DISPLAY, visi + i, GLX_DOUBLEBUFFER, &v);
03524            if ((!v == !cfg->doubleBuffered) && !errorFlagged) {
03525              pts = 0;
03526              glXGetConfig(wxAPP_DISPLAY, visi + i, GLX_AUX_BUFFERS, &v);
03527              if (v <= min_aux_match)
03528               pts += 4;
03529              glXGetConfig(wxAPP_DISPLAY, visi + i, GLX_STENCIL_SIZE, &v);
03530              if ((v <= min_sten_match) && (v >= cfg->stencil))
03531               pts += 4;
03532              glXGetConfig(wxAPP_DISPLAY, visi + i, GLX_DEPTH_SIZE, &v);
03533              if ((v <= min_depth_match) && (v >= cfg->depth))
03534               pts += 4;
03535              glXGetConfig(wxAPP_DISPLAY, visi + i, GLX_ACCUM_RED_SIZE, &v);
03536              if (v >= cfg->accum)
03537               pts++;
03538              glXGetConfig(wxAPP_DISPLAY, visi + i, GLX_ACCUM_GREEN_SIZE, &v);
03539              if (v >= cfg->accum)
03540               pts++;
03541              glXGetConfig(wxAPP_DISPLAY, visi + i, GLX_ACCUM_BLUE_SIZE, &v);
03542              if (v >= cfg->accum)
03543               pts++;
03544              glXGetConfig(wxAPP_DISPLAY, visi + i, GLX_ACCUM_ALPHA_SIZE, &v);
03545              if (v >= cfg->accum)
03546               pts++;
03547              if ((pts <= max_pts) && !errorFlagged) {
03548               max_pts = pts;
03549               vi = visi + i;
03550              }
03551            }
03552          }
03553        }
03554       }
03555     }
03556   }
03557 
03558   XFree(visi);
03559 
03560   XSetErrorHandler(old_handler);
03561 
03562   return vi;
03563 }
03564 
03565 Visual *wxGetGLCanvasVisual(wxGLConfig *cfg)
03566 {
03567   XVisualInfo *vi;
03568 
03569   if (!cfg && null_visual_set)
03570     vi = null_visual;
03571   else {
03572     vi = GetWindowVisual(cfg, FALSE);
03573     
03574     if (!cfg) {
03575       null_visual_set = 1;
03576       null_visual = vi;
03577     }
03578   }
03579 
03580   if (vi)
03581     return vi->visual;
03582   else
03583     return NULL;
03584 }
03585 
03586 wxGL::wxGL()
03587 : wxObject(WXGC_NO_CLEANUP)
03588 {
03589 }
03590 
03591 wxGL::~wxGL()
03592 {
03593 }
03594 
03595 int wxGL::Ok()
03596 {
03597   return !!GLctx;
03598 }
03599 
03600 void wxGL::Reset(wxGLConfig *cfg, long d, int offscreen)
03601 {
03602   XVisualInfo *vi;
03603   draw_to = 0;
03604 
03605   if (this == current_gl_context) {
03606     glXMakeCurrent(wxAPP_DISPLAY, None, NULL);
03607   }
03608   
03609   if (GLctx) {
03610     glXDestroyContext(wxAPP_DISPLAY, (GLXContext)GLctx);
03611     GLctx = 0;
03612     __type = wxTYPE_OBJECT; /* indicates "never selected" */
03613   }
03614 
03615   if (glx_pm) {
03616     glXDestroyGLXPixmap(wxAPP_DISPLAY, (GLXPixmap)glx_pm);
03617     glx_pm = 0;
03618   }
03619 
03620   if (d)
03621     vi = GetWindowVisual(cfg, offscreen);
03622   else
03623     vi = NULL;
03624 
03625   if (d) {
03626     GLXContext ctx;
03627 
03628     ctx = glXCreateContext(wxAPP_DISPLAY,
03629                         vi,
03630                         NULL,
03631                         offscreen ? GL_FALSE : GL_TRUE);
03632 
03633     GLctx = (long)ctx;
03634 
03635     if (GLctx) {
03636       if (offscreen) {
03637        GLXPixmap pm;
03638        
03639        pm = glXCreateGLXPixmap(wxAPP_DISPLAY, vi, (Drawable)d);
03640        glx_pm = (long)pm;
03641        draw_to = (long)pm;
03642       } else
03643        draw_to = d;
03644        
03645       if (current_gl_context == this) {
03646        ThisContextCurrent();
03647       }
03648     }
03649   }
03650 }
03651 
03652 void wxGL::SwapBuffers(void)
03653 {
03654   if (GLctx) {
03655     if (!glx_pm) {
03656       /* Only if it's been selected before. Some X servers
03657         seem to get annoyed, otherwise. */
03658       if (__type == wxTYPE_DC_OBJECT)
03659        glXSwapBuffers(wxAPP_DISPLAY, (Drawable)draw_to);
03660     }
03661   }
03662 }
03663 
03664 void wxGL::ThisContextCurrent(void)
03665 {
03666   if (current_gl_context != this) {
03667     current_gl_context = this;
03668     if (GLctx) {
03669       glXMakeCurrent(wxAPP_DISPLAY, (Drawable)draw_to, (GLXContext)GLctx);
03670       __type = wxTYPE_DC_OBJECT; /* indicates "selected" */
03671     } else {
03672       glXMakeCurrent(wxAPP_DISPLAY, None, NULL);
03673     }
03674   }
03675 }
03676 
03677 void wxGLNoContext(void)
03678 {
03679   glXMakeCurrent(wxAPP_DISPLAY, None, NULL);
03680   current_gl_context = NULL;
03681 }
03682 
03683 #endif
03684 
03685 #include "../../../wxcommon/wxGLConfig.cxx"
03686 
03687 /********************************************************************/
03688 /*                         Cairo                                    */
03689 /********************************************************************/
03690 
03691 #ifdef WX_USE_CAIRO
03692 void wxWindowDC::InitCairoDev()
03693 {
03694   if (!X->cairo_dev) {
03695     cairo_t *dev;
03696     double ww, hh;
03697 
03698     GetSize(&ww, &hh);
03699     cairo_set_create_xlib(dev, wxAPP_DISPLAY, DRAWABLE, wxAPP_VISUAL, (int)ww, (int)hh);
03700     X->cairo_dev = (long)dev;
03701     X->reset_cairo_clip = 1;
03702   }
03703 
03704   cairo_default_matrix(CAIRO_DEV);
03705   if (X->reset_cairo_clip) {
03706     cairo_init_clip(CAIRO_DEV);
03707     if (EXPOSE_REG) {
03708       /* We assume a rectangular expose region. */
03709       XRectangle r;
03710       XClipBox(EXPOSE_REG, &r);
03711       cairo_new_path(CAIRO_DEV);
03712       cairo_move_to(CAIRO_DEV, r.x, r.y);
03713       cairo_rel_line_to(CAIRO_DEV, 0, r.height);
03714       cairo_rel_line_to(CAIRO_DEV, r.width, 0);
03715       cairo_rel_line_to(CAIRO_DEV, 0, -r.height);
03716       cairo_clip(CAIRO_DEV);
03717       cairo_new_path(CAIRO_DEV);
03718     }
03719     if (clipping)
03720       clipping->Install((long)CAIRO_DEV, AlignSmoothing());
03721     X->reset_cairo_clip = 0;
03722   }
03723   if (!AlignSmoothing()) {
03724     cairo_translate(CAIRO_DEV, device_origin_x, device_origin_y);
03725     cairo_scale(CAIRO_DEV, scale_x, scale_y);
03726   }
03727   
03728 }
03729 
03730 void wxWindowDC::ReleaseCairoDev()
03731 {
03732   if (X->cairo_dev) {
03733     cairo_destroy_it(CAIRO_DEV);
03734     X->cairo_dev = 0;
03735   }
03736 }
03737 
03738 static double cairo_dotted[] = {2, 5, /* offset */ 2};
03739 static double cairo_short_dashed[] = {4, 4, /* offset */ 2};
03740 static double cairo_long_dashed[] = {4, 8, /* offset */ 2};
03741 static double cairo_dotted_dashed[] = {6, 6, 2, 6, /* offset */ 4};
03742 
03743 
03744 Bool wxWindowDC::SetCairoPen()
03745 {
03746   if (current_pen && current_pen->GetStyle() != wxTRANSPARENT) {
03747     wxColour *c;
03748     double pw;
03749     int cs, js;
03750     double *dashes;
03751     int ndash, r, g, b;
03752     double offset;
03753 
03754     c = current_pen->GetColour();
03755     r = c->Red();
03756     g = c->Green();
03757     b = c->Blue();
03758     cairo_set_source_rgba(CAIRO_DEV, 
03759                           r / 255.0, g / 255.0, b / 255.0,
03760                           current_alpha);
03761 
03762     pw = current_pen->GetWidthF();
03763     if (AlignSmoothing()) {
03764       pw = (int)pw;
03765       pw = (int)(pw * user_scale_x);
03766       if (!pw)
03767        pw = 1;
03768     } else {
03769       if (!pw) {
03770        if (scale_y > scale_x)
03771          pw = 1 / scale_x;
03772        else
03773          pw = 1 / scale_y;
03774       }
03775     }
03776     cairo_set_line_width(CAIRO_DEV, pw);
03777 
03778     cs = current_pen->GetCap();
03779     cairo_set_line_cap(CAIRO_DEV, c_cap_style[cs]);
03780 
03781     js = current_pen->GetJoin();
03782     cairo_set_line_join(CAIRO_DEV, c_join_style[js]);
03783 
03784     switch (current_pen->GetStyle ()) {
03785     case wxDOT:
03786       dashes = cairo_dotted;
03787       ndash = (sizeof(cairo_dotted) / sizeof(double)) - 1;
03788       break;
03789     case wxSHORT_DASH:
03790       dashes = cairo_short_dashed;
03791       ndash = (sizeof(cairo_short_dashed) / sizeof(double)) - 1;
03792       break;
03793     case wxLONG_DASH:
03794       dashes = cairo_long_dashed;
03795       ndash = (sizeof(cairo_long_dashed) / sizeof(double)) - 1;
03796       break;
03797     case wxDOT_DASH:
03798       dashes = cairo_dotted_dashed;
03799       ndash = (sizeof(cairo_dotted_dashed) / sizeof(double)) - 1;
03800       break;
03801     case wxSOLID:
03802     case wxTRANSPARENT:
03803     default:
03804       dashes = NULL;
03805       ndash = 0;
03806       break;
03807     }
03808     if (ndash)
03809       offset = dashes[ndash];
03810     else
03811       offset = 0;
03812     cairo_set_dash(CAIRO_DEV, dashes, ndash, offset);
03813 
03814     return TRUE;
03815   } else
03816     return FALSE;
03817 }
03818 
03819 Bool wxWindowDC::SetCairoBrush()
03820 {
03821   if (current_brush && current_brush->GetStyle() != wxTRANSPARENT) {
03822     wxColour *c;
03823     int r, g, b;
03824     c = current_brush->GetColour();
03825     r = c->Red();
03826     g = c->Green();
03827     b = c->Blue();
03828     cairo_set_source_rgba(CAIRO_DEV, 
03829                           r / 255.0, g / 255.0, b / 255.0,
03830                           current_alpha);
03831     return TRUE;
03832   } else
03833     return FALSE;
03834 }
03835 
03836 void wxWindowDC::SetAlpha(double d)
03837 {
03838   wxDC::SetAlpha(d);
03839 }
03840 
03841 Bool wxWindowDC::AlignSmoothing()
03842 {
03843   return (anti_alias == 2);
03844 }
03845 
03846 double wxWindowDC::GetPenSmoothingOffset()
03847 {
03848   int pw;
03849   pw = current_pen->GetWidth();
03850   pw = (int)(user_scale_x * pw);
03851   if (!pw)
03852     pw = 1;
03853   return ((pw & 1) * 0.5);
03854 }
03855 
03856 double wxWindowDC::SmoothingXFormX(double x)
03857 {
03858   if (AlignSmoothing())
03859     return floor((x * user_scale_x) + device_origin_x) + GetPenSmoothingOffset();
03860   else
03861     return x;
03862 }
03863 
03864 double wxWindowDC::SmoothingXFormY(double y)
03865 {
03866   if (AlignSmoothing())
03867     return floor((y * user_scale_y) + device_origin_y) + GetPenSmoothingOffset();
03868   else
03869     return y;
03870 }
03871 
03872 double wxWindowDC::SmoothingXFormW(double w, double x)
03873 {
03874   if (AlignSmoothing())
03875     return SmoothingXFormX(x + w) - SmoothingXFormX(x);
03876   else
03877     return w;
03878 }
03879 
03880 double wxWindowDC::SmoothingXFormH(double h, double y)
03881 {
03882   if (AlignSmoothing())
03883     return SmoothingXFormY(y + h) - SmoothingXFormY(y);
03884   else
03885     return h;
03886 }
03887 
03888 double wxWindowDC::SmoothingXFormXB(double x)
03889 {
03890   if (AlignSmoothing())
03891     return floor((x * user_scale_x) + device_origin_x);
03892   else
03893     return x;
03894 }
03895 
03896 double wxWindowDC::SmoothingXFormYB(double y)
03897 {
03898   if (AlignSmoothing())
03899     return floor((y * user_scale_y) + device_origin_y);
03900   else
03901     return y;
03902 }
03903 
03904 double wxWindowDC::SmoothingXFormWL(double w, double x)
03905 {
03906   if (AlignSmoothing()) {
03907     w = SmoothingXFormW(w, x);
03908     if (w >= 1.0)
03909       return w - 1.0;
03910     else
03911       return w;
03912   } else
03913     return w;
03914 }
03915 
03916 double wxWindowDC::SmoothingXFormHL(double h, double y)
03917 {
03918   if (AlignSmoothing()) {
03919     h = SmoothingXFormH(h, y);
03920     if (h >= 1.0)
03921       return h - 1.0;
03922     else
03923       return h;
03924   } else
03925     return h;
03926 }
03927 #endif
03928 
03929 void wxWindowDC::SetAntiAlias(int v)
03930 {
03931 #ifdef WX_USE_CAIRO
03932   if (v != anti_alias) {
03933     /* In case we go from aligned to not: */
03934     X->reset_cairo_clip = 1;
03935   }
03936     
03937   wxDC::SetAntiAlias(v);
03938 #endif
03939 }