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