314e09cc9ac1b693331ec94d4ba8fed200a765a9
[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             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(StrokeStyle style)
121 {
122     switch (style) {
123     case NoStroke:
124         return Qt::NoPen;
125         break;
126     case SolidStroke:
127         return Qt::SolidLine;
128         break;
129     case DottedStroke:
130         return Qt::DotLine;
131         break;
132     case DashedStroke:
133         return Qt::DashLine;
134         break;
135     }
136     qWarning("couldn't recognize the pen style");
137     return Qt::NoPen;
138 }
139
140 struct TransparencyLayer
141 {
142     TransparencyLayer(const QPainter* p, const QRect &rect)
143         : pixmap(rect.width(), rect.height())
144     {
145         offset = rect.topLeft();
146         pixmap.fill(Qt::transparent);
147         painter.begin(&pixmap);
148         painter.translate(-offset);
149         painter.setPen(p->pen());
150         painter.setBrush(p->brush());
151         painter.setTransform(p->transform(), true);
152         painter.setOpacity(p->opacity());
153         painter.setFont(p->font());
154         painter.setCompositionMode(p->compositionMode());
155         painter.setClipPath(p->clipPath());
156     }
157
158     TransparencyLayer()
159     {
160     }
161
162     QPixmap pixmap;
163     QPoint offset;
164     QPainter painter;
165     qreal opacity;
166 private:
167     TransparencyLayer(const TransparencyLayer &) {}
168     TransparencyLayer & operator=(const TransparencyLayer &) { return *this; }
169 };
170
171 struct TextShadow
172 {
173     TextShadow()
174         : x(0)
175         , y(0)
176         , blur(0)
177     {
178     }
179
180     bool isNull() { return !x && !y && !blur; }
181
182     int x;
183     int y;
184     int blur;
185
186     Color color;
187 };
188
189 class GraphicsContextPlatformPrivate
190 {
191 public:
192     GraphicsContextPlatformPrivate(QPainter* painter);
193     ~GraphicsContextPlatformPrivate();
194
195     inline QPainter* p()
196     {
197         if (layers.isEmpty()) {
198             if (redirect)
199                 return redirect;
200
201             return painter;
202         } else
203             return &layers.top()->painter;
204     }
205
206     QPaintDevice* device;
207
208     QStack<TransparencyLayer *> layers;
209     QPainter* redirect;
210
211     TextShadow shadow;
212
213     // Only used by SVG for now.
214     QPainterPath currentPath;
215
216 private:
217     QPainter* painter;
218 };
219
220
221 GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p)
222 {
223     painter = p;
224     device = painter ? painter->device() : 0;
225     redirect = 0;
226
227     // FIXME: Maybe only enable in SVG mode?
228     if (painter)
229         painter->setRenderHint(QPainter::Antialiasing);
230 }
231
232 GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
233 {
234 }
235
236 GraphicsContext::GraphicsContext(PlatformGraphicsContext* context)
237     : m_common(createGraphicsContextPrivate())
238     , m_data(new GraphicsContextPlatformPrivate(context))
239 {
240     setPaintingDisabled(!context);
241     if (context) {
242         // Make sure the context starts in sync with our state.
243         setPlatformFillColor(fillColor());
244         setPlatformStrokeColor(strokeColor());
245     }
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 FontStyle& 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 adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth,
389                                         const StrokeStyle& 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 == DottedStroke || penStyle == DashedStroke) {
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     adjustLineToPixelBoundaries(p1, p2, strokeThickness(), strokeStyle());
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::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
441 {
442     if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f || !strokeColor().alpha())
443         return;
444
445     m_data->p()->drawArc(rect, startAngle * 16, angleSpan * 16);
446 }
447
448 void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
449 {
450     if (paintingDisabled())
451         return;
452
453     if (npoints <= 1)
454         return;
455
456     QPolygonF polygon(npoints);
457
458     for (size_t i = 0; i < npoints; i++)
459         polygon[i] = points[i];
460
461     QPainter *p = m_data->p();
462     p->save();
463     p->setRenderHint(QPainter::Antialiasing, shouldAntialias);
464     p->drawConvexPolygon(polygon);
465     p->restore();
466 }
467
468 void GraphicsContext::fillRect(const IntRect& rect, const Color& c)
469 {
470     if (paintingDisabled())
471         return;
472
473     m_data->p()->fillRect(rect, QColor(c));
474 }
475
476 void GraphicsContext::fillRect(const FloatRect& rect, const Color& c)
477 {
478     if (paintingDisabled())
479         return;
480
481     m_data->p()->fillRect(rect, QColor(c));
482 }
483
484 void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color)
485 {
486     if (paintingDisabled() || !color.alpha())
487         return;
488
489     Path path = Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight);
490     m_data->p()->fillPath(*path.platformPath(), QColor(color));
491 }
492
493 void GraphicsContext::beginPath()
494 {
495     m_data->currentPath = QPainterPath();
496 }
497
498 void GraphicsContext::addPath(const Path& path)
499 {
500     m_data->currentPath = *(path.platformPath());
501 }
502
503 void GraphicsContext::setFillRule(WindRule rule)
504 {
505     m_data->currentPath.setFillRule(rule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill);
506 }
507
508 PlatformPath* GraphicsContext::currentPath()
509 {
510     return &m_data->currentPath;
511 }
512
513 void GraphicsContext::clip(const IntRect& rect)
514 {
515     if (paintingDisabled())
516         return;
517
518     QPainter *p = m_data->p();
519     if (p->clipRegion().isEmpty())
520         p->setClipRect(rect);
521     else p->setClipRect(rect, Qt::IntersectClip);
522 }
523
524 /**
525  * Focus ring handling is not handled here. Qt style in 
526  * RenderTheme handles drawing focus on widgets which 
527  * need it.
528  */
529 void setFocusRingColorChangeFunction(void (*)()) { }
530 Color focusRingColor() { return Color(0, 0, 0); }
531 void GraphicsContext::drawFocusRing(const Color& color)
532 {
533     if (paintingDisabled())
534         return;
535
536     const Vector<IntRect>& rects = focusRingRects();
537     unsigned rectCount = rects.size();
538
539     if (rects.size() > 1)
540     {
541         QPainterPath path;
542         for (int i = 0; i < rectCount; ++i)
543             path.addRect(QRectF(rects[i]));
544         QPainter *p = m_data->p();
545         p->save();
546         QPen nPen = p->pen();
547         nPen.setColor(color);
548         p->setBrush(Qt::NoBrush);
549         nPen.setStyle(Qt::DotLine);
550         p->setPen(nPen);
551 #if 0
552         // FIXME How do we do a bounding outline with Qt?
553         QPainterPathStroker stroker;
554         QPainterPath newPath = stroker.createStroke(path);
555         p->strokePath(newPath, nPen);
556 #else
557         p->drawRect(path.boundingRect());
558 #endif
559         p->restore();
560     }
561 }
562
563 void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
564 {
565     if (paintingDisabled())
566         return;
567
568     IntPoint endPoint = origin + IntSize(width, 0);
569     drawLine(origin, endPoint);
570 }
571
572 void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&,
573                                                          int width, bool grammar)
574 {
575     if (paintingDisabled())
576         return;
577
578     notImplemented();
579 }
580
581 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
582 {
583     QRectF rect(frect);
584     rect = m_data->p()->deviceMatrix().mapRect(rect);
585
586     QRect result = rect.toRect(); //round it
587     return FloatRect(QRectF(result));
588 }
589
590 void GraphicsContext::setShadow(const IntSize& pos, int blur, const Color &color)
591 {
592     if (paintingDisabled())
593         return;
594
595     m_data->shadow.x = pos.width();
596     m_data->shadow.y = pos.height();
597     m_data->shadow.blur = blur;
598     m_data->shadow.color = color;
599 }
600
601 void GraphicsContext::clearShadow()
602 {
603     if (paintingDisabled())
604         return;
605
606     m_data->shadow = TextShadow();
607 }
608
609 void GraphicsContext::beginTransparencyLayer(float opacity)
610 {
611     if (paintingDisabled())
612         return;
613
614     int x, y, w, h;
615     x = y = 0;
616     w = m_data->device->width();
617     h = m_data->device->height();
618
619     QPainter *p = m_data->p();
620     QRectF clip = p->clipPath().boundingRect();
621     bool ok;
622     QTransform transform = p->transform().inverted(&ok);
623     if (ok) {
624         QRectF deviceClip = transform.mapRect(clip);
625         x = int(qBound(qreal(0), deviceClip.x(), (qreal)w));
626         y = int(qBound(qreal(0), deviceClip.y(), (qreal)h));
627         w = int(qBound(qreal(0), deviceClip.width(), (qreal)w) + 2);
628         h = int(qBound(qreal(0), deviceClip.height(), (qreal)h) + 2);
629     }
630     TransparencyLayer * layer = new TransparencyLayer(m_data->p(), QRect(x, y, w, h));
631
632     layer->opacity = opacity;
633     m_data->layers.push(layer);
634 }
635
636 void GraphicsContext::endTransparencyLayer()
637 {
638     if (paintingDisabled())
639         return;
640
641     TransparencyLayer *layer = m_data->layers.pop();
642     layer->painter.end();
643
644     QPainter *p = m_data->p();
645     p->save();
646     p->resetTransform();
647     p->setOpacity(layer->opacity);
648     p->drawPixmap(layer->offset, layer->pixmap);
649     p->restore();
650
651     delete layer;
652 }
653
654 void GraphicsContext::clearRect(const FloatRect& rect)
655 {
656     if (paintingDisabled())
657         return;
658
659     QPainter *p = m_data->p();
660     QPainter::CompositionMode currentCompositionMode = p->compositionMode();
661     p->setCompositionMode(QPainter::CompositionMode_Source);
662     p->eraseRect(rect);
663     p->setCompositionMode(currentCompositionMode);
664 }
665
666 void GraphicsContext::strokeRect(const FloatRect& rect, float width)
667 {
668     if (paintingDisabled())
669         return;
670
671     QPainter *p = m_data->p();
672     QPainterPath path;
673     path.addRect(rect);
674     QPen nPen = p->pen();
675     nPen.setWidthF(width);
676     p->strokePath(path, nPen);
677 }
678
679 void GraphicsContext::setLineCap(LineCap lc)
680 {
681     if (paintingDisabled())
682         return;
683
684     QPainter *p = m_data->p();
685     QPen nPen = p->pen();
686     nPen.setCapStyle(toQtLineCap(lc));
687     p->setPen(nPen);
688 }
689
690 void GraphicsContext::setLineJoin(LineJoin lj)
691 {
692     if (paintingDisabled())
693         return;
694
695     QPainter *p = m_data->p();
696     QPen nPen = p->pen();
697     nPen.setJoinStyle(toQtLineJoin(lj));
698     p->setPen(nPen);
699 }
700
701 void GraphicsContext::setMiterLimit(float limit)
702 {
703     if (paintingDisabled())
704         return;
705
706     QPainter *p = m_data->p();
707     QPen nPen = p->pen();
708     nPen.setMiterLimit(limit);
709     p->setPen(nPen);
710 }
711
712 void GraphicsContext::setAlpha(float opacity)
713 {
714     if (paintingDisabled())
715         return;
716     QPainter *p = m_data->p();
717     p->setOpacity(opacity);
718 }
719
720 void GraphicsContext::setCompositeOperation(CompositeOperator op)
721 {
722     if (paintingDisabled())
723         return;
724
725     m_data->p()->setCompositionMode(toQtCompositionMode(op));
726 }
727
728 void GraphicsContext::clip(const Path& path)
729 {
730     if (paintingDisabled())
731         return;
732
733     m_data->p()->setClipPath(*path.platformPath(), Qt::IntersectClip);
734 }
735
736 void GraphicsContext::clipOut(const Path& path)
737 {
738     if (paintingDisabled())
739         return;
740
741     QPainter *p = m_data->p();
742     QRectF clipBounds = p->clipPath().boundingRect();
743     QPainterPath clippedOut = *path.platformPath();
744     QPainterPath newClip;
745     newClip.setFillRule(Qt::OddEvenFill);
746     newClip.addRect(clipBounds);
747     newClip.addPath(clippedOut);
748
749     p->setClipPath(newClip, Qt::IntersectClip);
750 }
751
752 void GraphicsContext::translate(float x, float y)
753 {
754     if (paintingDisabled())
755         return;
756
757     m_data->p()->translate(x, y);
758 }
759
760 IntPoint GraphicsContext::origin()
761 {
762     if (paintingDisabled())
763         return IntPoint();
764     const QTransform &transform = m_data->p()->transform();
765     return IntPoint(qRound(transform.dx()), qRound(transform.dy()));
766 }
767
768 void GraphicsContext::rotate(float radians)
769 {
770     if (paintingDisabled())
771         return;
772
773     m_data->p()->rotate(radians);
774 }
775
776 void GraphicsContext::scale(const FloatSize& s)
777 {
778     if (paintingDisabled())
779         return;
780
781     m_data->p()->scale(s.width(), s.height());
782 }
783
784 void GraphicsContext::clipOut(const IntRect& rect)
785 {
786     if (paintingDisabled())
787         return;
788         
789     QPainter *p = m_data->p();
790     QRectF clipBounds = p->clipPath().boundingRect();
791     QPainterPath newClip;
792     newClip.setFillRule(Qt::OddEvenFill);
793     newClip.addRect(clipBounds);
794     newClip.addRect(QRect(rect));
795
796     p->setClipPath(newClip, Qt::IntersectClip);
797 }
798
799 void GraphicsContext::clipOutEllipseInRect(const IntRect& rect)
800 {
801     if (paintingDisabled())
802         return;
803     
804     QPainter *p = m_data->p();
805     QRectF clipBounds = p->clipPath().boundingRect();
806     QPainterPath newClip;
807     newClip.setFillRule(Qt::OddEvenFill);
808     newClip.addRect(clipBounds);
809     newClip.addEllipse(QRect(rect));
810
811     p->setClipPath(newClip, Qt::IntersectClip);
812 }
813
814 void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect,
815                                               int thickness)
816 {
817     if (paintingDisabled())
818         return;
819
820     clip(rect);
821     QPainterPath path;
822
823     // Add outer ellipse
824     path.addEllipse(QRectF(rect.x(), rect.y(), rect.width(), rect.height()));
825
826     // Add inner ellipse.
827     path.addEllipse(QRectF(rect.x() + thickness, rect.y() + thickness,
828                            rect.width() - (thickness * 2), rect.height() - (thickness * 2)));
829
830     path.setFillRule(Qt::OddEvenFill);
831     m_data->p()->setClipPath(path, Qt::IntersectClip);
832 }
833
834 void GraphicsContext::concatCTM(const AffineTransform& transform)
835 {
836     if (paintingDisabled())
837         return;
838
839     m_data->p()->setMatrix(transform, true);
840 }
841
842 void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
843 {
844     notImplemented();
845 }
846
847 void GraphicsContext::setPlatformFont(const Font& aFont)
848 {
849     if (paintingDisabled())
850         return;
851     m_data->p()->setFont(aFont.font());
852 }
853
854 void GraphicsContext::setPlatformStrokeColor(const Color& color)
855 {
856     if (paintingDisabled())
857         return;
858     QPainter *p = m_data->p();
859     QPen newPen(p->pen());
860     newPen.setColor(color);
861     p->setPen(newPen);
862 }
863
864 void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& strokeStyle)
865 {   
866     if (paintingDisabled())
867         return;
868     QPainter *p = m_data->p();
869     QPen newPen(p->pen());
870     newPen.setStyle(toQPenStyle(strokeStyle));
871     p->setPen(newPen);
872 }
873
874 void GraphicsContext::setPlatformStrokeThickness(float thickness)
875 {
876     if (paintingDisabled())
877         return;
878     QPainter *p = m_data->p();
879     QPen newPen(p->pen());
880     newPen.setWidthF(thickness);
881     p->setPen(newPen);
882 }
883
884 void GraphicsContext::setPlatformFillColor(const Color& color)
885 {
886     if (paintingDisabled())
887         return;
888     m_data->p()->setBrush(QBrush(color));
889 }
890
891 void GraphicsContext::setUseAntialiasing(bool enable)
892 {
893     if (paintingDisabled())
894         return;
895     m_data->p()->setRenderHint(QPainter::Antialiasing, enable);
896 }
897
898 }
899
900 // vim: ts=4 sw=4 et