OSDN Git Service

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