Fix focus chain handling and cycling through focusable objects (links) using tab...
[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() == 0)
540         return;
541
542     QPainterPath path;
543     for (int i = 0; i < rectCount; ++i)
544         path.addRect(QRectF(rects[i]));
545     QPainter *p = m_data->p();
546
547     const QPen oldPen = p->pen();
548     const QBrush oldBrush = p->brush();
549
550     QPen nPen = p->pen();
551     nPen.setColor(color);
552     p->setBrush(Qt::NoBrush);
553     nPen.setStyle(Qt::DotLine);
554     p->setPen(nPen);
555 #if 0
556     // FIXME How do we do a bounding outline with Qt?
557     QPainterPathStroker stroker;
558     QPainterPath newPath = stroker.createStroke(path);
559     p->strokePath(newPath, nPen);
560 #else
561     p->drawRect(path.boundingRect());
562 #endif
563     p->setPen(oldPen);
564     p->setBrush(oldBrush);
565 }
566
567 void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
568 {
569     if (paintingDisabled())
570         return;
571
572     IntPoint endPoint = origin + IntSize(width, 0);
573     drawLine(origin, endPoint);
574 }
575
576 void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&,
577                                                          int width, bool grammar)
578 {
579     if (paintingDisabled())
580         return;
581
582     notImplemented();
583 }
584
585 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
586 {
587     QRectF rect(frect);
588     rect = m_data->p()->deviceMatrix().mapRect(rect);
589
590     QRect result = rect.toRect(); //round it
591     return FloatRect(QRectF(result));
592 }
593
594 void GraphicsContext::setShadow(const IntSize& pos, int blur, const Color &color)
595 {
596     if (paintingDisabled())
597         return;
598
599     m_data->shadow.x = pos.width();
600     m_data->shadow.y = pos.height();
601     m_data->shadow.blur = blur;
602     m_data->shadow.color = color;
603 }
604
605 void GraphicsContext::clearShadow()
606 {
607     if (paintingDisabled())
608         return;
609
610     m_data->shadow = TextShadow();
611 }
612
613 void GraphicsContext::beginTransparencyLayer(float opacity)
614 {
615     if (paintingDisabled())
616         return;
617
618     int x, y, w, h;
619     x = y = 0;
620     w = m_data->device->width();
621     h = m_data->device->height();
622
623     QPainter *p = m_data->p();
624     QRectF clip = p->clipPath().boundingRect();
625     bool ok;
626     QTransform transform = p->transform().inverted(&ok);
627     if (ok) {
628         QRectF deviceClip = transform.mapRect(clip);
629         x = int(qBound(qreal(0), deviceClip.x(), (qreal)w));
630         y = int(qBound(qreal(0), deviceClip.y(), (qreal)h));
631         w = int(qBound(qreal(0), deviceClip.width(), (qreal)w) + 2);
632         h = int(qBound(qreal(0), deviceClip.height(), (qreal)h) + 2);
633     }
634     TransparencyLayer * layer = new TransparencyLayer(m_data->p(), QRect(x, y, w, h));
635
636     layer->opacity = opacity;
637     m_data->layers.push(layer);
638 }
639
640 void GraphicsContext::endTransparencyLayer()
641 {
642     if (paintingDisabled())
643         return;
644
645     TransparencyLayer *layer = m_data->layers.pop();
646     layer->painter.end();
647
648     QPainter *p = m_data->p();
649     p->save();
650     p->resetTransform();
651     p->setOpacity(layer->opacity);
652     p->drawPixmap(layer->offset, layer->pixmap);
653     p->restore();
654
655     delete layer;
656 }
657
658 void GraphicsContext::clearRect(const FloatRect& rect)
659 {
660     if (paintingDisabled())
661         return;
662
663     QPainter *p = m_data->p();
664     QPainter::CompositionMode currentCompositionMode = p->compositionMode();
665     p->setCompositionMode(QPainter::CompositionMode_Source);
666     p->eraseRect(rect);
667     p->setCompositionMode(currentCompositionMode);
668 }
669
670 void GraphicsContext::strokeRect(const FloatRect& rect, float width)
671 {
672     if (paintingDisabled())
673         return;
674
675     QPainter *p = m_data->p();
676     QPainterPath path;
677     path.addRect(rect);
678     QPen nPen = p->pen();
679     nPen.setWidthF(width);
680     p->strokePath(path, nPen);
681 }
682
683 void GraphicsContext::setLineCap(LineCap lc)
684 {
685     if (paintingDisabled())
686         return;
687
688     QPainter *p = m_data->p();
689     QPen nPen = p->pen();
690     nPen.setCapStyle(toQtLineCap(lc));
691     p->setPen(nPen);
692 }
693
694 void GraphicsContext::setLineJoin(LineJoin lj)
695 {
696     if (paintingDisabled())
697         return;
698
699     QPainter *p = m_data->p();
700     QPen nPen = p->pen();
701     nPen.setJoinStyle(toQtLineJoin(lj));
702     p->setPen(nPen);
703 }
704
705 void GraphicsContext::setMiterLimit(float limit)
706 {
707     if (paintingDisabled())
708         return;
709
710     QPainter *p = m_data->p();
711     QPen nPen = p->pen();
712     nPen.setMiterLimit(limit);
713     p->setPen(nPen);
714 }
715
716 void GraphicsContext::setAlpha(float opacity)
717 {
718     if (paintingDisabled())
719         return;
720     QPainter *p = m_data->p();
721     p->setOpacity(opacity);
722 }
723
724 void GraphicsContext::setCompositeOperation(CompositeOperator op)
725 {
726     if (paintingDisabled())
727         return;
728
729     m_data->p()->setCompositionMode(toQtCompositionMode(op));
730 }
731
732 void GraphicsContext::clip(const Path& path)
733 {
734     if (paintingDisabled())
735         return;
736
737     m_data->p()->setClipPath(*path.platformPath(), Qt::IntersectClip);
738 }
739
740 void GraphicsContext::clipOut(const Path& path)
741 {
742     if (paintingDisabled())
743         return;
744
745     QPainter *p = m_data->p();
746     QRectF clipBounds = p->clipPath().boundingRect();
747     QPainterPath clippedOut = *path.platformPath();
748     QPainterPath newClip;
749     newClip.setFillRule(Qt::OddEvenFill);
750     newClip.addRect(clipBounds);
751     newClip.addPath(clippedOut);
752
753     p->setClipPath(newClip, Qt::IntersectClip);
754 }
755
756 void GraphicsContext::translate(float x, float y)
757 {
758     if (paintingDisabled())
759         return;
760
761     m_data->p()->translate(x, y);
762 }
763
764 IntPoint GraphicsContext::origin()
765 {
766     if (paintingDisabled())
767         return IntPoint();
768     const QTransform &transform = m_data->p()->transform();
769     return IntPoint(qRound(transform.dx()), qRound(transform.dy()));
770 }
771
772 void GraphicsContext::rotate(float radians)
773 {
774     if (paintingDisabled())
775         return;
776
777     m_data->p()->rotate(radians);
778 }
779
780 void GraphicsContext::scale(const FloatSize& s)
781 {
782     if (paintingDisabled())
783         return;
784
785     m_data->p()->scale(s.width(), s.height());
786 }
787
788 void GraphicsContext::clipOut(const IntRect& rect)
789 {
790     if (paintingDisabled())
791         return;
792         
793     QPainter *p = m_data->p();
794     QRectF clipBounds = p->clipPath().boundingRect();
795     QPainterPath newClip;
796     newClip.setFillRule(Qt::OddEvenFill);
797     newClip.addRect(clipBounds);
798     newClip.addRect(QRect(rect));
799
800     p->setClipPath(newClip, Qt::IntersectClip);
801 }
802
803 void GraphicsContext::clipOutEllipseInRect(const IntRect& rect)
804 {
805     if (paintingDisabled())
806         return;
807     
808     QPainter *p = m_data->p();
809     QRectF clipBounds = p->clipPath().boundingRect();
810     QPainterPath newClip;
811     newClip.setFillRule(Qt::OddEvenFill);
812     newClip.addRect(clipBounds);
813     newClip.addEllipse(QRect(rect));
814
815     p->setClipPath(newClip, Qt::IntersectClip);
816 }
817
818 void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect,
819                                               int thickness)
820 {
821     if (paintingDisabled())
822         return;
823
824     clip(rect);
825     QPainterPath path;
826
827     // Add outer ellipse
828     path.addEllipse(QRectF(rect.x(), rect.y(), rect.width(), rect.height()));
829
830     // Add inner ellipse.
831     path.addEllipse(QRectF(rect.x() + thickness, rect.y() + thickness,
832                            rect.width() - (thickness * 2), rect.height() - (thickness * 2)));
833
834     path.setFillRule(Qt::OddEvenFill);
835     m_data->p()->setClipPath(path, Qt::IntersectClip);
836 }
837
838 void GraphicsContext::concatCTM(const AffineTransform& transform)
839 {
840     if (paintingDisabled())
841         return;
842
843     m_data->p()->setMatrix(transform, true);
844 }
845
846 void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
847 {
848     notImplemented();
849 }
850
851 void GraphicsContext::setPlatformFont(const Font& aFont)
852 {
853     if (paintingDisabled())
854         return;
855     m_data->p()->setFont(aFont.font());
856 }
857
858 void GraphicsContext::setPlatformStrokeColor(const Color& color)
859 {
860     if (paintingDisabled())
861         return;
862     QPainter *p = m_data->p();
863     QPen newPen(p->pen());
864     newPen.setColor(color);
865     p->setPen(newPen);
866 }
867
868 void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& strokeStyle)
869 {   
870     if (paintingDisabled())
871         return;
872     QPainter *p = m_data->p();
873     QPen newPen(p->pen());
874     newPen.setStyle(toQPenStyle(strokeStyle));
875     p->setPen(newPen);
876 }
877
878 void GraphicsContext::setPlatformStrokeThickness(float thickness)
879 {
880     if (paintingDisabled())
881         return;
882     QPainter *p = m_data->p();
883     QPen newPen(p->pen());
884     newPen.setWidthF(thickness);
885     p->setPen(newPen);
886 }
887
888 void GraphicsContext::setPlatformFillColor(const Color& color)
889 {
890     if (paintingDisabled())
891         return;
892     m_data->p()->setBrush(QBrush(color));
893 }
894
895 void GraphicsContext::setUseAntialiasing(bool enable)
896 {
897     if (paintingDisabled())
898         return;
899     m_data->p()->setRenderHint(QPainter::Antialiasing, enable);
900 }
901
902 }
903
904 // vim: ts=4 sw=4 et