OSDN Git Service

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