OSDN Git Service

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