CMake is too slow to make it the default build for us. This
[WebKit-https.git] / WebCore / platform / graphics / qt / GraphicsContextQt.cpp
1 /*
2  * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
3  * Copyright (C) 2006 Zack Rusin <zack@kde.org>
4  * Copyright (C) 2006 George Staikos <staikos@kde.org>
5  * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
6  * Copyright (C) 2006 Allan Sandfeld Jensen <sandfeld@kde.org>
7  * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
21  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
28  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "config.h"
34
35 #include "AffineTransform.h"
36 #include "Path.h"
37 #include "Color.h"
38 #include "GraphicsContext.h"
39 #include "Font.h"
40 #include "Pen.h"
41 #include "SVGResourceImage.h"
42
43 #include <QStack>
44 #include <QPainter>
45 #include <QPolygonF>
46 #include <QPainterPath>
47 #include <QPaintDevice>
48
49 #ifndef M_PI
50 #define M_PI 3.14159265358979323846
51 #endif
52
53 #define notImplemented() do { fprintf(stderr, "FIXME: UNIMPLEMENTED: %s:%d\n", __FILE__, __LINE__); } while(0)
54
55 namespace WebCore {
56
57 static inline QPainter::CompositionMode toQtCompositionMode(CompositeOperator op)
58 {
59     switch (op) {
60         case CompositeClear:
61             return QPainter::CompositionMode_Clear;
62         case CompositeCopy:
63             return QPainter::CompositionMode_Source;
64         case CompositeSourceOver:
65             return QPainter::CompositionMode_SourceOver;
66         case CompositeSourceIn:
67             return QPainter::CompositionMode_SourceIn;
68         case CompositeSourceOut:
69             return QPainter::CompositionMode_SourceOut;
70         case CompositeSourceAtop:
71             return QPainter::CompositionMode_SourceAtop;
72         case CompositeDestinationOver:
73             return QPainter::CompositionMode_DestinationOver;
74         case CompositeDestinationIn:
75             return QPainter::CompositionMode_DestinationIn;
76         case CompositeDestinationOut:
77             return QPainter::CompositionMode_DestinationOut;
78         case CompositeDestinationAtop:
79             return QPainter::CompositionMode_DestinationAtop;
80         case CompositeXOR:
81             return QPainter::CompositionMode_Xor;
82         case CompositePlusDarker:
83             return QPainter::CompositionMode_SourceOver;
84         case CompositeHighlight:
85             return QPainter::CompositionMode_SourceOver;
86         case CompositePlusLighter:
87             return QPainter::CompositionMode_SourceOver;
88     }
89
90     return QPainter::CompositionMode_SourceOver;
91 }
92
93 static inline Qt::PenCapStyle toQtLineCap(LineCap lc)
94 {
95     switch (lc) {
96         case ButtCap:
97             return Qt::FlatCap;
98         case RoundCap:
99             return Qt::RoundCap;
100         case SquareCap:
101             return Qt::SquareCap;
102     }
103
104     return Qt::FlatCap;
105 }
106
107 static inline Qt::PenJoinStyle toQtLineJoin(LineJoin lj)
108 {
109     switch (lj) {
110         case MiterJoin:
111             return Qt::SvgMiterJoin;
112         case RoundJoin:
113             return Qt::RoundJoin;
114         case BevelJoin:
115             return Qt::BevelJoin;
116     }
117
118     return Qt::MiterJoin;
119 }
120
121 static Qt::PenStyle toQPenStyle(Pen::PenStyle style)
122 {
123     switch (style) {
124     case Pen::NoPen:
125         return Qt::NoPen;
126         break;
127     case Pen::SolidLine:
128         return Qt::SolidLine;
129         break;
130     case Pen::DotLine:
131         return Qt::DotLine;
132         break;
133     case Pen::DashLine:
134         return Qt::DashLine;
135         break;
136     }
137     qWarning("couldn't recognize the pen style");
138     return Qt::NoPen;
139 }
140
141 static inline QPen penToQPen(const Pen& pen)
142 {
143     return QPen(QColor(pen.color()), pen.width(), toQPenStyle(pen.style()));
144 }
145
146 struct TransparencyLayer
147 {
148     TransparencyLayer(const QPainter& p, int width, int height)
149     {
150         pixmap = QPixmap(width, height);
151
152         painter = new QPainter(&pixmap);
153         painter->setPen(p.pen());
154         painter->setBrush(p.brush());
155         painter->setMatrix(p.matrix());
156         painter->setOpacity(p.opacity());
157         painter->setFont(p.font());
158         painter->setCompositionMode(p.compositionMode());
159         painter->setClipPath(p.clipPath());
160     }
161
162     TransparencyLayer()
163         : painter(0)
164     {
165     }
166
167     void cleanup()
168     {
169         delete painter;
170     }
171
172     QPixmap pixmap;
173     QPainter* painter;
174     qreal opacity;
175 };
176
177 struct TextShadow
178 {
179     TextShadow()
180         : x(0)
181         , y(0)
182         , blur(0)
183     {
184     }
185
186     bool isNull() { return !x && !y && !blur; }
187
188     int x;
189     int y;
190     int blur;
191
192     Color color;
193 };
194
195 class GraphicsContextPlatformPrivate
196 {
197 public:
198     GraphicsContextPlatformPrivate(QPainter* painter);
199     ~GraphicsContextPlatformPrivate();
200
201     QPainter& p()
202     {
203         if (layers.isEmpty()) {
204             if (redirect)
205                 return *redirect;
206
207             return *painter;
208         } else
209             return *layers.top().painter;
210     }
211
212     QPaintDevice* device;
213
214     QStack<TransparencyLayer> layers;
215     QPainter* redirect;
216
217     IntRect focusRingClip;
218     TextShadow shadow;
219
220     // Only used by SVG for now.
221     QPainterPath currentPath;
222
223 private:
224     QPainter* painter;
225 };
226
227
228 GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p)
229     : device(p->device())
230 {
231     painter = p;
232     redirect = 0;
233
234     // FIXME: Maybe only enable in SVG mode?
235     painter->setRenderHint(QPainter::Antialiasing);
236 }
237
238 GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
239 {
240 }
241
242 GraphicsContext::GraphicsContext(PlatformGraphicsContext* context)
243     : m_common(createGraphicsContextPrivate())
244     , m_data(new GraphicsContextPlatformPrivate(context))
245 {
246     setPaintingDisabled(!context);
247 }
248
249 GraphicsContext::~GraphicsContext()
250 {
251     while(!m_data->layers.isEmpty())
252         endTransparencyLayer();
253
254     destroyGraphicsContextPrivate(m_common);
255     delete m_data;
256 }
257
258 PlatformGraphicsContext* GraphicsContext::platformContext() const
259 {
260     return &m_data->p();
261 }
262
263 void GraphicsContext::savePlatformState()
264 {
265     m_data->p().save();
266 }
267
268 void GraphicsContext::restorePlatformState()
269 {
270     m_data->p().restore();
271 }
272
273 /* FIXME: DISABLED WHILE MERGING BACK FROM UNITY
274 void GraphicsContext::drawTextShadow(const TextRun& run, const IntPoint& point, const TextStyle& style)
275 {
276     if (paintingDisabled())
277         return;
278
279     if (m_data->shadow.isNull())
280         return;
281
282     TextShadow* shadow = &m_data->shadow;
283
284     if (shadow->blur <= 0) {
285         Pen p = pen();
286         setPen(shadow->color);
287         font().drawText(this, run, style, IntPoint(point.x() + shadow->x, point.y() + shadow->y));
288         setPen(p);
289     } else {
290         const int thickness = shadow->blur;
291         // FIXME: OPTIMIZE: limit the area to only the actually painted area + 2*thickness
292         const int w = m_data->p().device()->width();
293         const int h = m_data->p().device()->height();
294         const QRgb color = qRgb(255, 255, 255);
295         const QRgb bgColor = qRgb(0, 0, 0);
296         QImage image(QSize(w, h), QImage::Format_ARGB32);
297         image.fill(bgColor);
298         QPainter p;
299
300         Pen curPen = pen();
301         p.begin(&image);
302         setPen(color);
303         m_data->redirect = &p;
304         font().drawText(this, run, style, IntPoint(point.x() + shadow->x, point.y() + shadow->y));
305         m_data->redirect = 0;
306         p.end();
307         setPen(curPen);
308
309         int md = thickness * thickness; // max-dist^2
310
311         // blur map/precalculated shadow-decay
312         float* bmap = (float*) alloca(sizeof(float) * (md + 1));
313         for (int n = 0; n <= md; n++) {
314             float f;
315             f = n / (float) (md + 1);
316             f = 1.0 - f * f;
317             bmap[n] = f;
318         }
319
320         float factor = 0.0; // maximal potential opacity-sum
321         for (int n = -thickness; n <= thickness; n++) {
322             for (int m = -thickness; m <= thickness; m++) {
323                 int d = n * n + m * m;
324                 if (d <= md)
325                     factor += bmap[d];
326             }
327         }
328
329         // alpha map
330         float* amap = (float*) alloca(sizeof(float) * (h * w));
331         memset(amap, 0, h * w * (sizeof(float)));
332
333         for (int j = thickness; j<h-thickness; j++) {
334             for (int i = thickness; i<w-thickness; i++) {
335                 QRgb col = image.pixel(i,j);
336                 if (col == bgColor)
337                     continue;
338
339                 float g = qAlpha(col);
340                 g = g / 255;
341
342                 for (int n = -thickness; n <= thickness; n++) {
343                     for (int m = -thickness; m <= thickness; m++) {
344                         int d = n * n + m * m;
345                         if (d > md)
346                             continue;
347
348                         float f = bmap[d];
349                         amap[(i + m) + (j + n) * w] += (g * f);
350                     }
351                 }
352             }
353         }
354
355         QImage res(QSize(w,h),QImage::Format_ARGB32);
356         int r = shadow->color.red();
357         int g = shadow->color.green();
358         int b = shadow->color.blue();
359         int a1 = shadow->color.alpha();
360
361         // arbitratry factor adjustment to make shadows more solid.
362         factor = 1.333 / factor;
363
364         for (int j = 0; j < h; j++) {
365             for (int i = 0; i < w; i++) {
366                 int a = (int) (amap[i + j * w] * factor * a1);
367                 if (a > 255)
368                     a = 255;
369
370                 res.setPixel(i,j, qRgba(r, g, b, a));
371             }
372         }
373
374         m_data->p().drawImage(0, 0, res, 0, 0, -1, -1, Qt::DiffuseAlphaDither | Qt::ColorOnly | Qt::PreferDither);
375     }
376 }
377 */
378
379 // Draws a filled rectangle with a stroked border.
380 void GraphicsContext::drawRect(const IntRect& rect)
381 {
382     if (paintingDisabled())
383         return;
384
385     m_data->p().drawRect(rect);
386 }
387
388 // FIXME: Now that this is refactored, it should be shared by all contexts.
389 static void adjustLineToPixelBounderies(FloatPoint& p1, FloatPoint& p2, float strokeWidth,
390                                         const Pen::PenStyle& penStyle)
391 {
392     // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic
393     // works out.  For example, with a border width of 3, KHTML will pass us (y1+y2)/2, e.g.,
394     // (50+53)/2 = 103/2 = 51 when we want 51.5.  It is always true that an even width gave
395     // us a perfect position, but an odd width gave us a position that is off by exactly 0.5.
396     if (penStyle == Pen::DotLine || penStyle == Pen::DashLine) {
397         if (p1.x() == p2.x()) {
398             p1.setY(p1.y() + strokeWidth);
399             p2.setY(p2.y() - strokeWidth);
400         } else {
401             p1.setX(p1.x() + strokeWidth);
402             p2.setX(p2.x() - strokeWidth);
403         }
404     }
405
406     if (((int) strokeWidth) % 2) {
407         if (p1.x() == p2.x()) {
408             // We're a vertical line.  Adjust our x.
409             p1.setX(p1.x() + 0.5);
410             p2.setX(p2.x() + 0.5);
411         } else {
412             // We're a horizontal line. Adjust our y.
413             p1.setY(p1.y() + 0.5);
414             p2.setY(p2.y() + 0.5);
415         }
416     }
417 }
418
419 // This is only used to draw borders.
420 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
421 {
422     if (paintingDisabled())
423         return;
424
425     FloatPoint p1 = point1;
426     FloatPoint p2 = point2;
427
428     adjustLineToPixelBounderies(p1, p2, pen().width(), pen().style());
429     m_data->p().drawLine(p1, p2);
430 }
431
432 // This method is only used to draw the little circles used in lists.
433 void GraphicsContext::drawEllipse(const IntRect& rect)
434 {
435     if (paintingDisabled())
436         return;
437
438     m_data->p().drawEllipse(rect);
439 }
440
441 void GraphicsContext::drawArc(const IntRect& rect, float thickness,
442                               int startAngle, int angleSpan)
443 {
444     if (paintingDisabled())
445         return;
446
447     const QPen oldPen = m_data->p().pen();
448     QPen nPen = oldPen;
449     nPen.setWidthF(thickness);
450     m_data->p().setPen(nPen);
451     m_data->p().drawArc(rect, startAngle, angleSpan);
452     m_data->p().setPen(oldPen);
453 }
454
455 void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
456 {
457     if (paintingDisabled())
458         return;
459
460     if (npoints <= 1)
461         return;
462
463     QPolygonF polygon(npoints);
464
465     for (size_t i = 0; i < npoints; i++)
466         polygon[i] = points[i];
467
468     m_data->p().save();
469     m_data->p().setRenderHint(QPainter::Antialiasing, shouldAntialias);
470     m_data->p().drawConvexPolygon(polygon);
471     m_data->p().restore();
472 }
473
474 void GraphicsContext::fillRect(const IntRect& rect, const Color& c)
475 {
476     if (paintingDisabled())
477         return;
478
479     m_data->p().fillRect(rect, QColor(c));
480 }
481
482 void GraphicsContext::fillRect(const FloatRect& rect, const Color& c)
483 {
484     if (paintingDisabled())
485         return;
486
487     m_data->p().fillRect(rect, QColor(c));
488 }
489
490 void GraphicsContext::beginPath()
491 {
492     m_data->currentPath = QPainterPath();
493 }
494
495 void GraphicsContext::addPath(const Path& path)
496 {
497     m_data->currentPath = *(path.platformPath());
498 }
499
500 void GraphicsContext::setFillRule(WindRule rule)
501 {
502     m_data->currentPath.setFillRule(rule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill);
503 }
504
505 PlatformPath* GraphicsContext::currentPath()
506 {
507     return &m_data->currentPath;
508 }
509
510 void GraphicsContext::clip(const IntRect& rect)
511 {
512     if (paintingDisabled())
513         return;
514
515     QPainterPath path;
516     path.addRect(QRectF(rect));
517     m_data->p().setClipPath(path, Qt::UniteClip);
518 }
519
520 void GraphicsContext::drawFocusRing(const Color& color)
521 {
522     if (paintingDisabled())
523         return;
524
525     notImplemented();
526 }
527
528 void GraphicsContext::setFocusRingClip(const IntRect& rect)
529 {
530     if (paintingDisabled())
531         return;
532
533     m_data->focusRingClip = rect;
534 }
535
536 void GraphicsContext::clearFocusRingClip()
537 {
538     if (paintingDisabled())
539         return;
540
541     m_data->focusRingClip = IntRect();
542 }
543
544 void GraphicsContext::drawLineForText(const IntPoint& point, int yOffset,
545                                       int width, bool printing)
546 {
547     if (paintingDisabled())
548         return;
549
550     IntPoint origin = point + IntSize(0, yOffset + 1);
551     IntPoint endPoint = origin + IntSize(width, 0);
552     drawLine(origin, endPoint);
553 }
554
555 void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&,
556                                                          int width, bool grammar)
557 {
558     if (paintingDisabled())
559         return;
560
561     notImplemented();
562 }
563
564 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
565 {
566     QRectF rect(frect);
567     rect = m_data->p().deviceMatrix().mapRect(rect);
568
569     QRect result = rect.toRect(); //round it
570     return FloatRect(QRectF(result));
571 }
572
573 void GraphicsContext::setShadow(const IntSize& pos, int blur, const Color &color)
574 {
575     if (paintingDisabled())
576         return;
577
578     m_data->shadow.x = pos.width();
579     m_data->shadow.y = pos.height();
580     m_data->shadow.blur = blur;
581     m_data->shadow.color = color;
582 }
583
584 void GraphicsContext::clearShadow()
585 {
586     if (paintingDisabled())
587         return;
588
589     m_data->shadow = TextShadow();
590 }
591
592 void GraphicsContext::beginTransparencyLayer(float opacity)
593 {
594     if (paintingDisabled())
595         return;
596
597     TransparencyLayer layer(m_data->p(),
598                             m_data->device->width(),
599                             m_data->device->height());
600
601     layer.opacity = opacity;
602     m_data->layers.push(layer);
603 }
604
605 void GraphicsContext::endTransparencyLayer()
606 {
607     if (paintingDisabled())
608         return;
609
610     TransparencyLayer layer = m_data->layers.pop();
611     layer.painter->end();
612
613     m_data->p().save();
614     m_data->p().setOpacity(layer.opacity);
615     m_data->p().drawPixmap(0, 0, layer.pixmap);
616     m_data->p().restore();
617     m_data->p().end();
618
619     layer.cleanup();
620 }
621
622 void GraphicsContext::clearRect(const FloatRect& rect)
623 {
624     if (paintingDisabled())
625         return;
626
627     m_data->p().eraseRect(rect);
628 }
629
630 void GraphicsContext::strokeRect(const FloatRect& rect, float width)
631 {
632     if (paintingDisabled())
633         return;
634
635     QPainterPath path;
636     path.addRect(rect);
637     QPen nPen = m_data->p().pen();
638     nPen.setWidthF(width);
639     m_data->p().strokePath(path, nPen);
640 }
641
642 void GraphicsContext::setLineWidth(float width)
643 {
644     if (paintingDisabled())
645         return;
646
647     QPen nPen = m_data->p().pen();
648     nPen.setWidthF(width);
649     m_data->p().setPen(nPen);
650 }
651
652 void GraphicsContext::setLineCap(LineCap lc)
653 {
654     if (paintingDisabled())
655         return;
656
657     QPen nPen = m_data->p().pen();
658     nPen.setCapStyle(toQtLineCap(lc));
659     m_data->p().setPen(nPen);
660 }
661
662 void GraphicsContext::setLineJoin(LineJoin lj)
663 {
664     if (paintingDisabled())
665         return;
666
667     QPen nPen = m_data->p().pen();
668     nPen.setJoinStyle(toQtLineJoin(lj));
669     m_data->p().setPen(nPen);
670 }
671
672 void GraphicsContext::setMiterLimit(float limit)
673 {
674     if (paintingDisabled())
675         return;
676
677     QPen nPen = m_data->p().pen();
678     nPen.setMiterLimit(limit);
679     m_data->p().setPen(nPen);
680 }
681
682 void GraphicsContext::setAlpha(float opacity)
683 {
684     if (paintingDisabled())
685         return;
686
687     m_data->p().setOpacity(opacity);
688 }
689
690 void GraphicsContext::setCompositeOperation(CompositeOperator op)
691 {
692     if (paintingDisabled())
693         return;
694
695     m_data->p().setCompositionMode(toQtCompositionMode(op));
696 }
697
698 void GraphicsContext::clip(const Path& path)
699 {
700     if (paintingDisabled())
701         return;
702
703     m_data->p().setClipPath(*path.platformPath());
704 }
705
706 void GraphicsContext::translate(float x, float y)
707 {
708     if (paintingDisabled())
709         return;
710
711     m_data->p().translate(x, y);
712 }
713
714 IntPoint GraphicsContext::origin()
715 {
716     return IntPoint(qRound(m_data->p().matrix().dx()),
717                     qRound(m_data->p().matrix().dy()));
718 }
719
720 void GraphicsContext::rotate(float radians)
721 {
722     if (paintingDisabled())
723         return;
724
725     m_data->p().rotate(radians);
726 }
727
728 void GraphicsContext::scale(const FloatSize& s)
729 {
730     if (paintingDisabled())
731         return;
732
733     m_data->p().scale(s.width(), s.height());
734 }
735
736 void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect,
737                                               int thickness)
738 {
739     if (paintingDisabled())
740         return;
741
742     clip(rect);
743     QPainterPath path;
744
745     // Add outer ellipse
746     path.addEllipse(QRectF(rect.x(), rect.y(), rect.width(), rect.height()));
747
748     // Add inner ellipse.
749     path.addEllipse(QRectF(rect.x() + thickness, rect.y() + thickness,
750                            rect.width() - (thickness * 2), rect.height() - (thickness * 2)));
751
752     path.setFillRule(Qt::OddEvenFill);
753     m_data->p().setClipPath(path, Qt::IntersectClip);
754 }
755
756 void GraphicsContext::addRoundedRectClip(const IntRect& rect, const IntSize& topLeft,
757                                          const IntSize& topRight, const IntSize& bottomLeft,
758                                          const IntSize& bottomRight)
759 {
760     if (paintingDisabled())
761         return;
762
763     // Need sufficient width and height to contain these curves.  Sanity check our top/bottom
764     // values and our width/height values to make sure the curves can all fit.
765     int requiredWidth = qMax(topLeft.width() + topRight.width(), bottomLeft.width() + bottomRight.width());
766     if (requiredWidth > rect.width())
767         return;
768
769     int requiredHeight = qMax(topLeft.height() + bottomLeft.height(), topRight.height() + bottomRight.height());
770     if (requiredHeight > rect.height())
771         return;
772
773     // Clip to our rect.
774     clip(rect);
775
776     // OK, the curves can fit.
777     QPainterPath path;
778
779     // Add the four ellipses to the path.  Technically this really isn't good enough, since we could end up
780     // not clipping the other 3/4 of the ellipse we don't care about.  We're relying on the fact that for
781     // normal use cases these ellipses won't overlap one another (or when they do the curvature of one will
782     // be subsumed by the other).
783     path.addEllipse(QRectF(rect.x(), rect.y(), topLeft.width() * 2, topLeft.height() * 2));
784     path.addEllipse(QRectF(rect.right() - topRight.width() * 2, rect.y(),
785                            topRight.width() * 2, topRight.height() * 2));
786     path.addEllipse(QRectF(rect.x(), rect.bottom() - bottomLeft.height() * 2,
787                            bottomLeft.width() * 2, bottomLeft.height() * 2));
788     path.addEllipse(QRectF(rect.right() - bottomRight.width() * 2,
789                            rect.bottom() - bottomRight.height() * 2,
790                            bottomRight.width() * 2, bottomRight.height() * 2));
791
792     int topLeftRightHeightMax = qMax(topLeft.height(), topRight.height());
793     int bottomLeftRightHeightMax = qMax(bottomLeft.height(), bottomRight.height());
794
795     int topBottomLeftWidthMax = qMax(topLeft.width(), bottomLeft.width());
796     int topBottomRightWidthMax = qMax(topRight.width(), bottomRight.width());
797
798     // Now add five rects (one for each edge rect in between the rounded corners and one for the interior).
799     path.addRect(QRectF(rect.x() + topLeft.width(),
800                         rect.y(),
801                         rect.width() - topLeft.width() - topRight.width(),
802                         topLeftRightHeightMax));
803
804     path.addRect(QRectF(rect.x() + bottomLeft.width(), rect.bottom() - bottomLeftRightHeightMax,
805                         rect.width() - bottomLeft.width() - bottomRight.width(), bottomLeftRightHeightMax));
806
807     path.addRect(QRectF(rect.x(),
808                         rect.y() + topLeft.height(),
809                         topBottomLeftWidthMax,
810                         rect.height() - topLeft.height() - bottomLeft.height()));
811
812     path.addRect(QRectF(rect.right() - topBottomRightWidthMax,
813                         rect.y() + topRight.height(),
814                         topBottomRightWidthMax,
815                         rect.height() - topRight.height() - bottomRight.height()));
816
817     path.addRect(QRectF(rect.x() + topBottomLeftWidthMax,
818                         rect.y() + topLeftRightHeightMax,
819                         rect.width() - topBottomLeftWidthMax - topBottomRightWidthMax,
820                         rect.height() - topLeftRightHeightMax - bottomLeftRightHeightMax));
821
822     path.setFillRule(Qt::WindingFill);
823     m_data->p().setClipPath(path, Qt::IntersectClip);
824 }
825
826 void GraphicsContext::concatCTM(const AffineTransform& transform)
827 {
828     if (paintingDisabled())
829         return;
830
831     m_data->p().setMatrix(transform, true);
832 }
833
834 void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
835 {
836     notImplemented();
837 }
838
839 void GraphicsContext::setPlatformFont(const Font& aFont)
840 {
841     m_data->p().setFont(aFont);
842 }
843
844 void GraphicsContext::setPlatformPen(const Pen& pen)
845 {
846     m_data->p().setPen(penToQPen(pen));
847 }
848
849 void GraphicsContext::setPlatformFillColor(const Color& color)
850 {
851     m_data->p().setBrush(QBrush(color));
852 }
853
854 #ifdef SVG_SUPPORT
855 GraphicsContext* contextForImage(SVGResourceImage*)
856 {
857     // FIXME!
858     return 0;
859 }
860 #endif
861
862 }
863 // vim: ts=4 sw=4 et