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