2011-07-05 Igor Oliveira <igor.oliveira@openbossa.org>
[WebKit-https.git] / Source / 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  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
9  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
10  * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de>
11  * Copyright (C) 2010, 2011 Sencha, Inc.
12  * Copyright (C) 2011 Andreas Kling <kling@webkit.org>
13  *
14  * All rights reserved.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  *
25  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
26  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
29  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
33  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37
38 #include "config.h"
39 #include "GraphicsContext.h"
40
41 #ifdef Q_WS_WIN
42 #include <windows.h>
43 #endif
44
45 #include "AffineTransform.h"
46 #include "Color.h"
47 #include "FloatConversion.h"
48 #include "Font.h"
49 #include "ImageBuffer.h"
50 #include "NotImplemented.h"
51 #include "Path.h"
52 #include "Pattern.h"
53 #include "ShadowBlur.h"
54 #include "TransparencyLayer.h"
55
56 #include <QBrush>
57 #include <QGradient>
58 #include <QPaintDevice>
59 #include <QPaintEngine>
60 #include <QPainter>
61 #include <QPainterPath>
62 #include <QPixmap>
63 #include <QPolygonF>
64 #include <QStack>
65 #include <QVector>
66 #include <wtf/MathExtras.h>
67
68 namespace WebCore {
69
70 static inline QPainter::CompositionMode toQtCompositionMode(CompositeOperator op)
71 {
72     switch (op) {
73     case CompositeClear:
74         return QPainter::CompositionMode_Clear;
75     case CompositeCopy:
76         return QPainter::CompositionMode_Source;
77     case CompositeSourceOver:
78         return QPainter::CompositionMode_SourceOver;
79     case CompositeSourceIn:
80         return QPainter::CompositionMode_SourceIn;
81     case CompositeSourceOut:
82         return QPainter::CompositionMode_SourceOut;
83     case CompositeSourceAtop:
84         return QPainter::CompositionMode_SourceAtop;
85     case CompositeDestinationOver:
86         return QPainter::CompositionMode_DestinationOver;
87     case CompositeDestinationIn:
88         return QPainter::CompositionMode_DestinationIn;
89     case CompositeDestinationOut:
90         return QPainter::CompositionMode_DestinationOut;
91     case CompositeDestinationAtop:
92         return QPainter::CompositionMode_DestinationAtop;
93     case CompositeXOR:
94         return QPainter::CompositionMode_Xor;
95     case CompositePlusDarker:
96         // there is no exact match, but this is the closest
97         return QPainter::CompositionMode_Darken;
98     case CompositePlusLighter:
99         return QPainter::CompositionMode_Plus;
100     default:
101         ASSERT_NOT_REACHED();
102     }
103
104     return QPainter::CompositionMode_SourceOver;
105 }
106
107 static inline Qt::PenCapStyle toQtLineCap(LineCap lc)
108 {
109     switch (lc) {
110     case ButtCap:
111         return Qt::FlatCap;
112     case RoundCap:
113         return Qt::RoundCap;
114     case SquareCap:
115         return Qt::SquareCap;
116     default:
117         ASSERT_NOT_REACHED();
118     }
119
120     return Qt::FlatCap;
121 }
122
123 static inline Qt::PenJoinStyle toQtLineJoin(LineJoin lj)
124 {
125     switch (lj) {
126     case MiterJoin:
127         return Qt::SvgMiterJoin;
128     case RoundJoin:
129         return Qt::RoundJoin;
130     case BevelJoin:
131         return Qt::BevelJoin;
132     default:
133         ASSERT_NOT_REACHED();
134     }
135
136     return Qt::SvgMiterJoin;
137 }
138
139 static Qt::PenStyle toQPenStyle(StrokeStyle style)
140 {
141     switch (style) {
142     case NoStroke:
143         return Qt::NoPen;
144         break;
145     case SolidStroke:
146         return Qt::SolidLine;
147         break;
148     case DottedStroke:
149         return Qt::DotLine;
150         break;
151     case DashedStroke:
152         return Qt::DashLine;
153         break;
154     default:
155         ASSERT_NOT_REACHED();
156     }
157     return Qt::NoPen;
158 }
159
160 static inline Qt::FillRule toQtFillRule(WindRule rule)
161 {
162     switch (rule) {
163     case RULE_EVENODD:
164         return Qt::OddEvenFill;
165     case RULE_NONZERO:
166         return Qt::WindingFill;
167     default:
168         ASSERT_NOT_REACHED();
169     }
170     return Qt::OddEvenFill;
171 }
172
173 class GraphicsContextPlatformPrivate {
174     WTF_MAKE_NONCOPYABLE(GraphicsContextPlatformPrivate); WTF_MAKE_FAST_ALLOCATED;
175 public:
176     GraphicsContextPlatformPrivate(QPainter*, const QColor& initialSolidColor);
177     ~GraphicsContextPlatformPrivate();
178
179     inline QPainter* p() const
180     {
181         if (layers.isEmpty())
182             return painter;
183         return &layers.top()->painter;
184     }
185
186     bool antiAliasingForRectsAndLines;
187
188     QStack<TransparencyLayer*> layers;
189     // Counting real layers. Required by inTransparencyLayer() calls
190     // For example, layers with valid alphaMask are not real layers
191     int layerCount;
192
193     // reuse this brush for solid color (to prevent expensive QBrush construction)
194     QBrush solidColor;
195
196     InterpolationQuality imageInterpolationQuality;
197     bool initialSmoothPixmapTransformHint;
198
199     ShadowBlur* shadow;
200
201     bool mustUseShadowBlur() const
202     {
203         // We can't avoid ShadowBlur, since the shadow has blur.
204         if (shadow->type() == ShadowBlur::BlurShadow)
205             return true;
206         // We can avoid ShadowBlur and optimize, since we're not drawing on a
207         // canvas and box shadows are affected by the transformation matrix.
208         if (!shadow->shadowsIgnoreTransforms())
209             return false;
210         // We can avoid ShadowBlur, since there are no transformations to apply to the canvas.
211         if (p()->combinedTransform().isIdentity())
212             return false;
213         // Otherwise, no chance avoiding ShadowBlur.
214         return true;
215     }
216
217     QRectF clipBoundingRect() const
218     {
219 #if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
220         return p()->clipBoundingRect();
221 #else
222         return p()->clipRegion().boundingRect();
223 #endif
224     }
225
226     void takeOwnershipOfPlatformContext() { platformContextIsOwned = true; }
227
228 private:
229     QPainter* painter;
230     bool platformContextIsOwned;
231 };
232
233 GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p, const QColor& initialSolidColor)
234     : antiAliasingForRectsAndLines(false)
235     , layerCount(0)
236     , solidColor(initialSolidColor)
237     , imageInterpolationQuality(InterpolationDefault)
238     , initialSmoothPixmapTransformHint(false)
239     , shadow(new ShadowBlur())
240     , painter(p)
241     , platformContextIsOwned(false)
242 {
243     if (!painter)
244         return;
245
246 #if OS(SYMBIAN)
247     if (painter->paintEngine()->type() == QPaintEngine::OpenVG)
248         antiAliasingForRectsAndLines = true;
249     else
250         antiAliasingForRectsAndLines = painter->testRenderHint(QPainter::Antialiasing);
251 #else
252     // Use the default the QPainter was constructed with.
253     antiAliasingForRectsAndLines = painter->testRenderHint(QPainter::Antialiasing);
254 #endif
255
256     // Used for default image interpolation quality.
257     initialSmoothPixmapTransformHint = painter->testRenderHint(QPainter::SmoothPixmapTransform);
258
259     painter->setRenderHint(QPainter::Antialiasing, true);
260
261 }
262
263 GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
264 {
265     if (!platformContextIsOwned)
266         return;
267
268     QPaintDevice* device = painter->device();
269     painter->end();
270     delete shadow;
271     delete painter;
272     delete device;
273 }
274
275 void GraphicsContext::platformInit(PlatformGraphicsContext* painter)
276 {
277     m_data = new GraphicsContextPlatformPrivate(painter, fillColor());
278
279     setPaintingDisabled(!painter);
280
281     if (!painter)
282         return;
283
284     // solidColor is initialized with the fillColor().
285     painter->setBrush(m_data->solidColor);
286
287     QPen pen(painter->pen());
288     pen.setColor(strokeColor());
289     pen.setJoinStyle(toQtLineJoin(MiterJoin));
290     painter->setPen(pen);
291 }
292
293 void GraphicsContext::platformDestroy()
294 {
295     while (!m_data->layers.isEmpty())
296         endTransparencyLayer();
297
298     delete m_data;
299 }
300
301 PlatformGraphicsContext* GraphicsContext::platformContext() const
302 {
303     return m_data->p();
304 }
305
306 AffineTransform GraphicsContext::getCTM() const
307 {
308     const QTransform& matrix = platformContext()->combinedTransform();
309     return AffineTransform(matrix.m11(), matrix.m12(), matrix.m21(),
310                            matrix.m22(), matrix.dx(), matrix.dy());
311 }
312
313 void GraphicsContext::savePlatformState()
314 {
315     if (!m_data->layers.isEmpty() && !m_data->layers.top()->alphaMask.isNull())
316         ++m_data->layers.top()->saveCounter;
317     m_data->p()->save();
318 }
319
320 void GraphicsContext::restorePlatformState()
321 {
322     if (!m_data->layers.isEmpty() && !m_data->layers.top()->alphaMask.isNull())
323         if (!--m_data->layers.top()->saveCounter)
324             endTransparencyLayer();
325
326     m_data->p()->restore();
327
328     m_data->shadow->setShadowValues(FloatSize(m_state.shadowBlur, m_state.shadowBlur), m_state.shadowOffset, m_state.shadowColor, m_state.shadowColorSpace, m_state.shadowsIgnoreTransforms);
329 }
330
331 // Draws a filled rectangle with a stroked border.
332 // This is only used to draw borders (real fill is done via fillRect), and
333 // thus it must not cast any shadow.
334 void GraphicsContext::drawRect(const IntRect& rect)
335 {
336     if (paintingDisabled())
337         return;
338
339     QPainter* p = m_data->p();
340     const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
341     p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines);
342
343     p->drawRect(rect);
344
345     p->setRenderHint(QPainter::Antialiasing, antiAlias);
346 }
347
348 // This is only used to draw borders.
349 // Must not cast any shadow.
350 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
351 {
352     if (paintingDisabled())
353         return;
354
355     StrokeStyle style = strokeStyle();
356     Color color = strokeColor();
357     if (style == NoStroke)
358         return;
359
360     float width = strokeThickness();
361
362     FloatPoint p1 = point1;
363     FloatPoint p2 = point2;
364     bool isVerticalLine = (p1.x() == p2.x());
365
366     QPainter* p = m_data->p();
367     const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
368     p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines);
369     adjustLineToPixelBoundaries(p1, p2, width, style);
370
371     int patWidth = 0;
372     switch (style) {
373     case NoStroke:
374     case SolidStroke:
375         break;
376     case DottedStroke:
377         patWidth = static_cast<int>(width);
378         break;
379     case DashedStroke:
380         patWidth = 3 * static_cast<int>(width);
381         break;
382     }
383
384     if (patWidth) {
385         p->save();
386
387         // Do a rect fill of our endpoints.  This ensures we always have the
388         // appearance of being a border.  We then draw the actual dotted/dashed line.
389         if (isVerticalLine) {
390             p->fillRect(FloatRect(p1.x() - width / 2, p1.y() - width, width, width), QColor(color));
391             p->fillRect(FloatRect(p2.x() - width / 2, p2.y(), width, width), QColor(color));
392         } else {
393             p->fillRect(FloatRect(p1.x() - width, p1.y() - width / 2, width, width), QColor(color));
394             p->fillRect(FloatRect(p2.x(), p2.y() - width / 2, width, width), QColor(color));
395         }
396
397         // Example: 80 pixels with a width of 30 pixels.
398         // Remainder is 20.  The maximum pixels of line we could paint
399         // will be 50 pixels.
400         int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*(int)width;
401         int remainder = distance % patWidth;
402         int coverage = distance - remainder;
403         int numSegments = coverage / patWidth;
404
405         float patternOffset = 0.0f;
406         // Special case 1px dotted borders for speed.
407         if (patWidth == 1)
408             patternOffset = 1.0f;
409         else {
410             bool evenNumberOfSegments = !(numSegments % 2);
411             if (remainder)
412                 evenNumberOfSegments = !evenNumberOfSegments;
413             if (evenNumberOfSegments) {
414                 if (remainder) {
415                     patternOffset += patWidth - remainder;
416                     patternOffset += remainder / 2;
417                 } else
418                     patternOffset = patWidth / 2;
419             } else {
420                 if (remainder)
421                     patternOffset = (patWidth - remainder) / 2;
422             }
423         }
424
425         QVector<qreal> dashes;
426         dashes << qreal(patWidth) / width << qreal(patWidth) / width;
427
428         QPen pen = p->pen();
429         pen.setWidthF(width);
430         pen.setCapStyle(Qt::FlatCap);
431         pen.setDashPattern(dashes);
432         pen.setDashOffset(patternOffset / width);
433         p->setPen(pen);
434     }
435
436     p->drawLine(p1, p2);
437
438     if (patWidth)
439         p->restore();
440
441     p->setRenderHint(QPainter::Antialiasing, antiAlias);
442 }
443
444 // This method is only used to draw the little circles used in lists.
445 void GraphicsContext::drawEllipse(const IntRect& rect)
446 {
447     if (paintingDisabled())
448         return;
449
450     m_data->p()->drawEllipse(rect);
451 }
452
453 void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
454 {
455     if (paintingDisabled())
456         return;
457
458     if (npoints <= 1)
459         return;
460
461     QPolygonF polygon(npoints);
462
463     for (size_t i = 0; i < npoints; i++)
464         polygon[i] = points[i];
465
466     QPainter* p = m_data->p();
467
468     const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
469     p->setRenderHint(QPainter::Antialiasing, shouldAntialias);
470
471     p->drawConvexPolygon(polygon);
472
473     p->setRenderHint(QPainter::Antialiasing, antiAlias);
474 }
475
476 void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
477 {
478     if (paintingDisabled())
479         return;
480
481     if (numPoints <= 1)
482         return;
483
484     QPainterPath path(points[0]);
485     for (size_t i = 1; i < numPoints; ++i)
486         path.lineTo(points[i]);
487     path.setFillRule(Qt::WindingFill);
488
489     QPainter* p = m_data->p();
490
491     bool painterWasAntialiased = p->testRenderHint(QPainter::Antialiasing);
492
493     if (painterWasAntialiased != antialiased)
494         p->setRenderHint(QPainter::Antialiasing, antialiased);
495
496     p->setClipPath(path, Qt::IntersectClip);
497
498     if (painterWasAntialiased != antialiased)
499         p->setRenderHint(QPainter::Antialiasing, painterWasAntialiased);
500 }
501
502 void GraphicsContext::fillPath(const Path& path)
503 {
504     if (paintingDisabled())
505         return;
506
507     QPainter* p = m_data->p();
508     QPainterPath platformPath = path.platformPath();
509     platformPath.setFillRule(toQtFillRule(fillRule()));
510
511     if (hasShadow()) {
512         ShadowBlur* shadow = shadowBlur();
513         if (m_data->mustUseShadowBlur() || m_state.fillPattern || m_state.fillGradient)
514         {
515             GraphicsContext* shadowContext = shadow->beginShadowLayer(this, platformPath.controlPointRect());
516             if (shadowContext) {
517                 QPainter* shadowPainter = shadowContext->platformContext();
518                 if (m_state.fillPattern) {
519                     AffineTransform affine;
520                     shadowPainter->fillPath(platformPath, QBrush(m_state.fillPattern->createPlatformPattern(affine)));
521                 } else if (m_state.fillGradient) {
522                     QBrush brush(*m_state.fillGradient->platformGradient());
523                     brush.setTransform(m_state.fillGradient->gradientSpaceTransform());
524                     shadowPainter->fillPath(platformPath, brush);
525                 } else {
526                     QColor shadowColor = m_state.shadowColor;
527                     shadowPainter->fillPath(platformPath, p->brush().color());
528                 }
529                 shadow->endShadowLayer(this);
530             }
531         } else {
532             QPointF offset(m_state.shadowOffset.width(), m_state.shadowOffset.height());
533             p->translate(offset);
534             QColor shadowColor = m_state.shadowColor;
535             shadowColor.setAlphaF(shadowColor.alphaF() * p->brush().color().alphaF());
536             p->fillPath(platformPath, shadowColor);
537             p->translate(-offset);
538         }
539     }
540     if (m_state.fillPattern) {
541         AffineTransform affine;
542         p->fillPath(platformPath, QBrush(m_state.fillPattern->createPlatformPattern(affine)));
543     } else if (m_state.fillGradient) {
544         QBrush brush(*m_state.fillGradient->platformGradient());
545         brush.setTransform(m_state.fillGradient->gradientSpaceTransform());
546         p->fillPath(platformPath, brush);
547     } else
548         p->fillPath(platformPath, p->brush());
549 }
550
551 void GraphicsContext::strokePath(const Path& path)
552 {
553     if (paintingDisabled())
554         return;
555
556     QPainter* p = m_data->p();
557     QPen pen(p->pen());
558     QPainterPath platformPath = path.platformPath();
559     platformPath.setFillRule(toQtFillRule(fillRule()));
560
561     if (hasShadow()) {
562         ShadowBlur* shadow = shadowBlur();
563         if (m_data->mustUseShadowBlur() || m_state.strokePattern || m_state.strokeGradient)
564         {
565             FloatRect boundingRect = platformPath.controlPointRect();
566             boundingRect.inflate(pen.miterLimit() + pen.widthF());
567             GraphicsContext* shadowContext = shadow->beginShadowLayer(this, boundingRect);
568             if (shadowContext) {
569                 QPainter* shadowPainter = shadowContext->platformContext();
570                 if (m_state.strokeGradient) {
571                     QBrush brush(*m_state.strokeGradient->platformGradient());
572                     brush.setTransform(m_state.strokeGradient->gradientSpaceTransform());
573                     QPen shadowPen(pen);
574                     shadowPen.setBrush(brush);
575                     shadowPainter->strokePath(platformPath, shadowPen);
576                 } else {
577                     shadowPainter->strokePath(platformPath, pen);
578                 }
579                 shadow->endShadowLayer(this);
580             }
581         } else {
582             QPointF offset(m_state.shadowOffset.width(), m_state.shadowOffset.height());
583             p->translate(offset);
584             QColor shadowColor = m_state.shadowColor;
585             shadowColor.setAlphaF(shadowColor.alphaF() * pen.color().alphaF());
586             QPen shadowPen(pen);
587             shadowPen.setColor(shadowColor);
588             p->strokePath(platformPath, shadowPen);
589             p->translate(-offset);
590         }
591     }
592
593     if (m_state.strokePattern) {
594         AffineTransform affine;
595         pen.setBrush(QBrush(m_state.strokePattern->createPlatformPattern(affine)));
596         p->setPen(pen);
597         p->strokePath(platformPath, pen);
598     } else if (m_state.strokeGradient) {
599         QBrush brush(*m_state.strokeGradient->platformGradient());
600         brush.setTransform(m_state.strokeGradient->gradientSpaceTransform());
601         pen.setBrush(brush);
602         p->setPen(pen);
603         p->strokePath(platformPath, pen);
604     } else
605         p->strokePath(platformPath, pen);
606 }
607
608 static inline void drawRepeatPattern(QPainter* p, QPixmap* image, const FloatRect& rect, const bool repeatX, const bool repeatY)
609 {
610     // Patterns must be painted so that the top left of the first image is anchored at
611     // the origin of the coordinate space
612     if (image) {
613         int w = image->width();
614         int h = image->height();
615         int startX, startY;
616         QRect r(static_cast<int>(rect.x()), static_cast<int>(rect.y()), static_cast<int>(rect.width()), static_cast<int>(rect.height()));
617
618         // startX, startY is the coordinate of the first image we need to put on the left-top of the rect
619         if (repeatX && repeatY) {
620             // repeat
621             // startX, startY is at the left top side of the left-top of the rect
622             startX = r.x() >=0 ? r.x() - (r.x() % w) : r.x() - (w - qAbs(r.x()) % w);
623             startY = r.y() >=0 ? r.y() - (r.y() % h) : r.y() - (h - qAbs(r.y()) % h);
624         } else {
625            if (!repeatX && !repeatY) {
626                // no-repeat
627                // only draw the image once at orgin once, check if need to draw
628                QRect imageRect(0, 0, w, h);
629                if (imageRect.intersects(r)) {
630                    startX = 0;
631                    startY = 0;
632                } else
633                    return;   
634            } else if (repeatX && !repeatY) {
635                // repeat-x
636                // startY is fixed, but startX change based on the left-top of the rect
637                QRect imageRect(r.x(), 0, r.width(), h);
638                if (imageRect.intersects(r)) {
639                    startX = r.x() >=0 ? r.x() - (r.x() % w) : r.x() - (w - qAbs(r.x()) % w);
640                    startY = 0;
641                } else
642                    return;
643            } else {
644                // repeat-y
645                // startX is fixed, but startY change based on the left-top of the rect
646                QRect imageRect(0, r.y(), w, r.height());
647                if (imageRect.intersects(r)) {
648                    startX = 0;
649                    startY = r.y() >=0 ? r.y() - (r.y() % h) : r.y() - (h - qAbs(r.y()) % h);
650                } else
651                    return;
652            }
653         }
654
655         int x = startX;
656         int y = startY; 
657         do {
658             // repeat Y
659             do {
660                 // repeat X
661                 QRect   imageRect(x, y, w, h);
662                 QRect   intersectRect = imageRect.intersected(r);
663                 QPoint  destStart(intersectRect.x(), intersectRect.y());
664                 QRect   sourceRect(intersectRect.x() - imageRect.x(), intersectRect.y() - imageRect.y(), intersectRect.width(), intersectRect.height());
665
666                 p->drawPixmap(destStart, *image, sourceRect);
667                 x += w;
668             } while (repeatX && x < r.x() + r.width());
669             x = startX;
670             y += h;
671         } while (repeatY && y < r.y() + r.height());
672     }
673 }
674
675 void GraphicsContext::fillRect(const FloatRect& rect)
676 {
677     if (paintingDisabled())
678         return;
679
680     QPainter* p = m_data->p();
681     QRectF normalizedRect = rect.normalized();
682     ShadowBlur* shadow = shadowBlur();
683
684     if (m_state.fillPattern) {
685         QPixmap* image = m_state.fillPattern->tileImage()->nativeImageForCurrentFrame();
686         GraphicsContext* shadowContext = hasShadow() ? shadow->beginShadowLayer(this, normalizedRect) : 0;
687         if (shadowContext) {
688             QPainter* shadowPainter = shadowContext->platformContext();
689             drawRepeatPattern(shadowPainter, image, normalizedRect, m_state.fillPattern->repeatX(), m_state.fillPattern->repeatY());
690             shadow->endShadowLayer(this);
691         }
692         drawRepeatPattern(p, image, normalizedRect, m_state.fillPattern->repeatX(), m_state.fillPattern->repeatY());
693     } else if (m_state.fillGradient) {
694         QBrush brush(*m_state.fillGradient->platformGradient());
695         brush.setTransform(m_state.fillGradient->gradientSpaceTransform());
696         GraphicsContext* shadowContext = hasShadow() ? shadow->beginShadowLayer(this, normalizedRect) : 0;
697         if (shadowContext) {
698             QPainter* shadowPainter = shadowContext->platformContext();
699             shadowPainter->fillRect(normalizedRect, brush);
700             shadow->endShadowLayer(this);
701         }
702         p->fillRect(normalizedRect, brush);
703     } else {
704         if (hasShadow()) {
705             if (m_data->mustUseShadowBlur()) {
706                 GraphicsContext* shadowContext = shadow->beginShadowLayer(this, normalizedRect);
707                 if (shadowContext) {
708                     QPainter* shadowPainter = shadowContext->platformContext();
709                     shadowPainter->fillRect(normalizedRect, p->brush());
710                     shadow->endShadowLayer(this);
711                 }
712             } else {
713                 // Solid rectangle fill with no blur shadow or transformations applied can be done
714                 // faster without using the shadow layer at all.
715                 QColor shadowColor = m_state.shadowColor;
716                 shadowColor.setAlphaF(shadowColor.alphaF() * p->brush().color().alphaF());
717                 p->fillRect(normalizedRect.translated(QPointF(m_state.shadowOffset.width(), m_state.shadowOffset.height())), shadowColor);
718             }
719         }
720
721         p->fillRect(normalizedRect, p->brush());
722     }
723 }
724
725
726 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
727 {
728     if (paintingDisabled() || !color.isValid())
729         return;
730
731     m_data->solidColor.setColor(color);
732     QPainter* p = m_data->p();
733     QRectF normalizedRect = rect.normalized();
734
735     if (hasShadow()) {
736         ShadowBlur* shadow = shadowBlur();
737         if (m_data->mustUseShadowBlur()) {
738             GraphicsContext* shadowContext = shadow->beginShadowLayer(this, normalizedRect);
739             if (shadowContext) {
740                 QPainter* shadowPainter = shadowContext->platformContext();
741                 shadowPainter->setCompositionMode(QPainter::CompositionMode_Source);
742                 shadowPainter->fillRect(normalizedRect, m_state.shadowColor);
743                 shadow->endShadowLayer(this);
744             }
745         } else {
746             QColor shadowColor = m_state.shadowColor;
747             shadowColor.setAlphaF(shadowColor.alphaF() * p->brush().color().alphaF());
748             p->fillRect(normalizedRect.translated(QPointF(m_state.shadowOffset.width(), m_state.shadowOffset.height())), shadowColor);
749         }
750     }
751
752     p->fillRect(normalizedRect, m_data->solidColor);
753 }
754
755 void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
756 {
757     if (paintingDisabled() || !color.isValid())
758         return;
759
760     Path path;
761     path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
762     QPainter* p = m_data->p();
763     if (hasShadow()) {
764         ShadowBlur* shadow = shadowBlur();
765         if (m_data->mustUseShadowBlur()) {
766             GraphicsContext* shadowContext = shadow->beginShadowLayer(this, rect);
767             if (shadowContext) {
768                 QPainter* shadowPainter = shadowContext->platformContext();
769                 shadowPainter->setCompositionMode(QPainter::CompositionMode_Source);
770                 shadowPainter->fillPath(path.platformPath(), QColor(m_state.shadowColor));
771                 shadow->endShadowLayer(this);
772             }
773         } else {
774             const QPointF shadowOffset(m_state.shadowOffset.width(), m_state.shadowOffset.height());
775             p->translate(shadowOffset);
776             p->fillPath(path.platformPath(), QColor(m_state.shadowColor));
777             p->translate(-shadowOffset);
778         }
779     }
780     p->fillPath(path.platformPath(), QColor(color));
781 }
782
783 bool GraphicsContext::inTransparencyLayer() const
784 {
785     return m_data->layerCount;
786 }
787
788 ShadowBlur* GraphicsContext::shadowBlur()
789 {
790     return m_data->shadow;
791 }
792
793 void GraphicsContext::clip(const IntRect& rect)
794 {
795     if (paintingDisabled())
796         return;
797
798     m_data->p()->setClipRect(rect, Qt::IntersectClip);
799 }
800
801 void GraphicsContext::clip(const FloatRect& rect)
802 {
803     if (paintingDisabled())
804         return;
805
806     m_data->p()->setClipRect(rect, Qt::IntersectClip);
807 }
808 IntRect GraphicsContext::clipBounds() const
809 {
810     QPainter* p = m_data->p();
811     QRectF clipRect;
812
813     if (p->hasClipping())
814         clipRect = m_data->clipBoundingRect();
815     else
816         clipRect = p->transform().inverted().mapRect(p->window());
817
818     return enclosingIntRect(clipRect);
819 }
820
821 void GraphicsContext::clipPath(const Path& path, WindRule clipRule)
822 {
823     if (paintingDisabled())
824         return;
825
826     QPainter* p = m_data->p();
827     QPainterPath platformPath = path.platformPath();
828     platformPath.setFillRule(clipRule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill);
829     p->setClipPath(platformPath, Qt::IntersectClip);
830 }
831
832 void drawFocusRingForPath(QPainter* p, const QPainterPath& path, const Color& color, bool antiAliasing)
833 {
834     const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
835     p->setRenderHint(QPainter::Antialiasing, antiAliasing);
836
837     const QPen oldPen = p->pen();
838     const QBrush oldBrush = p->brush();
839
840     QPen nPen = p->pen();
841     nPen.setColor(color);
842     p->setBrush(Qt::NoBrush);
843     nPen.setStyle(Qt::DotLine);
844
845     p->strokePath(path, nPen);
846     p->setBrush(oldBrush);
847     p->setPen(oldPen);
848
849     p->setRenderHint(QPainter::Antialiasing, antiAlias);
850 }
851
852 void GraphicsContext::drawFocusRing(const Path& path, int /* width */, int offset, const Color& color)
853 {
854     // FIXME: Use 'offset' for something? http://webkit.org/b/49909
855
856     if (paintingDisabled() || !color.isValid())
857         return;
858
859     drawFocusRingForPath(m_data->p(), path.platformPath(), color, m_data->antiAliasingForRectsAndLines);
860 }
861
862 /**
863  * Focus ring handling for form controls is not handled here. Qt style in
864  * RenderTheme handles drawing focus on widgets which 
865  * need it. It is still handled here for links.
866  */
867 void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
868 {
869     if (paintingDisabled() || !color.isValid())
870         return;
871
872     unsigned rectCount = rects.size();
873
874     if (!rects.size())
875         return;
876
877     int radius = (width - 1) / 2;
878     QPainterPath path;
879     for (unsigned i = 0; i < rectCount; ++i) {
880         QRect rect = QRect((rects[i])).adjusted(-offset - radius, -offset - radius, offset + radius, offset + radius);
881         // This is not the most efficient way to add a rect to a path, but if we don't create the tmpPath,
882         // we will end up with ugly lines in between rows of text on anchors with multiple lines.
883         QPainterPath tmpPath;
884         tmpPath.addRoundedRect(rect, radius, radius);
885         path = path.united(tmpPath);
886     }
887     drawFocusRingForPath(m_data->p(), path, color, m_data->antiAliasingForRectsAndLines);
888 }
889
890 void GraphicsContext::drawLineForText(const FloatPoint& origin, float width, bool)
891 {
892     if (paintingDisabled())
893         return;
894
895     FloatPoint startPoint = origin;
896     FloatPoint endPoint = origin + FloatSize(width, 0);
897
898     // If paintengine type is X11 to avoid artifacts
899     // like bug https://bugs.webkit.org/show_bug.cgi?id=42248
900 #if defined(Q_WS_X11)
901     QPainter* p = m_data->p();
902     if (p->paintEngine()->type() == QPaintEngine::X11) {
903         // If stroke thickness is odd we need decrease Y coordinate by 1 pixel,
904         // because inside method adjustLineToPixelBoundaries(...), which
905         // called from drawLine(...), Y coordinate will be increased by 0.5f
906         // and then inside Qt painting engine will be rounded to next greater
907         // integer value.
908         float strokeWidth = strokeThickness();
909         if (static_cast<int>(strokeWidth) % 2) {
910             startPoint.setY(startPoint.y() - 1);
911             endPoint.setY(endPoint.y() - 1);
912         }
913     }
914 #endif // defined(Q_WS_X11)
915
916     // FIXME: Loss of precision here. Might consider rounding.
917     drawLine(IntPoint(startPoint.x(), startPoint.y()), IntPoint(endPoint.x(), endPoint.y()));
918 }
919
920 void GraphicsContext::drawLineForTextChecking(const FloatPoint&, float, TextCheckingLineStyle)
921 {
922     if (paintingDisabled())
923         return;
924
925     notImplemented();
926 }
927
928 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode)
929 {
930     // It is not enough just to round to pixels in device space. The rotation part of the
931     // affine transform matrix to device space can mess with this conversion if we have a
932     // rotating image like the hands of the world clock widget. We just need the scale, so
933     // we get the affine transform matrix and extract the scale.
934     QPainter* painter = platformContext();
935     QTransform deviceTransform = painter->deviceTransform();
936     if (deviceTransform.isIdentity())
937         return frect;
938
939     qreal deviceScaleX = sqrtf(deviceTransform.m11() * deviceTransform.m11() + deviceTransform.m12() * deviceTransform.m12());
940     qreal deviceScaleY = sqrtf(deviceTransform.m21() * deviceTransform.m21() + deviceTransform.m22() * deviceTransform.m22());
941
942     QPoint deviceOrigin(frect.x() * deviceScaleX, frect.y() * deviceScaleY);
943     QPoint deviceLowerRight(frect.maxX() * deviceScaleX, frect.maxY() * deviceScaleY);
944
945     // Don't let the height or width round to 0 unless either was originally 0
946     if (deviceOrigin.y() == deviceLowerRight.y() && frect.height())
947         deviceLowerRight.setY(deviceLowerRight.y() + 1);
948     if (deviceOrigin.x() == deviceLowerRight.x() && frect.width())
949         deviceLowerRight.setX(deviceLowerRight.x() + 1);
950
951     FloatPoint roundedOrigin = FloatPoint(deviceOrigin.x() / deviceScaleX, deviceOrigin.y() / deviceScaleY);
952     FloatPoint roundedLowerRight = FloatPoint(deviceLowerRight.x() / deviceScaleX, deviceLowerRight.y() / deviceScaleY);
953     return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin);
954 }
955
956 void GraphicsContext::setPlatformShadow(const FloatSize& size, float blur, const Color& color, ColorSpace colorSpace)
957 {
958     // Qt doesn't support shadows natively, they are drawn manually in the draw*
959     // functions
960
961     if (m_state.shadowsIgnoreTransforms) {
962         // Meaning that this graphics context is associated with a CanvasRenderingContext
963         // We flip the height since CG and HTML5 Canvas have opposite Y axis
964         m_state.shadowOffset = FloatSize(size.width(), -size.height());
965     }
966
967     m_data->shadow->setShadowValues(FloatSize(m_state.shadowBlur, m_state.shadowBlur), m_state.shadowOffset, color, colorSpace, m_state.shadowsIgnoreTransforms);
968 }
969
970 void GraphicsContext::clearPlatformShadow()
971 {
972     m_data->shadow->clear();
973 }
974
975 void GraphicsContext::pushTransparencyLayerInternal(const QRect &rect, qreal opacity, QPixmap& alphaMask)
976 {
977     QPainter* p = m_data->p();
978
979     QRect deviceClip = p->transform().mapRect(rect);
980     if (alphaMask.width() != deviceClip.width() || alphaMask.height() != deviceClip.height())
981         alphaMask = alphaMask.scaled(deviceClip.width(), deviceClip.height());
982
983     m_data->layers.push(new TransparencyLayer(p, deviceClip, 1.0, alphaMask));
984 }
985
986 void GraphicsContext::beginTransparencyLayer(float opacity)
987 {
988     if (paintingDisabled())
989         return;
990
991     int x, y, w, h;
992     x = y = 0;
993     QPainter* p = m_data->p();
994     const QPaintDevice* device = p->device();
995     w = device->width();
996     h = device->height();
997
998     QRectF clip = m_data->clipBoundingRect();
999     QRectF deviceClip = p->transform().mapRect(clip);
1000     x = int(qBound(qreal(0), deviceClip.x(), (qreal)w));
1001     y = int(qBound(qreal(0), deviceClip.y(), (qreal)h));
1002     w = int(qBound(qreal(0), deviceClip.width(), (qreal)w) + 2);
1003     h = int(qBound(qreal(0), deviceClip.height(), (qreal)h) + 2);
1004
1005     QPixmap emptyAlphaMask;
1006     m_data->layers.push(new TransparencyLayer(p, QRect(x, y, w, h), opacity, emptyAlphaMask));
1007     ++m_data->layerCount;
1008 }
1009
1010 void GraphicsContext::endTransparencyLayer()
1011 {
1012     if (paintingDisabled())
1013         return;
1014
1015     TransparencyLayer* layer = m_data->layers.pop();
1016     if (!layer->alphaMask.isNull()) {
1017         layer->painter.resetTransform();
1018         layer->painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
1019         layer->painter.drawPixmap(QPoint(), layer->alphaMask);
1020     } else
1021         --m_data->layerCount; // see the comment for layerCount
1022     layer->painter.end();
1023
1024     QPainter* p = m_data->p();
1025     p->save();
1026     p->resetTransform();
1027     p->setOpacity(layer->opacity);
1028     p->drawPixmap(layer->offset, layer->pixmap);
1029     p->restore();
1030
1031     delete layer;
1032 }
1033
1034 void GraphicsContext::clearRect(const FloatRect& rect)
1035 {
1036     if (paintingDisabled())
1037         return;
1038
1039     QPainter* p = m_data->p();
1040     QPainter::CompositionMode currentCompositionMode = p->compositionMode();
1041     p->setCompositionMode(QPainter::CompositionMode_Source);
1042     p->fillRect(rect, Qt::transparent);
1043     p->setCompositionMode(currentCompositionMode);
1044 }
1045
1046 void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
1047 {
1048     if (paintingDisabled())
1049         return;
1050
1051     Path path;
1052     path.addRect(rect);
1053
1054     float previousStrokeThickness = strokeThickness();
1055
1056     if (lineWidth != previousStrokeThickness)
1057         setStrokeThickness(lineWidth);
1058
1059     strokePath(path);
1060
1061     if (lineWidth != previousStrokeThickness)
1062         setStrokeThickness(previousStrokeThickness);
1063 }
1064
1065 void GraphicsContext::setLineCap(LineCap lc)
1066 {
1067     if (paintingDisabled())
1068         return;
1069
1070     QPainter* p = m_data->p();
1071     QPen nPen = p->pen();
1072     nPen.setCapStyle(toQtLineCap(lc));
1073     p->setPen(nPen);
1074 }
1075
1076 void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
1077 {
1078     QPainter* p = m_data->p();
1079     QPen pen = p->pen();
1080     unsigned dashLength = dashes.size();
1081     if (dashLength) {
1082         QVector<qreal> pattern;
1083         unsigned count = dashLength;
1084         if (dashLength % 2)
1085             count *= 2;
1086
1087         float penWidth = narrowPrecisionToFloat(double(pen.widthF()));
1088         for (unsigned i = 0; i < count; i++)
1089             pattern.append(dashes[i % dashLength] / penWidth);
1090
1091         pen.setDashPattern(pattern);
1092         pen.setDashOffset(dashOffset / penWidth);
1093     } else
1094         pen.setStyle(Qt::SolidLine);
1095     p->setPen(pen);
1096 }
1097
1098 void GraphicsContext::setLineJoin(LineJoin lj)
1099 {
1100     if (paintingDisabled())
1101         return;
1102
1103     QPainter* p = m_data->p();
1104     QPen nPen = p->pen();
1105     nPen.setJoinStyle(toQtLineJoin(lj));
1106     p->setPen(nPen);
1107 }
1108
1109 void GraphicsContext::setMiterLimit(float limit)
1110 {
1111     if (paintingDisabled())
1112         return;
1113
1114     QPainter* p = m_data->p();
1115     QPen nPen = p->pen();
1116     nPen.setMiterLimit(limit);
1117     p->setPen(nPen);
1118 }
1119
1120 void GraphicsContext::setAlpha(float opacity)
1121 {
1122     if (paintingDisabled())
1123         return;
1124     QPainter* p = m_data->p();
1125     p->setOpacity(opacity);
1126 }
1127
1128 void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
1129 {
1130     if (paintingDisabled())
1131         return;
1132
1133     m_data->p()->setCompositionMode(toQtCompositionMode(op));
1134 }
1135
1136 void GraphicsContext::clip(const Path& path)
1137 {
1138     if (paintingDisabled())
1139         return;
1140
1141     QPainterPath clipPath = path.platformPath();
1142     clipPath.setFillRule(Qt::WindingFill);
1143     m_data->p()->setClipPath(clipPath, Qt::IntersectClip);
1144 }
1145
1146 void GraphicsContext::canvasClip(const Path& path)
1147 {
1148     clip(path);
1149 }
1150
1151 void GraphicsContext::clipOut(const Path& path)
1152 {
1153     if (paintingDisabled())
1154         return;
1155
1156     QPainter* p = m_data->p();
1157     QPainterPath clippedOut = path.platformPath();
1158     QPainterPath newClip;
1159     newClip.setFillRule(Qt::OddEvenFill);
1160     if (p->hasClipping()) {
1161         newClip.addRect(m_data->clipBoundingRect());
1162         newClip.addPath(clippedOut);
1163         p->setClipPath(newClip, Qt::IntersectClip);
1164     } else {
1165         QRect windowRect = p->transform().inverted().mapRect(p->window());
1166         newClip.addRect(windowRect);
1167         newClip.addPath(clippedOut.intersected(newClip));
1168         p->setClipPath(newClip);
1169     }
1170 }
1171
1172 void GraphicsContext::translate(float x, float y)
1173 {
1174     if (paintingDisabled())
1175         return;
1176
1177     m_data->p()->translate(x, y);
1178 }
1179
1180 void GraphicsContext::rotate(float radians)
1181 {
1182     if (paintingDisabled())
1183         return;
1184
1185     m_data->p()->rotate(rad2deg(qreal(radians)));
1186 }
1187
1188 void GraphicsContext::scale(const FloatSize& s)
1189 {
1190     if (paintingDisabled())
1191         return;
1192
1193     m_data->p()->scale(s.width(), s.height());
1194 }
1195
1196 void GraphicsContext::clipOut(const IntRect& rect)
1197 {
1198     if (paintingDisabled())
1199         return;
1200
1201     QPainter* p = m_data->p();
1202     QPainterPath newClip;
1203     newClip.setFillRule(Qt::OddEvenFill);
1204     if (p->hasClipping()) {
1205         newClip.addRect(m_data->clipBoundingRect());
1206         newClip.addRect(QRect(rect));
1207         p->setClipPath(newClip, Qt::IntersectClip);
1208     } else {
1209         QRect clipOutRect(rect);
1210         QRect window = p->transform().inverted().mapRect(p->window());
1211         clipOutRect &= window;
1212         newClip.addRect(window);
1213         newClip.addRect(clipOutRect);
1214         p->setClipPath(newClip);
1215     }
1216 }
1217
1218 void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect,
1219                                               int thickness)
1220 {
1221     if (paintingDisabled())
1222         return;
1223
1224     clip(rect);
1225     QPainterPath path;
1226
1227     // Add outer ellipse
1228     path.addEllipse(QRectF(rect.x(), rect.y(), rect.width(), rect.height()));
1229
1230     // Add inner ellipse.
1231     path.addEllipse(QRectF(rect.x() + thickness, rect.y() + thickness,
1232                            rect.width() - (thickness * 2), rect.height() - (thickness * 2)));
1233
1234     path.setFillRule(Qt::OddEvenFill);
1235
1236     QPainter* p = m_data->p();
1237
1238     const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
1239     p->setRenderHint(QPainter::Antialiasing, true);
1240     p->setClipPath(path, Qt::IntersectClip);
1241     p->setRenderHint(QPainter::Antialiasing, antiAlias);
1242 }
1243
1244 void GraphicsContext::concatCTM(const AffineTransform& transform)
1245 {
1246     if (paintingDisabled())
1247         return;
1248
1249     m_data->p()->setWorldTransform(transform, true);
1250 }
1251
1252 void GraphicsContext::setCTM(const AffineTransform& transform)
1253 {
1254     if (paintingDisabled())
1255         return;
1256
1257     m_data->p()->setWorldTransform(transform);
1258 }
1259
1260 void GraphicsContext::setURLForRect(const KURL&, const IntRect&)
1261 {
1262     notImplemented();
1263 }
1264
1265 void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace)
1266 {
1267     if (paintingDisabled() || !color.isValid())
1268         return;
1269
1270     QPainter* p = m_data->p();
1271     QPen newPen(p->pen());
1272     m_data->solidColor.setColor(color);
1273     newPen.setBrush(m_data->solidColor);
1274     p->setPen(newPen);
1275 }
1276
1277 void GraphicsContext::setPlatformStrokeStyle(StrokeStyle strokeStyle)
1278 {
1279     if (paintingDisabled())
1280         return;
1281     QPainter* p = m_data->p();
1282     QPen newPen(p->pen());
1283     newPen.setStyle(toQPenStyle(strokeStyle));
1284     p->setPen(newPen);
1285 }
1286
1287 void GraphicsContext::setPlatformStrokeThickness(float thickness)
1288 {
1289     if (paintingDisabled())
1290         return;
1291     QPainter* p = m_data->p();
1292     QPen newPen(p->pen());
1293     newPen.setWidthF(thickness);
1294     p->setPen(newPen);
1295 }
1296
1297 void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
1298 {
1299     if (paintingDisabled() || !color.isValid())
1300         return;
1301
1302     m_data->solidColor.setColor(color);
1303     m_data->p()->setBrush(m_data->solidColor);
1304 }
1305
1306 void GraphicsContext::setPlatformShouldAntialias(bool enable)
1307 {
1308     if (paintingDisabled())
1309         return;
1310     m_data->p()->setRenderHint(QPainter::Antialiasing, enable);
1311 }
1312
1313 #ifdef Q_WS_WIN
1314
1315 HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
1316 {
1317     // painting through native HDC is only supported for plugin, where mayCreateBitmap is always true
1318     Q_ASSERT(mayCreateBitmap);
1319
1320     if (dstRect.isEmpty())
1321         return 0;
1322
1323     // Create a bitmap DC in which to draw.
1324     BITMAPINFO bitmapInfo;
1325     bitmapInfo.bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
1326     bitmapInfo.bmiHeader.biWidth         = dstRect.width();
1327     bitmapInfo.bmiHeader.biHeight        = dstRect.height();
1328     bitmapInfo.bmiHeader.biPlanes        = 1;
1329     bitmapInfo.bmiHeader.biBitCount      = 32;
1330     bitmapInfo.bmiHeader.biCompression   = BI_RGB;
1331     bitmapInfo.bmiHeader.biSizeImage     = 0;
1332     bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
1333     bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
1334     bitmapInfo.bmiHeader.biClrUsed       = 0;
1335     bitmapInfo.bmiHeader.biClrImportant  = 0;
1336
1337     void* pixels = 0;
1338     HBITMAP bitmap = ::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
1339     if (!bitmap)
1340         return 0;
1341
1342     HDC displayDC = ::GetDC(0);
1343     HDC bitmapDC = ::CreateCompatibleDC(displayDC);
1344     ::ReleaseDC(0, displayDC);
1345
1346     ::SelectObject(bitmapDC, bitmap);
1347
1348     // Fill our buffer with clear if we're going to alpha blend.
1349     if (supportAlphaBlend) {
1350         BITMAP bmpInfo;
1351         GetObject(bitmap, sizeof(bmpInfo), &bmpInfo);
1352         int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
1353         memset(bmpInfo.bmBits, 0, bufferSize);
1354     }
1355
1356 #if !OS(WINCE)
1357     // Make sure we can do world transforms.
1358     SetGraphicsMode(bitmapDC, GM_ADVANCED);
1359
1360     // Apply a translation to our context so that the drawing done will be at (0,0) of the bitmap.
1361     XFORM xform;
1362     xform.eM11 = 1.0f;
1363     xform.eM12 = 0.0f;
1364     xform.eM21 = 0.0f;
1365     xform.eM22 = 1.0f;
1366     xform.eDx = -dstRect.x();
1367     xform.eDy = -dstRect.y();
1368     ::SetWorldTransform(bitmapDC, &xform);
1369 #endif
1370
1371     return bitmapDC;
1372 }
1373
1374 void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
1375 {
1376     // painting through native HDC is only supported for plugin, where mayCreateBitmap is always true
1377     Q_ASSERT(mayCreateBitmap);
1378
1379     if (hdc) {
1380
1381         if (!dstRect.isEmpty()) {
1382
1383             HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
1384             BITMAP info;
1385             GetObject(bitmap, sizeof(info), &info);
1386             ASSERT(info.bmBitsPixel == 32);
1387
1388             QPixmap pixmap = QPixmap::fromWinHBITMAP(bitmap, supportAlphaBlend ? QPixmap::PremultipliedAlpha : QPixmap::NoAlpha);
1389             m_data->p()->drawPixmap(dstRect, pixmap);
1390
1391             ::DeleteObject(bitmap);
1392         }
1393
1394         ::DeleteDC(hdc);
1395     }
1396 }
1397 #endif
1398
1399 void GraphicsContext::setImageInterpolationQuality(InterpolationQuality quality)
1400 {
1401     m_data->imageInterpolationQuality = quality;
1402
1403     switch (quality) {
1404     case InterpolationNone:
1405     case InterpolationLow:
1406         // use nearest-neigbor
1407         m_data->p()->setRenderHint(QPainter::SmoothPixmapTransform, false);
1408         break;
1409
1410     case InterpolationMedium:
1411     case InterpolationHigh:
1412         // use the filter
1413         m_data->p()->setRenderHint(QPainter::SmoothPixmapTransform, true);
1414         break;
1415
1416     case InterpolationDefault:
1417     default:
1418         m_data->p()->setRenderHint(QPainter::SmoothPixmapTransform, m_data->initialSmoothPixmapTransformHint);
1419         break;
1420     };
1421 }
1422
1423 InterpolationQuality GraphicsContext::imageInterpolationQuality() const
1424 {
1425     return m_data->imageInterpolationQuality;
1426 }
1427
1428 void GraphicsContext::takeOwnershipOfPlatformContext()
1429 {
1430     m_data->takeOwnershipOfPlatformContext();
1431 }
1432
1433 }
1434
1435 // vim: ts=4 sw=4 et