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