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