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