Back to index

texmacs  1.0.7.15
qt_renderer.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : qt_renderer.cpp
00004 * DESCRIPTION: QT drawing interface class
00005 * COPYRIGHT  : (C) 2008 Massimiliano Gubinelli
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "qt_renderer.hpp"
00013 #include "analyze.hpp"
00014 #include "image_files.hpp"
00015 #include "qt_utilities.hpp"
00016 #include "file.hpp"
00017 #include "image_files.hpp"
00018 
00019 #include <QObject>
00020 #include <QWidget>
00021 #include <QPaintDevice>
00022 #include <QPixmap>
00023 
00024 /******************************************************************************
00025 * Qt images
00026 ******************************************************************************/
00027 
00028 struct qt_image_rep: concrete_struct {
00029   QTMImage *img;
00030   SI xo,yo;
00031   int w,h;
00032   qt_image_rep (QTMImage* img2, SI xo2, SI yo2, int w2, int h2):
00033     img (img2), xo (xo2), yo (yo2), w (w2), h (h2) {};
00034   ~qt_image_rep() { delete img; };
00035   friend class qt_image;
00036 };
00037 
00038 class qt_image {
00039 CONCRETE_NULL(qt_image);
00040   qt_image (QTMImage* img2, SI xo2, SI yo2, int w2, int h2):
00041     rep (tm_new<qt_image_rep> (img2, xo2, yo2, w2, h2)) {};
00042   // qt_image ();
00043 };
00044 
00045 CONCRETE_NULL_CODE(qt_image);
00046 
00047 /******************************************************************************
00048  * Qt pixmaps
00049  ******************************************************************************/
00050 
00051 struct qt_pixmap_rep: concrete_struct {
00052   QPixmap *img;
00053   SI xo,yo;
00054   int w,h;
00055   qt_pixmap_rep (QPixmap* img2, SI xo2, SI yo2, int w2, int h2):
00056     img (img2), xo (xo2), yo (yo2), w (w2), h (h2) {};
00057   ~qt_pixmap_rep()  { delete img; };
00058   friend class qt_pixmap;
00059 };
00060 
00061 class qt_pixmap {
00062 CONCRETE_NULL(qt_pixmap);
00063   qt_pixmap (QPixmap* img2, SI xo2, SI yo2, int w2, int h2):
00064     rep (tm_new<qt_pixmap_rep> (img2, xo2, yo2, w2, h2)) {};
00065   // qt_pixmap ();
00066 };
00067 
00068 CONCRETE_NULL_CODE(qt_pixmap);
00069 
00070 /******************************************************************************
00071 * Global support variables for all qt_renderers
00072 ******************************************************************************/
00073 
00074 // bitmaps of all characters
00075 static hashmap<basic_character,qt_image> character_image;  
00076 // image cache
00077 static hashmap<string,qt_pixmap> images;
00078 
00079 /******************************************************************************
00080 * qt_renderer
00081 ******************************************************************************/
00082 
00083 qt_renderer_rep::qt_renderer_rep (QPainter *_painter, int w2, int h2):
00084   basic_renderer_rep(w2, h2), painter(_painter) {}
00085 
00086 qt_renderer_rep::~qt_renderer_rep () {}
00087 
00088 void
00089 qt_renderer_rep::begin (void* handle) {
00090   QPaintDevice *device = (QPaintDevice*)handle;
00091   painter->begin (device);
00092   w = painter->device()->width();
00093   h = painter->device()->height();
00094 }
00095 
00096 void qt_renderer_rep::end () { painter->end (); }
00097 
00098 void 
00099 qt_renderer_rep::get_extents (int& w2, int& h2) {  
00100   if (painter->device()) {
00101     w2 = painter->device()->width(); h2 = painter->device()->height();
00102   } else {
00103     w2 = w; h2 = h;
00104   }
00105 }
00106 
00107 /******************************************************************************
00108  * Clipping
00109  ******************************************************************************/
00110 
00111 void
00112 qt_renderer_rep::set_clipping (SI x1, SI y1, SI x2, SI y2, bool restore)
00113 {
00114   (void) restore;
00115   basic_renderer_rep::set_clipping (x1, y1, x2, y2);
00116   outer_round (x1, y1, x2, y2);
00117   decode (x1, y1);
00118   decode (x2, y2);
00119   if ((x1<x2) && (y2<y1)) {
00120     QRect r(x1,y2,x2-x1,y1-y2);
00121     painter->setClipRect(r);
00122   } else {
00123     painter->setClipRect(QRect());
00124   }
00125 }
00126 
00127 
00128 
00129 /******************************************************************************
00130 * Drawing 
00131 ******************************************************************************/
00132 
00133 void
00134 qt_renderer_rep::set_color (color c) {
00135   basic_renderer_rep::set_color(c);
00136   QPen p (painter->pen ());
00137   QBrush b (painter->brush ());
00138   p.setColor (to_qcolor(cur_fg));
00139   b.setColor (to_qcolor(cur_fg));
00140   painter->setPen (p);
00141   painter->setBrush (b);
00142 }
00143 
00144 void
00145 qt_renderer_rep::set_line_style (SI lw, int type, bool round) {
00146   (void) type;
00147   QPen p (painter->pen ());
00148   if (lw <= pixel) p.setWidth (0);
00149   else p.setWidth ((lw+thicken) / (1.0*pixel));
00150   p.setCapStyle (round? Qt::RoundCap: Qt::SquareCap);
00151   p.setJoinStyle (Qt::RoundJoin);
00152   painter->setPen (p);
00153 }
00154 
00155 void
00156 qt_renderer_rep::line (SI x1, SI y1, SI x2, SI y2) {
00157   decode (x1, y1);
00158   decode (x2, y2);
00159   // y1--; y2--; // top-left origin to bottom-left origin conversion
00160   painter->setRenderHints (QPainter::Antialiasing);
00161   painter->drawLine (x1, y1, x2, y2);
00162 }
00163 
00164 void
00165 qt_renderer_rep::lines (array<SI> x, array<SI> y) {
00166   int i, n= N(x);
00167   if ((N(y) != n) || (n<1)) return;
00168   STACK_NEW_ARRAY (pnt, QPoint, n);
00169   for (i=0; i<n; i++) {
00170     SI xx= x[i], yy= y[i];
00171     decode (xx, yy);
00172     pnt[i].rx()= xx;
00173     pnt[i].ry()= yy;
00174     if (i>0) {
00175       painter->setRenderHints (QPainter::Antialiasing);
00176       painter->drawLine (pnt[i-1], pnt[i]); // FIX: hack
00177     }
00178   }
00179   // XDrawLines (dpy, win, gc, pnt, n, CoordModeOrigin);
00180   STACK_DELETE_ARRAY (pnt);
00181 }
00182 
00183 void
00184 qt_renderer_rep::clear (SI x1, SI y1, SI x2, SI y2) {
00185   x1= max (x1, cx1-ox); y1= max (y1, cy1-oy);
00186   x2= min (x2, cx2-ox); y2= min (y2, cy2-oy);
00187   // outer_round (x1, y1, x2, y2); might still be needed somewhere
00188   decode (x1, y1);
00189   decode (x2, y2);
00190   if ((x1>=x2) || (y1<=y2)) return;
00191   QBrush brush (to_qcolor(cur_bg));
00192   painter->setRenderHints (0);
00193   painter->fillRect (x1, y2, x2-x1, y1-y2, brush);       
00194 }
00195 
00196 void
00197 qt_renderer_rep::fill (SI x1, SI y1, SI x2, SI y2) {
00198   if ((x2>x1) && ((x2-x1)<pixel)) {
00199     SI d= pixel-(x2-x1);
00200     x1 -= (d>>1);
00201     x2 += ((d+1)>>1);
00202   }
00203   if ((y2>y1) && ((y2-y1)<pixel)) {
00204     SI d= pixel-(y2-y1);
00205     y1 -= (d>>1);
00206     y2 += ((d+1)>>1);
00207   }
00208 
00209   x1= max (x1, cx1-ox); y1= max (y1, cy1-oy);
00210   x2= min (x2, cx2-ox); y2= min (y2, cy2-oy);
00211   // outer_round (x1, y1, x2, y2); might still be needed somewhere
00212   if ((x1>=x2) || (y1>=y2)) return;
00213 
00214   decode (x1, y1);
00215   decode (x2, y2);
00216 
00217   QBrush brush (to_qcolor(cur_fg));
00218   painter->setRenderHints (0);
00219   painter->fillRect (x1, y2, x2-x1, y1-y2, brush);       
00220 }
00221 
00222 void
00223 qt_renderer_rep::arc (SI x1, SI y1, SI x2, SI y2, int alpha, int delta) {
00224   (void) alpha; (void) delta;
00225   if ((x1>=x2) || (y1>=y2)) return;
00226   decode (x1, y1);
00227   decode (x2, y2);
00228   painter->setRenderHints (QPainter::Antialiasing);
00229   painter->drawArc (x1, y2, x2-x1, y1-y2, alpha / 4, delta / 4);
00230 }
00231 
00232 void
00233 qt_renderer_rep::fill_arc (SI x1, SI y1, SI x2, SI y2, int alpha, int delta) {
00234   (void) alpha; (void) delta;
00235   if ((x1>=x2) || (y1>=y2)) return;
00236   decode (x1, y1);
00237   decode (x2, y2);
00238   QBrush brush(to_qcolor(cur_fg));
00239   QPainterPath pp;
00240   pp.arcMoveTo (x1, y2, x2-x1, y1-y2, alpha / 64);
00241   pp.arcTo (x1, y2, x2-x1, y1-y2, alpha / 64, delta / 64);
00242   pp.closeSubpath ();
00243   pp.setFillRule (Qt::WindingFill);
00244   painter->setRenderHints (QPainter::Antialiasing);
00245   painter->fillPath (pp, brush);
00246 }
00247 
00248 void
00249 qt_renderer_rep::polygon (array<SI> x, array<SI> y, bool convex) {
00250   int i, n= N(x);
00251   if ((N(y) != n) || (n<1)) return;
00252   QPolygonF poly(n);
00253   for (i=0; i<n; i++) {
00254     SI xx= x[i], yy= y[i];
00255     decode (xx, yy);
00256     poly[i] = QPointF (xx, yy);
00257   }
00258   QBrush brush(to_qcolor(cur_fg));
00259   QPainterPath pp;
00260   pp.addPolygon (poly);
00261   pp.closeSubpath ();
00262   pp.setFillRule (convex? Qt::OddEvenFill: Qt::WindingFill);
00263   painter->setRenderHints (QPainter::Antialiasing);
00264   painter->fillPath (pp, brush);
00265 }
00266 
00267 
00268 /******************************************************************************
00269 * Image rendering
00270 ******************************************************************************/
00271 
00272 struct qt_cache_image_rep: cache_image_element_rep {
00273   qt_cache_image_rep (int w2, int h2, time_t time2, QImage *ptr2):
00274     cache_image_element_rep (w2, h2, time2, ptr2) {}
00275   virtual ~qt_cache_image_rep () {
00276     delete static_cast<QImage*> (ptr); }
00277 };
00278 
00279 void
00280 qt_renderer_rep::image (url u, SI w, SI h, SI x, SI y,
00281                         double cx1, double cy1, double cx2, double cy2,
00282                         int alpha)
00283 {
00284   // Given an image of original size (W, H),
00285   // we display the part (cx1 * W, xy1 * H, cx2 * W, cy2 * H)
00286   // at position (x, y) in a rectangle of size (w, h)
00287   if(cx2<=cx1 || cy2<=cy1) return;
00288 
00289   w= w/pixel; h= h/pixel;
00290   decode (x, y);
00291 
00292   // safety check
00293   url ru = resolve(u);
00294   u = is_none (ru) ? "$TEXMACS_PATH/misc/pixmaps/unknown.ps" : ru;
00295   
00296   QImage *pm = NULL;
00297   tree lookup= tuple (u->t);
00298   lookup << as_string (w ) << as_string (h )
00299          << as_string (cx1) << as_string (cy1)
00300          << as_string (cx2) << as_string (cy2) << "qt-image" ;
00301   cache_image_element ci = get_image_cache(lookup);
00302   if (!is_nil(ci)) {
00303     pm= static_cast<QImage*> (ci->ptr);
00304   } else {
00305     // rendering
00306     bool needs_crop= false;
00307     if (qt_supports (u)) {
00308       pm= new QImage (utf8_to_qstring (concretize (u)));
00309       needs_crop= true;
00310     }
00311     else if (suffix (u) == "ps" ||
00312              suffix (u) == "eps" ||
00313              suffix (u) == "pdf") {
00314       url temp= url_temp (".png");
00315       image_to_png (u, temp, w, h);
00316       needs_crop= true;
00317 /*
00318       string idstr= eval_system ("identify",u);
00319       int i=0;
00320       int a=0,b=0;
00321       while(i<N(idstr)) {
00322         b=0;
00323         if(idstr[i]==' ') {
00324           i++;
00325           a=i;
00326           while(i<N(idstr) && idstr[i]>'0' && idstr[i]<'9')
00327             i++;
00328           if(i>=N(idstr))
00329             break;
00330           if(idstr[i] != 'x')
00331             continue;
00332           i++;
00333           b=i;
00334           while(i<N(idstr) && idstr[i]>'0' && idstr[i]<'9')
00335             i++;
00336           if(i<N(idstr) && idstr[i]==' ')
00337             break;
00338         }
00339         i++;
00340       }
00341       int iw,ih;
00342       if(b>0) {
00343         iw=as_int(idstr(a,b-1));
00344         ih=as_int(idstr(b,i));
00345       } else {
00346         int bbx1,bby1,bbx2,bby2;
00347         ps_bounding_box(u,bbx1,bby1,bbx2,bby2);
00348         iw=bbx2-bbx1;
00349         ih=bby2-bby1;
00350       }
00351 
00352 //      float resx = 72*w/((bbx2-bbx1)*(cx2-cx1));
00353 //      float resy = 72*h/((bby2-bby1)*(cy2-cy1));
00354       float resx = 144*w/(iw*(cx2-cx1));
00355       float resy = 144*h/(ih*(cy2-cy1));
00356 
00357       url temp= url_temp (".png");
00358       system ("convert -density " * as_string(resx) * "x" * as_string(resy)
00359              * " -scale 50% -crop " * as_string(w) * "x" * as_string(h)
00360              * "+" * as_string (cx1*w/(cx2-cx1))
00361              * "+" * as_string ((1-cy2)*h/(cy2-cy1))
00362              * "! -background white -flatten", u, temp);
00363 */
00364       pm= new QImage (to_qstring (as_string (temp)));
00365       remove (temp);
00366     }
00367     if (pm == NULL || pm->isNull ()) {
00368       cout << "TeXmacs] warning: cannot render " << concretize (u) << "\n";
00369       if (pm != NULL) delete pm;
00370       return;
00371     }
00372 
00373     if(needs_crop) {
00374       int iw= pm->width ();
00375       int ih= pm->height ();
00376       int x1= as_int (cx1 * iw);
00377       int y1= as_int (cy1 * ih);
00378       int x2= as_int (cx2 * iw);
00379       int y2= as_int (cy2 * ih);
00380       int ww= x2 - x1;
00381       int hh= y2 - y1;
00382 
00383       (*pm)= pm->copy(QRect (x1, hh-y2, ww, hh));
00384       (*pm)= pm->scaled(w,h);
00385     }
00386 
00387     ci = tm_new<qt_cache_image_rep> (w,h, texmacs_time(), pm);
00388     set_image_cache(lookup, ci);
00389     (ci->nr)++;
00390   }
00391 
00392   qreal old_opacity= painter->opacity ();
00393   painter->setOpacity (qreal (alpha) / qreal (255));
00394   painter->drawImage (x, y-h, *pm);
00395   painter->setOpacity (old_opacity);
00396 };
00397 
00398 
00399 void
00400 qt_renderer_rep::draw_clipped (QImage *im, int w, int h, SI x, SI y) {
00401   (void) w; (void) h;
00402   int x1=cx1-ox, y1=cy2-oy, x2= cx2-ox, y2= cy1-oy;
00403   decode (x , y );
00404   decode (x1, y1);
00405   decode (x2, y2);
00406   y--; // top-left origin to bottom-left origin conversion
00407        // clear(x1,y1,x2,y2);
00408   painter->setRenderHints (0);
00409   painter->drawImage (x, y, *im);
00410 }
00411 
00412 void
00413 qt_renderer_rep::draw_clipped (QPixmap *im, int w, int h, SI x, SI y) {
00414   decode (x , y );
00415   y--; // top-left origin to bottom-left origin conversion
00416   // clear(x1,y1,x2,y2);
00417   painter->setRenderHints (0);
00418   painter->drawPixmap (x, y, w, h, *im);
00419 }
00420 
00421 
00422 
00423 void
00424 qt_renderer_rep::draw (int c, font_glyphs fng, SI x, SI y) {
00425   // get the pixmap
00426   basic_character xc (c, fng, sfactor, cur_fg, 0);
00427   qt_image mi = character_image [xc];
00428   if (is_nil(mi)) {
00429     int r, g, b, a;
00430     get_rgb (cur_fg, r, g, b, a);
00431     SI xo, yo;
00432     glyph pre_gl= fng->get (c); if (is_nil (pre_gl)) return;
00433     glyph gl= shrink (pre_gl, sfactor, sfactor, xo, yo);
00434     int i, j, w= gl->width, h= gl->height;
00435 #ifdef QTMPIXMAPS
00436     QTMImage *im = new QPixmap(w,h);
00437     {
00438       int nr_cols= sfactor*sfactor;
00439       if (nr_cols >= 64) nr_cols= 64;
00440 
00441       im->fill (Qt::transparent);
00442       QPainter pp(im);
00443       QPen pen(painter->pen());
00444       QBrush brush(pen.color());
00445       pp.setPen(Qt::NoPen);
00446       for (j=0; j<h; j++)
00447         for (i=0; i<w; i++) {
00448           int col = gl->get_x (i, j);
00449           brush.setColor (QColor (r, g, b, (a*col)/nr_cols));
00450           pp.fillRect (i, j, 1, 1, brush);
00451         }
00452       pp.end();
00453     }
00454 #else
00455     QTMImage *im= new QImage (w, h, QImage::Format_ARGB32);
00456     //QTMImage *im= new QImage (w, h, QImage::Format_ARGB32_Premultiplied);
00457     {
00458       int nr_cols= sfactor*sfactor;
00459       if (nr_cols >= 64) nr_cols= 64;
00460 
00461       // the following line is disabled because
00462       // it causes a crash on Qt/X11 4.4.3
00463       //im->fill (Qt::transparent);
00464 
00465       for (j=0; j<h; j++)
00466         for (i=0; i<w; i++) {
00467           int col = gl->get_x (i, j);
00468           im->setPixel (i, j, qRgba (r, g, b, (a*col)/nr_cols));
00469         }
00470     }
00471 #endif
00472     qt_image mi2 (im, xo, yo, w, h);
00473     mi = mi2;
00474     //[im release]; // qt_image retains im
00475     character_image (xc)= mi;
00476     // FIXME: we must release the image at some point 
00477     //        (this should be ok now, see qt_image)
00478   }
00479 
00480   // draw the character
00481   //cout << (char)c << ": " << cx1/256 << ","  << cy1/256 << ","  
00482   //<< cx2/256 << ","  << cy2/256 << LF; 
00483   draw_clipped (mi->img, mi->w, mi->h, x- mi->xo*sfactor, y+ mi->yo*sfactor);
00484 }
00485 
00486 /******************************************************************************
00487 * Setting up and displaying xpm pixmaps
00488 ******************************************************************************/
00489 
00490 extern int char_clip;
00491 
00492 QPixmap*
00493 qt_renderer_rep::xpm_image (url file_name) {
00494   QPixmap *pxm= NULL;
00495   qt_pixmap mi= images [as_string (file_name)];
00496   if (is_nil (mi)) {
00497     string sss;
00498     if (suffix (file_name) == "xpm") {
00499       url png_equiv= glue (unglue (file_name, 3), "png");
00500       load_string ("$TEXMACS_PIXMAP_PATH" * png_equiv, sss, false);
00501     }
00502     if (sss == "")
00503       load_string ("$TEXMACS_PIXMAP_PATH" * file_name, sss, false);
00504     if (sss == "")
00505       load_string ("$TEXMACS_PATH/misc/pixmaps/TeXmacs.xpm", sss, true);
00506     uchar *buf= (uchar*) as_charp (sss);
00507     pxm= new QPixmap();
00508     pxm->loadFromData (buf, N(sss));
00509     tm_delete_array ((char*) buf);
00510     //out << sss;
00511     //cout << "pxm: " << file_name << "(" << pxm->size().width()
00512     //     << "," <<  pxm->size().height() << ")\n";
00513     qt_pixmap mi2 (pxm, 0, 0, pxm->width(), pxm->height());
00514     mi= mi2;
00515     images (as_string (file_name))= mi2;
00516   }
00517   else pxm=  mi->img ;
00518   return pxm;
00519 }
00520 
00521 void
00522 qt_renderer_rep::xpm (url file_name, SI x, SI y) {
00523   y -= pixel; // counter balance shift in draw_clipped
00524   QPixmap* image = xpm_image (file_name);
00525   ASSERT (sfactor == 1, "shrinking factor should be 1");
00526   int w, h;
00527   w = image->width ();
00528   h = image->height ();
00529   int old_clip= char_clip;
00530   char_clip= true;
00531   draw_clipped (image, w, h, x, y);
00532   char_clip=old_clip;
00533 }
00534 
00535 /******************************************************************************
00536  * main qt renderer
00537  ******************************************************************************/
00538 
00539 
00540 qt_renderer_rep*
00541 the_qt_renderer () {
00542   static QPainter *the_painter = NULL;
00543   static qt_renderer_rep* the_renderer= NULL;
00544   if (!the_renderer) {
00545     the_painter = new QPainter();
00546     the_renderer= tm_new<qt_renderer_rep> (the_painter);
00547   }
00548   return the_renderer;
00549 }
00550 
00551 
00552 /******************************************************************************
00553  * Shadow management methods 
00554  ******************************************************************************/
00555 
00556 /* Shadows are auxiliary renderers which allows double buffering and caching of
00557  * graphics. TeXmacs has explicit double buffering from the X11 port. Maybe
00558  * it would be better to design a better API abstracting from the low level 
00559  * details but for the moment the following code and the qt_proxy_renderer_rep
00560  * and qt_shadow_renderer_rep classes are designed to solve two problems:
00561  * 
00562  * 1) Qt has already double buffering.
00563  * 2) in Qt we are not easily allowed to read onscreen pixels (we can only ask a
00564  *    widget to redraw himself on a pixmap or read the screen pixels -- this has
00565  *    the drawback that if our widget is under another one we won't read the 
00566  *    right pixels)
00567  * 
00568  * qt_proxy_renderer_rep solve the double buffering problem: when texmacs ask
00569  * a qt_renderer_rep for a shadow it is given a proxy of the original renderer
00570  * texmacs uses this shadow for double buffering and the proxy will simply
00571  * forward the drawing operations to the original surface and neglect all the
00572  * syncronization operations
00573  *
00574  * to solve the second problem we do not draw directly on screen in QTMWidget.
00575  * Instead we maintain an internal pixmap which represent the state of the pixels
00576  * according to texmacs. when we are asked to initialize a qt_shadow_renderer_rep
00577  * we simply read the pixels form this backing store. At the Qt level then
00578  * (in QTMWidget) we make sure that the state of the backing store is in sync
00579  * with the screen via paintEvent/repaint mechanism.
00580  *
00581  */
00582 
00583 
00584 void
00585 qt_renderer_rep::new_shadow (renderer& ren) {
00586   SI mw, mh, sw, sh;
00587   get_extents (mw, mh);
00588   if (ren != NULL) {
00589     ren->get_extents (sw, sh);
00590     if (sw != mw || sh != mh) {
00591       delete_shadow (ren);
00592       ren= NULL;
00593     }
00594     // cout << "Old: " << sw << ", " << sh << "\n";
00595   }
00596   if (ren == NULL)  ren= (renderer) tm_new<qt_proxy_renderer_rep> (this);
00597   
00598   // cout << "Create " << mw << ", " << mh << "\n";
00599 }
00600 
00601 void 
00602 qt_renderer_rep::delete_shadow (renderer& ren)  {
00603   if (ren != NULL) {
00604     tm_delete (ren);
00605     ren= NULL;
00606   }
00607 }
00608 
00609 
00610 void 
00611 qt_renderer_rep::get_shadow (renderer ren, SI x1, SI y1, SI x2, SI y2) {
00612   // FIXME: we should use the routine fetch later
00613   ASSERT (ren != NULL, "invalid renderer");
00614   if (ren->is_printer ()) return;
00615   qt_renderer_rep* shadow= static_cast<qt_renderer_rep*>(ren);
00616   outer_round (x1, y1, x2, y2);
00617   x1= max (x1, cx1- ox);
00618   y1= max (y1, cy1- oy);
00619   x2= min (x2, cx2- ox);
00620   y2= min (y2, cy2- oy);
00621   shadow->ox= ox;
00622   shadow->oy= oy;
00623   shadow->master= this;
00624   shadow->cx1= x1+ ox;
00625   shadow->cy1= y1+ oy;
00626   shadow->cx2= x2+ ox;
00627   shadow->cy2= y2+ oy;
00628   
00629   decode (x1, y1);
00630   decode (x2, y2);
00631   if (x1<x2 && y2<y1) {
00632     QRect rect = QRect(x1, y2, x2-x1, y1-y2);
00633     //    shadow->painter->setCompositionMode(QPainter::CompositionMode_Source);  
00634     shadow->painter->setClipRect(rect);
00635 //    shadow->painter->drawPixmap (rect, px, rect);
00636     //    cout << "qt_shadow_renderer_rep::get_shadow " 
00637     //         << rectangle(x1,y2,x2,y1) << LF;
00638     //  XCopyArea (dpy, win, shadow->win, gc, x1, y2, x2-x1, y1-y2, x1, y2);
00639   } else {
00640     shadow->painter->setClipRect(QRect());
00641   }
00642 }
00643 
00644 void 
00645 qt_renderer_rep::put_shadow (renderer ren, SI x1, SI y1, SI x2, SI y2) {
00646   // FIXME: we should use the routine fetch later
00647   ASSERT (ren != NULL, "invalid renderer");
00648   if (ren->is_printer ()) return;
00649   if (painter == static_cast<qt_renderer_rep*>(ren)->painter) return;
00650   qt_shadow_renderer_rep* shadow= static_cast<qt_shadow_renderer_rep*>(ren);
00651   outer_round (x1, y1, x2, y2);
00652   x1= max (x1, cx1- ox);
00653   y1= max (y1, cy1- oy);
00654   x2= min (x2, cx2- ox);
00655   y2= min (y2, cy2- oy);
00656   decode (x1, y1);
00657   decode (x2, y2);
00658   if (x1<x2 && y2<y1) {
00659     QRect rect = QRect(x1, y2, x2-x1, y1-y2);
00660     //    cout << "qt_shadow_renderer_rep::put_shadow " 
00661     //         << rectangle(x1,y2,x2,y1) << LF;
00662     //    painter->setCompositionMode(QPainter::CompositionMode_Source);
00663     painter->drawPixmap (rect, shadow->px, rect);
00664     //  XCopyArea (dpy, shadow->win, win, gc, x1, y2, x2-x1, y1-y2, x1, y2);
00665   }
00666 }
00667 
00668 
00669 void 
00670 qt_renderer_rep::apply_shadow (SI x1, SI y1, SI x2, SI y2)  {
00671   if (master == NULL) return;
00672   if (painter == static_cast<qt_renderer_rep*>(master)->painter) return;
00673   outer_round (x1, y1, x2, y2);
00674   decode (x1, y1);
00675   decode (x2, y2);
00676   static_cast<qt_renderer_rep*>(master)->encode (x1, y1);
00677   static_cast<qt_renderer_rep*>(master)->encode (x2, y2);
00678   master->put_shadow (this, x1, y1, x2, y2);
00679 }
00680 
00681 
00682 /******************************************************************************
00683  * proxy qt renderer
00684  ******************************************************************************/
00685 
00686 void 
00687 qt_proxy_renderer_rep::new_shadow (renderer& ren) {
00688   SI mw, mh, sw, sh;
00689   get_extents (mw, mh);
00690   if (ren != NULL) {
00691     ren->get_extents (sw, sh);
00692     if (sw != mw || sh != mh) {
00693       delete_shadow (ren);
00694       ren= NULL;
00695     }
00696     else 
00697       static_cast<qt_shadow_renderer_rep*>(ren)->end();
00698     // cout << "Old: " << sw << ", " << sh << "\n";
00699   }
00700   if (ren == NULL)  
00701     ren= (renderer) tm_new<qt_shadow_renderer_rep> (QPixmap (mw, mh));
00702   
00703   // cout << "Create " << mw << ", " << mh << "\n";
00704   static_cast<qt_shadow_renderer_rep*>(ren)->begin(
00705           &(static_cast<qt_shadow_renderer_rep*>(ren)->px));
00706 }
00707 
00708 void 
00709 qt_proxy_renderer_rep::get_shadow (renderer ren, SI x1, SI y1, SI x2, SI y2) {
00710   // FIXME: we should use the routine fetch later
00711   ASSERT (ren != NULL, "invalid renderer");
00712   if (ren->is_printer ()) return;
00713   qt_renderer_rep* shadow= static_cast<qt_renderer_rep*>(ren);
00714   outer_round (x1, y1, x2, y2);
00715   x1= max (x1, cx1- ox);
00716   y1= max (y1, cy1- oy);
00717   x2= min (x2, cx2- ox);
00718   y2= min (y2, cy2- oy);
00719   shadow->ox= ox;
00720   shadow->oy= oy;
00721   shadow->cx1= x1+ ox;
00722   shadow->cy1= y1+ oy;
00723   shadow->cx2= x2+ ox;
00724   shadow->cy2= y2+ oy;
00725   shadow->master= this;
00726   decode (x1, y1);
00727   decode (x2, y2);
00728   if (x1<x2 && y2<y1) {
00729     QRect rect = QRect(x1, y2, x2-x1, y1-y2);
00730 
00731     shadow->painter->setClipRect(rect);
00732 
00733     //    shadow->painter->setCompositionMode(QPainter::CompositionMode_Source);
00734     QPixmap *_pixmap = static_cast<QPixmap*>(painter->device()); 
00735     if (_pixmap) {
00736       shadow->painter->drawPixmap (rect, *_pixmap, rect);
00737     }
00738     //    cout << "qt_shadow_renderer_rep::get_shadow " 
00739     //         << rectangle(x1,y2,x2,y1) << LF;
00740     //  XCopyArea (dpy, win, shadow->win, gc, x1, y2, x2-x1, y1-y2, x1, y2);
00741   } else {
00742     shadow->painter->setClipRect(QRect());
00743   }
00744 
00745 }
00746 
00747 
00748 /******************************************************************************
00749  * shadow qt renderer
00750  ******************************************************************************/
00751 
00752 qt_shadow_renderer_rep::qt_shadow_renderer_rep (QPixmap _px) 
00753 // : qt_renderer_rep (_px.width(),_px.height()), px(_px) 
00754 : qt_renderer_rep (new QPainter()), px(_px) 
00755 { 
00756   //cout << px.width() << "," << px.height() << " " << LF;
00757  // painter->begin(&px);
00758 }
00759 
00760 qt_shadow_renderer_rep::~qt_shadow_renderer_rep () 
00761 { 
00762   painter->end(); 
00763   delete painter;
00764   painter = NULL;
00765 }
00766 
00767 void 
00768 qt_shadow_renderer_rep::get_shadow (renderer ren, SI x1, SI y1, SI x2, SI y2) {
00769   // FIXME: we should use the routine fetch later
00770   ASSERT (ren != NULL, "invalid renderer");
00771   if (ren->is_printer ()) return;
00772   qt_shadow_renderer_rep* shadow= static_cast<qt_shadow_renderer_rep*>(ren);
00773   outer_round (x1, y1, x2, y2);
00774   x1= max (x1, cx1- ox);
00775   y1= max (y1, cy1- oy);
00776   x2= min (x2, cx2- ox);
00777   y2= min (y2, cy2- oy);
00778   shadow->ox= ox;
00779   shadow->oy= oy;
00780   shadow->cx1= x1+ ox;
00781   shadow->cy1= y1+ oy;
00782   shadow->cx2= x2+ ox;
00783   shadow->cy2= y2+ oy;
00784   shadow->master= this;
00785   decode (x1, y1);
00786   decode (x2, y2);
00787   if (x1<x2 && y2<y1) {
00788     QRect rect = QRect(x1, y2, x2-x1, y1-y2);
00789     shadow->painter->setClipRect(rect);
00790 
00791 //    shadow->painter->setCompositionMode(QPainter::CompositionMode_Source);   
00792     shadow->painter->drawPixmap (rect, px, rect);
00793 //    cout << "qt_shadow_renderer_rep::get_shadow " 
00794 //         << rectangle(x1,y2,x2,y1) << LF;
00795 //  XCopyArea (dpy, win, shadow->win, gc, x1, y2, x2-x1, y1-y2, x1, y2);
00796   } else {
00797     shadow->painter->setClipRect(QRect());
00798   }
00799 }
00800 
00801