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