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