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