OSDN Git Service

Merge WebKit at r71558: Initial merge by git.
[android-x86/external-webkit.git] / WebCore / platform / graphics / qt / GraphicsContextQt.cpp
index 105d866..4f68577 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
  * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de>
+ * Copyright (C) 2010 Sencha, Inc.
  *
  * All rights reserved.
  *
@@ -42,6 +43,7 @@
 
 #include "AffineTransform.h"
 #include "Color.h"
+#include "ContextShadow.h"
 #include "FloatConversion.h"
 #include "Font.h"
 #include "GraphicsContextPrivate.h"
@@ -50,6 +52,7 @@
 #include "Path.h"
 #include "Pattern.h"
 #include "Pen.h"
+#include "TransparencyLayer.h"
 
 #include <QBrush>
 #include <QDebug>
@@ -69,7 +72,7 @@
 
 namespace WebCore {
 
-static inline QPainter::CompositionMode toQtCompositionMode(CompositeOperator op)
+QPainter::CompositionMode GraphicsContext::toQtCompositionMode(CompositeOperator op)
 {
     switch (op) {
     case CompositeClear:
@@ -166,59 +169,26 @@ static inline Qt::FillRule toQtFillRule(WindRule rule)
     return Qt::OddEvenFill;
 }
 
-struct TransparencyLayer : FastAllocBase {
-    TransparencyLayer(const QPainter* p, const QRect &rect)
-        : pixmap(rect.width(), rect.height())
-    {
-        offset = rect.topLeft();
-        pixmap.fill(Qt::transparent);
-        painter.begin(&pixmap);
-        painter.setRenderHint(QPainter::Antialiasing, p->testRenderHint(QPainter::Antialiasing));
-        painter.translate(-offset);
-        painter.setPen(p->pen());
-        painter.setBrush(p->brush());
-        painter.setTransform(p->transform(), true);
-        painter.setOpacity(p->opacity());
-        painter.setFont(p->font());
-        if (painter.paintEngine()->hasFeature(QPaintEngine::PorterDuff))
-            painter.setCompositionMode(p->compositionMode());
-        painter.setClipPath(p->clipPath());
-    }
-
-    TransparencyLayer()
-    {
-    }
-
-    QPixmap pixmap;
-    QPoint offset;
-    QPainter painter;
-    qreal opacity;
-private:
-    TransparencyLayer(const TransparencyLayer &) {}
-    TransparencyLayer & operator=(const TransparencyLayer &) { return *this; }
-};
-
 class GraphicsContextPlatformPrivate : public Noncopyable {
 public:
-    GraphicsContextPlatformPrivate(QPainter* painter);
+    GraphicsContextPlatformPrivate(QPainter*, const QColor& initialSolidColor);
     ~GraphicsContextPlatformPrivate();
 
-    inline QPainter* p()
+    inline QPainter* p() const
     {
-        if (layers.isEmpty()) {
-            if (redirect)
-                return redirect;
-
+        if (layers.isEmpty())
             return painter;
-        }
         return &layers.top()->painter;
     }
 
     bool antiAliasingForRectsAndLines;
 
     QStack<TransparencyLayer*> layers;
-    QPainter* redirect;
+    // Counting real layers. Required by inTransparencyLayer() calls
+    // For example, layers with valid alphaMask are not real layers
+    int layerCount;
 
+    // reuse this brush for solid color (to prevent expensive QBrush construction)
     QBrush solidColor;
 
     InterpolationQuality imageInterpolationQuality;
@@ -226,43 +196,71 @@ public:
     // Only used by SVG for now.
     QPainterPath currentPath;
 
+    ContextShadow shadow;
+    QStack<ContextShadow> shadowStack;
+
+    bool hasShadow() const
+    {
+        return shadow.m_type != ContextShadow::NoShadow;
+    }
+
+    inline void clearCurrentPath()
+    {
+        if (!currentPath.elementCount())
+            return;
+        currentPath = QPainterPath();
+    }
+
+    QRectF clipBoundingRect() const
+    {
+#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
+        return p()->clipBoundingRect();
+#else
+        return p()->clipRegion().boundingRect();
+#endif
+    }
+
 private:
     QPainter* painter;
 };
 
 
-GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p)
+GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p, const QColor& initialSolidColor)
+    : antiAliasingForRectsAndLines(false)
+    , layerCount(0)
+    , solidColor(initialSolidColor)
+    , imageInterpolationQuality(InterpolationDefault)
+    , painter(p)
 {
-    painter = p;
-    redirect = 0;
-
-    solidColor = QBrush(Qt::black);
+    if (!painter)
+        return;
 
-    imageInterpolationQuality = InterpolationDefault;
+    // Use the default the QPainter was constructed with.
+    antiAliasingForRectsAndLines = painter->testRenderHint(QPainter::Antialiasing);
 
-    if (painter) {
-        // use the default the QPainter was constructed with
-        antiAliasingForRectsAndLines = painter->testRenderHint(QPainter::Antialiasing);
-        // FIXME: Maybe only enable in SVG mode?
-        painter->setRenderHint(QPainter::Antialiasing, true);
-    } else
-        antiAliasingForRectsAndLines = false;
+    painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, true);
 }
 
 GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
 {
 }
 
-GraphicsContext::GraphicsContext(PlatformGraphicsContext* context)
+GraphicsContext::GraphicsContext(PlatformGraphicsContext* painter)
     : m_common(createGraphicsContextPrivate())
-    , m_data(new GraphicsContextPlatformPrivate(context))
+    , m_data(new GraphicsContextPlatformPrivate(painter, fillColor()))
 {
-    setPaintingDisabled(!context);
-    if (context) {
-        // Make sure the context starts in sync with our state.
-        setPlatformFillColor(fillColor(), DeviceColorSpace);
-        setPlatformStrokeColor(strokeColor(), DeviceColorSpace);
-    }
+    setPaintingDisabled(!painter);
+
+    if (!painter)
+        return;
+
+    // solidColor is initialized with the fillColor().
+    painter->setBrush(m_data->solidColor);
+
+    QPen pen(painter->pen());
+    pen.setColor(strokeColor());
+    pen.setJoinStyle(toQtLineJoin(MiterJoin));
+    painter->setPen(pen);
 }
 
 GraphicsContext::~GraphicsContext()
@@ -288,20 +286,34 @@ AffineTransform GraphicsContext::getCTM() const
 
 void GraphicsContext::savePlatformState()
 {
+    if (!m_data->layers.isEmpty() && !m_data->layers.top()->alphaMask.isNull())
+        ++m_data->layers.top()->saveCounter;
     m_data->p()->save();
+    m_data->shadowStack.push(m_data->shadow);
 }
 
 void GraphicsContext::restorePlatformState()
 {
+    if (!m_data->layers.isEmpty() && !m_data->layers.top()->alphaMask.isNull())
+        if (!--m_data->layers.top()->saveCounter)
+            endTransparencyLayer();
+
     m_data->p()->restore();
 
     if (!m_data->currentPath.isEmpty() && m_common->state.pathTransform.isInvertible()) {
         QTransform matrix = m_common->state.pathTransform;
         m_data->currentPath = m_data->currentPath * matrix;
     }
+
+    if (m_data->shadowStack.isEmpty())
+        m_data->shadow = ContextShadow();
+    else
+        m_data->shadow = m_data->shadowStack.pop();
 }
 
 // Draws a filled rectangle with a stroked border.
+// This is only used to draw borders (real fill is done via fillRect), and
+// thus it must not cast any shadow.
 void GraphicsContext::drawRect(const IntRect& rect)
 {
     if (paintingDisabled())
@@ -311,22 +323,13 @@ void GraphicsContext::drawRect(const IntRect& rect)
     const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
     p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines);
 
-    IntSize shadowSize;
-    int shadowBlur;
-    Color shadowColor;
-    if (getShadow(shadowSize, shadowBlur, shadowColor)) {
-        IntRect shadowRect = rect;
-        shadowRect.move(shadowSize.width(), shadowSize.height());
-        shadowRect.inflate(static_cast<int>(p->pen().widthF()));
-        p->fillRect(shadowRect, QColor(shadowColor));
-    }
-
     p->drawRect(rect);
 
     p->setRenderHint(QPainter::Antialiasing, antiAlias);
 }
 
 // This is only used to draw borders.
+// Must not cast any shadow.
 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
 {
     if (paintingDisabled())
@@ -334,7 +337,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
 
     StrokeStyle style = strokeStyle();
     Color color = strokeColor();
-    if (style == NoStroke || !color.alpha())
+    if (style == NoStroke)
         return;
 
     float width = strokeThickness();
@@ -348,17 +351,6 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
     p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines);
     adjustLineToPixelBoundaries(p1, p2, width, style);
 
-    IntSize shadowSize;
-    int shadowBlur;
-    Color shadowColor;
-    if (textDrawingMode() == cTextFill && getShadow(shadowSize, shadowBlur, shadowColor)) {
-        p->save();
-        p->translate(shadowSize.width(), shadowSize.height());
-        p->setPen(shadowColor);
-        p->drawLine(p1, p2);
-        p->restore();
-    }
-
     int patWidth = 0;
     switch (style) {
     case NoStroke:
@@ -409,7 +401,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
                     patternOffset = patWidth / 2;
             } else {
                 if (remainder)
-                    patternOffset = (patWidth - remainder)/2;
+                    patternOffset = (patWidth - remainder) / 2;
             }
         }
 
@@ -443,23 +435,21 @@ void GraphicsContext::drawEllipse(const IntRect& rect)
 
 void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
 {
-    if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f || !strokeColor().alpha())
+    if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f)
         return;
 
     QPainter* p = m_data->p();
     const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
     p->setRenderHint(QPainter::Antialiasing, true);
 
-    IntSize shadowSize;
-    int shadowBlur;
-    Color shadowColor;
     startAngle *= 16;
     angleSpan *= 16;
-    if (getShadow(shadowSize, shadowBlur, shadowColor)) {
+
+    if (m_data->hasShadow()) {
         p->save();
-        p->translate(shadowSize.width(), shadowSize.height());
+        p->translate(m_data->shadow.offset());
         QPen pen(p->pen());
-        pen.setColor(shadowColor);
+        pen.setColor(m_data->shadow.m_color);
         p->setPen(pen);
         p->drawArc(rect, startAngle, angleSpan);
         p->restore();
@@ -485,17 +475,14 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points
     QPainter* p = m_data->p();
     p->save();
     p->setRenderHint(QPainter::Antialiasing, shouldAntialias);
-    IntSize shadowSize;
-    int shadowBlur;
-    Color shadowColor;
-    if (getShadow(shadowSize, shadowBlur, shadowColor)) {
+    if (m_data->hasShadow()) {
         p->save();
-        p->translate(shadowSize.width(), shadowSize.height());
+        p->translate(m_data->shadow.offset());
         if (p->brush().style() != Qt::NoBrush)
-            p->setBrush(QBrush(shadowColor));
+            p->setBrush(QBrush(m_data->shadow.m_color));
         QPen pen(p->pen());
         if (pen.style() != Qt::NoPen) {
-            pen.setColor(shadowColor);
+            pen.setColor(m_data->shadow.m_color);
             p->setPen(pen);
         }
         p->drawConvexPolygon(polygon);
@@ -505,25 +492,30 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points
     p->restore();
 }
 
-QPen GraphicsContext::pen()
+void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
 {
     if (paintingDisabled())
-        return QPen();
+        return;
+
+    if (numPoints <= 1)
+        return;
+
+    QPainterPath path(points[0]);
+    for (size_t i = 1; i < numPoints; ++i)
+        path.lineTo(points[i]);
+    path.setFillRule(Qt::WindingFill);
 
     QPainter* p = m_data->p();
-    return p->pen();
-}
 
-static void inline drawFilledShadowPath(GraphicsContext* context, QPainter* p, const QPainterPath& path)
-{
-    IntSize shadowSize;
-    int shadowBlur;
-    Color shadowColor;
-    if (context->getShadow(shadowSize, shadowBlur, shadowColor)) {
-        p->translate(shadowSize.width(), shadowSize.height());
-        p->fillPath(path, QBrush(shadowColor));
-        p->translate(-shadowSize.width(), -shadowSize.height());
-    }
+    bool painterWasAntialiased = p->testRenderHint(QPainter::Antialiasing);
+
+    if (painterWasAntialiased != antialiased)
+        p->setRenderHint(QPainter::Antialiasing, antialiased);
+
+    p->setClipPath(path, Qt::IntersectClip);
+
+    if (painterWasAntialiased != antialiased)
+        p->setRenderHint(QPainter::Antialiasing, painterWasAntialiased);
 }
 
 void GraphicsContext::fillPath()
@@ -532,24 +524,25 @@ void GraphicsContext::fillPath()
         return;
 
     QPainter* p = m_data->p();
-    QPainterPath path = m_data->currentPath;
+    QPainterPath& path = m_data->currentPath; // Avoid detaching the QPainterPath
     path.setFillRule(toQtFillRule(fillRule()));
 
-    if (m_common->state.fillPattern || m_common->state.fillGradient || fillColor().alpha()) {
-        drawFilledShadowPath(this, p, path);
-        if (m_common->state.fillPattern) {
-            AffineTransform affine;
-            p->fillPath(path, QBrush(m_common->state.fillPattern->createPlatformPattern(affine)));
-        } else if (m_common->state.fillGradient) {
-            QBrush brush(*m_common->state.fillGradient->platformGradient());
-            brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform());
-            p->fillPath(path, brush);
-        } else {
-            if (fillColor().alpha())
-                p->fillPath(path, p->brush());
-        }
+    if (m_data->hasShadow()) {
+        p->translate(m_data->shadow.offset());
+        p->fillPath(path, QColor(m_data->shadow.m_color));
+        p->translate(-m_data->shadow.offset());
     }
-    m_data->currentPath = QPainterPath();
+    if (m_common->state.fillPattern) {
+        AffineTransform affine;
+        p->fillPath(path, QBrush(m_common->state.fillPattern->createPlatformPattern(affine)));
+    } else if (m_common->state.fillGradient) {
+        QBrush brush(*m_common->state.fillGradient->platformGradient());
+        brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform());
+        p->fillPath(path, brush);
+    } else
+        p->fillPath(path, p->brush());
+
+    m_data->clearCurrentPath();
 }
 
 void GraphicsContext::strokePath()
@@ -559,49 +552,96 @@ void GraphicsContext::strokePath()
 
     QPainter* p = m_data->p();
     QPen pen(p->pen());
-    QPainterPath path = m_data->currentPath;
+    QPainterPath& path = m_data->currentPath; // Avoid detaching the QPainterPath
     path.setFillRule(toQtFillRule(fillRule()));
 
-    if (m_common->state.strokePattern || m_common->state.strokeGradient || strokeColor().alpha()) {
-        IntSize shadowSize;
-        int shadowBlur;
-        Color shadowColor;
-        if (getShadow(shadowSize, shadowBlur, shadowColor)) {
-            QTransform t(p->worldTransform());
-            p->translate(shadowSize.width(), shadowSize.height());
-            QPen shadowPen(pen);
-            shadowPen.setColor(shadowColor);
-            p->strokePath(path, shadowPen);
-            p->setWorldTransform(t);
-        }
-        if (m_common->state.strokePattern) {
-            AffineTransform affine;
-            pen.setBrush(QBrush(m_common->state.strokePattern->createPlatformPattern(affine)));
-            p->setPen(pen);
-            p->strokePath(path, pen);
-        } else if (m_common->state.strokeGradient) {
-            QBrush brush(*m_common->state.strokeGradient->platformGradient());
-            brush.setTransform(m_common->state.strokeGradient->gradientSpaceTransform());
-            pen.setBrush(brush);
-            p->setPen(pen);
-            p->strokePath(path, pen);
+    if (m_data->hasShadow()) {
+        p->translate(m_data->shadow.offset());
+        QPen shadowPen(pen);
+        shadowPen.setColor(m_data->shadow.m_color);
+        p->strokePath(path, shadowPen);
+        p->translate(-m_data->shadow.offset());
+    }
+    if (m_common->state.strokePattern) {
+        AffineTransform affine;
+        pen.setBrush(QBrush(m_common->state.strokePattern->createPlatformPattern(affine)));
+        p->setPen(pen);
+        p->strokePath(path, pen);
+    } else if (m_common->state.strokeGradient) {
+        QBrush brush(*m_common->state.strokeGradient->platformGradient());
+        brush.setTransform(m_common->state.strokeGradient->gradientSpaceTransform());
+        pen.setBrush(brush);
+        p->setPen(pen);
+        p->strokePath(path, pen);
+    } else
+        p->strokePath(path, pen);
+    m_data->clearCurrentPath();
+}
+
+static inline void drawRepeatPattern(QPainter* p, QPixmap* image, const FloatRect& rect, const bool repeatX, const bool repeatY)
+{
+    // Patterns must be painted so that the top left of the first image is anchored at
+    // the origin of the coordinate space
+    if (image) {
+        int w = image->width();
+        int h = image->height();
+        int startX, startY;
+        QRect r(static_cast<int>(rect.x()), static_cast<int>(rect.y()), static_cast<int>(rect.width()), static_cast<int>(rect.height()));
+
+        // startX, startY is the coordinate of the first image we need to put on the left-top of the rect
+        if (repeatX && repeatY) {
+            // repeat
+            // startX, startY is at the left top side of the left-top of the rect
+            startX = r.x() >=0 ? r.x() - (r.x() % w) : r.x() - (w - qAbs(r.x()) % w);
+            startY = r.y() >=0 ? r.y() - (r.y() % h) : r.y() - (h - qAbs(r.y()) % h);
         } else {
-            if (strokeColor().alpha())
-                p->strokePath(path, pen);
+           if (!repeatX && !repeatY) {
+               // no-repeat
+               // only draw the image once at orgin once, check if need to draw
+               QRect imageRect(0, 0, w, h);
+               if (imageRect.intersects(r)) {
+                   startX = 0;
+                   startY = 0;
+               } else
+                   return;   
+           } else if (repeatX && !repeatY) {
+               // repeat-x
+               // startY is fixed, but startX change based on the left-top of the rect
+               QRect imageRect(r.x(), 0, r.width(), h);
+               if (imageRect.intersects(r)) {
+                   startX = r.x() >=0 ? r.x() - (r.x() % w) : r.x() - (w - qAbs(r.x()) % w);
+                   startY = 0;
+               } else
+                   return;
+           } else {
+               // repeat-y
+               // startX is fixed, but startY change based on the left-top of the rect
+               QRect imageRect(0, r.y(), w, r.height());
+               if (imageRect.intersects(r)) {
+                   startX = 0;
+                   startY = r.y() >=0 ? r.y() - (r.y() % h) : r.y() - (h - qAbs(r.y()) % h);
+               } else
+                   return;
+           }
         }
-    }
-    m_data->currentPath = QPainterPath();
-}
 
-static inline void drawBorderlessRectShadow(GraphicsContext* context, QPainter* p, const FloatRect& rect)
-{
-    IntSize shadowSize;
-    int shadowBlur;
-    Color shadowColor;
-    if (context->getShadow(shadowSize, shadowBlur, shadowColor)) {
-        FloatRect shadowRect(rect);
-        shadowRect.move(shadowSize.width(), shadowSize.height());
-        p->fillRect(shadowRect, QColor(shadowColor));
+        int x = startX;
+        int y = startY; 
+        do {
+            // repeat Y
+            do {
+                // repeat X
+                QRect   imageRect(x, y, w, h);
+                QRect   intersectRect = imageRect.intersected(r);
+                QPoint  destStart(intersectRect.x(), intersectRect.y());
+                QRect   sourceRect(intersectRect.x() - imageRect.x(), intersectRect.y() - imageRect.y(), intersectRect.width(), intersectRect.height());
+
+                p->drawPixmap(destStart, *image, sourceRect);
+                x += w;
+            } while (repeatX && x < r.x() + r.width());
+            x = startX;
+            y += h;
+        } while (repeatY && y < r.y() + r.height());
     }
 }
 
@@ -611,60 +651,126 @@ void GraphicsContext::fillRect(const FloatRect& rect)
         return;
 
     QPainter* p = m_data->p();
-
-    if (m_common->state.fillPattern || m_common->state.fillGradient || fillColor().alpha()) {
-        drawBorderlessRectShadow(this, p, rect);
-        if (m_common->state.fillPattern) {
-            AffineTransform affine;
-            p->fillRect(rect, QBrush(m_common->state.fillPattern->createPlatformPattern(affine)));
-        } else if (m_common->state.fillGradient) {
-            QBrush brush(*m_common->state.fillGradient->platformGradient());
-            brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform());
-            p->fillRect(rect, brush);
-        } else {
-            if (fillColor().alpha())
-                p->fillRect(rect, p->brush());
+    QRectF normalizedRect = rect.normalized();
+    ContextShadow* shadow = contextShadow();
+
+    if (m_common->state.fillPattern) {
+        AffineTransform affine;
+        QBrush brush(m_common->state.fillPattern->createPlatformPattern(affine));
+        QPixmap* image = m_common->state.fillPattern->tileImage()->nativeImageForCurrentFrame();
+        QPainter* shadowPainter = m_data->hasShadow() ? shadow->beginShadowLayer(p, normalizedRect) : 0;
+        if (shadowPainter) {
+            drawRepeatPattern(shadowPainter, image, normalizedRect, m_common->state.fillPattern->repeatX(), m_common->state.fillPattern->repeatY());
+            shadowPainter->setCompositionMode(QPainter::CompositionMode_SourceIn);
+            shadowPainter->fillRect(normalizedRect, shadow->m_color);
+            shadow->endShadowLayer(p);
         }
+        drawRepeatPattern(p, image, normalizedRect, m_common->state.fillPattern->repeatX(), m_common->state.fillPattern->repeatY());
+    } else if (m_common->state.fillGradient) {
+        QBrush brush(*m_common->state.fillGradient->platformGradient());
+        brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform());
+        QPainter* shadowPainter = m_data->hasShadow() ? shadow->beginShadowLayer(p, normalizedRect) : 0;
+        if (shadowPainter) {
+            shadowPainter->fillRect(normalizedRect, brush);
+            shadowPainter->setCompositionMode(QPainter::CompositionMode_SourceIn);
+            shadowPainter->fillRect(normalizedRect, shadow->m_color);
+            shadow->endShadowLayer(p);
+        }
+        p->fillRect(normalizedRect, brush);
+    } else {
+        if (m_data->hasShadow()) {
+            if (shadow->m_type == ContextShadow::BlurShadow) {
+                QPainter* shadowPainter = shadow->beginShadowLayer(p, normalizedRect);
+                if (shadowPainter) {
+                    shadowPainter->fillRect(normalizedRect, p->brush());
+                    shadow->endShadowLayer(p);
+                }
+            } else {
+                // Solid rectangle fill with no blur shadow can be done faster
+                // without using the shadow layer at all.
+                QColor shadowColor = shadow->m_color;
+                shadowColor.setAlphaF(shadowColor.alphaF() * p->brush().color().alphaF());
+                p->fillRect(normalizedRect.translated(shadow->offset()), shadowColor);
+            }
+        }
+        p->fillRect(normalizedRect, p->brush());
     }
 }
 
-void GraphicsContext::fillRect(const FloatRect& rect, const Color& c, ColorSpace colorSpace)
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
 {
-    if (paintingDisabled())
+    if (paintingDisabled() || !color.isValid())
         return;
 
-    m_data->solidColor.setColor(c);
+    m_data->solidColor.setColor(color);
     QPainter* p = m_data->p();
-    drawBorderlessRectShadow(this, p, rect);
-    p->fillRect(rect, m_data->solidColor);
+    QRectF normalizedRect = rect.normalized();
+
+    if (m_data->hasShadow()) {
+        ContextShadow* shadow = contextShadow();
+
+        if (shadow->m_type != ContextShadow::BlurShadow) {
+            // We do not need any layer for simple shadow.
+            p->fillRect(normalizedRect.translated(shadow->offset()), shadow->m_color);
+        } else {
+            QPainter* shadowPainter = shadow->beginShadowLayer(p, normalizedRect);
+            if (shadowPainter) {
+                shadowPainter->setCompositionMode(QPainter::CompositionMode_Source);
+                shadowPainter->fillRect(normalizedRect, shadow->m_color);
+                shadow->endShadowLayer(p);
+            }
+        }
+    }
+
+    p->fillRect(normalizedRect, m_data->solidColor);
 }
 
 void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
 {
-    if (paintingDisabled() || !color.alpha())
+    if (paintingDisabled() || !color.isValid())
         return;
 
-    Path path = Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight);
+    Path path;
+    path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
     QPainter* p = m_data->p();
-    drawFilledShadowPath(this, p, path.platformPath());
+    if (m_data->hasShadow()) {
+        ContextShadow* shadow = contextShadow();
+
+        if (shadow->m_type != ContextShadow::BlurShadow) {
+            // We do not need any layer for simple shadow.
+            p->translate(m_data->shadow.offset());
+            p->fillPath(path.platformPath(), QColor(m_data->shadow.m_color));
+            p->translate(-m_data->shadow.offset());
+        } else {
+            QPainter* shadowPainter = shadow->beginShadowLayer(p, rect);
+            if (shadowPainter) {
+                shadowPainter->setCompositionMode(QPainter::CompositionMode_Source);
+                shadowPainter->fillPath(path.platformPath(), QColor(m_data->shadow.m_color));
+                shadow->endShadowLayer(p);
+            }
+        }
+    }
     p->fillPath(path.platformPath(), QColor(color));
 }
 
 void GraphicsContext::beginPath()
 {
-    m_data->currentPath = QPainterPath();
+    m_data->clearCurrentPath();
 }
 
 void GraphicsContext::addPath(const Path& path)
 {
-    QPainterPath newPath = m_data->currentPath;
-    newPath.addPath(path.platformPath());
-    m_data->currentPath = newPath;
+    if (!m_data->currentPath.elementCount()) {
+        m_data->currentPath = path.platformPath();
+        return;
+    }
+    m_data->currentPath.addPath(path.platformPath());
 }
 
 bool GraphicsContext::inTransparencyLayer() const
 {
-    return !m_data->layers.isEmpty();
+    return m_data->layerCount;
 }
 
 PlatformPath* GraphicsContext::currentPath()
@@ -672,6 +778,11 @@ PlatformPath* GraphicsContext::currentPath()
     return &m_data->currentPath;
 }
 
+ContextShadow* GraphicsContext::contextShadow()
+{
+    return &m_data->shadow;
+}
+
 void GraphicsContext::clip(const FloatRect& rect)
 {
     if (paintingDisabled())
@@ -688,7 +799,7 @@ void GraphicsContext::clipPath(WindRule clipRule)
     QPainter* p = m_data->p();
     QPainterPath newPath = m_data->currentPath;
     newPath.setFillRule(clipRule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill);
-    p->setClipPath(newPath);
+    p->setClipPath(newPath, Qt::IntersectClip);
 }
 
 void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color)
@@ -703,7 +814,7 @@ void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int of
  */
 void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int /* width */, int /* offset */, const Color& color)
 {
-    if (paintingDisabled())
+    if (paintingDisabled() || !color.isValid())
         return;
 
     unsigned rectCount = rects.size();
@@ -746,11 +857,31 @@ void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool)
     if (paintingDisabled())
         return;
 
+    IntPoint startPoint = origin;
     IntPoint endPoint = origin + IntSize(width, 0);
-    drawLine(origin, endPoint);
+
+    // If paintengine type is X11 to avoid artifacts
+    // like bug https://bugs.webkit.org/show_bug.cgi?id=42248
+#if defined(Q_WS_X11)
+    QPainter* p = m_data->p();
+    if (p->paintEngine()->type() == QPaintEngine::X11) {
+        // If stroke thickness is odd we need decrease Y coordinate by 1 pixel,
+        // because inside method adjustLineToPixelBoundaries(...), which
+        // called from drawLine(...), Y coordinate will be increased by 0.5f
+        // and then inside Qt painting engine will be rounded to next greater
+        // integer value.
+        float strokeWidth = strokeThickness();
+        if (static_cast<int>(strokeWidth) % 2) {
+            startPoint.setY(startPoint.y() - 1);
+            endPoint.setY(endPoint.y() - 1);
+        }
+    }
+#endif // defined(Q_WS_X11)
+
+    drawLine(startPoint, endPoint);
 }
 
-void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int, bool)
+void GraphicsContext::drawLineForTextChecking(const IntPoint&, int, TextCheckingLineStyle)
 {
     if (paintingDisabled())
         return;
@@ -760,14 +891,33 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int, b
 
 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
 {
-    QRectF rect(frect);
-    rect = m_data->p()->deviceMatrix().mapRect(rect);
+    // It is not enough just to round to pixels in device space. The rotation part of the
+    // affine transform matrix to device space can mess with this conversion if we have a
+    // rotating image like the hands of the world clock widget. We just need the scale, so
+    // we get the affine transform matrix and extract the scale.
+    QPainter* painter = platformContext();
+    QTransform deviceTransform = painter->deviceTransform();
+    if (deviceTransform.isIdentity())
+        return frect;
+
+    qreal deviceScaleX = sqrtf(deviceTransform.m11() * deviceTransform.m11() + deviceTransform.m12() * deviceTransform.m12());
+    qreal deviceScaleY = sqrtf(deviceTransform.m21() * deviceTransform.m21() + deviceTransform.m22() * deviceTransform.m22());
+
+    QPoint deviceOrigin(frect.x() * deviceScaleX, frect.y() * deviceScaleY);
+    QPoint deviceLowerRight(frect.right() * deviceScaleX, frect.bottom() * deviceScaleY);
+
+    // Don't let the height or width round to 0 unless either was originally 0
+    if (deviceOrigin.y() == deviceLowerRight.y() && frect.height())
+        deviceLowerRight.setY(deviceLowerRight.y() + 1);
+    if (deviceOrigin.x() == deviceLowerRight.x() && frect.width())
+        deviceLowerRight.setX(deviceLowerRight.x() + 1);
 
-    QRect result = rect.toRect(); //round it
-    return FloatRect(QRectF(result));
+    FloatPoint roundedOrigin = FloatPoint(deviceOrigin.x() / deviceScaleX, deviceOrigin.y() / deviceScaleY);
+    FloatPoint roundedLowerRight = FloatPoint(deviceLowerRight.x() / deviceScaleX, deviceLowerRight.y() / deviceScaleY);
+    return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin);
 }
 
-void GraphicsContext::setPlatformShadow(const IntSize& size, int, const Color&, ColorSpace)
+void GraphicsContext::setPlatformShadow(const FloatSize& size, float blur, const Color& color, ColorSpace)
 {
     // Qt doesn't support shadows natively, they are drawn manually in the draw*
     // functions
@@ -775,14 +925,21 @@ void GraphicsContext::setPlatformShadow(const IntSize& size, int, const Color&,
     if (m_common->state.shadowsIgnoreTransforms) {
         // Meaning that this graphics context is associated with a CanvasRenderingContext
         // We flip the height since CG and HTML5 Canvas have opposite Y axis
-        m_common->state.shadowSize = IntSize(size.width(), -size.height());
+        m_common->state.shadowOffset = FloatSize(size.width(), -size.height());
+        m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), -size.height()));
+    } else {
+        m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), size.height()));
     }
 }
 
 void GraphicsContext::clearPlatformShadow()
 {
-    // Qt doesn't support shadows natively, they are drawn manually in the draw*
-    // functions
+    m_data->shadow.clear();
+}
+
+void GraphicsContext::pushTransparencyLayerInternal(const QRect &rect, qreal opacity, QPixmap& alphaMask)
+{
+   m_data->layers.push(new TransparencyLayer(m_data->p(), m_data->p()->transform().mapRect(rect), 1.0, alphaMask));
 }
 
 void GraphicsContext::beginTransparencyLayer(float opacity)
@@ -797,17 +954,16 @@ void GraphicsContext::beginTransparencyLayer(float opacity)
     w = device->width();
     h = device->height();
 
-    QRectF clip = p->clipPath().boundingRect();
+    QRectF clip = m_data->clipBoundingRect();
     QRectF deviceClip = p->transform().mapRect(clip);
     x = int(qBound(qreal(0), deviceClip.x(), (qreal)w));
     y = int(qBound(qreal(0), deviceClip.y(), (qreal)h));
     w = int(qBound(qreal(0), deviceClip.width(), (qreal)w) + 2);
     h = int(qBound(qreal(0), deviceClip.height(), (qreal)h) + 2);
 
-    TransparencyLayer * layer = new TransparencyLayer(m_data->p(), QRect(x, y, w, h));
-
-    layer->opacity = opacity;
-    m_data->layers.push(layer);
+    QPixmap emptyAlphaMask;
+    m_data->layers.push(new TransparencyLayer(m_data->p(), QRect(x, y, w, h), opacity, emptyAlphaMask));
+    ++m_data->layerCount;
 }
 
 void GraphicsContext::endTransparencyLayer()
@@ -816,6 +972,12 @@ void GraphicsContext::endTransparencyLayer()
         return;
 
     TransparencyLayer* layer = m_data->layers.pop();
+    if (!layer->alphaMask.isNull()) {
+        layer->painter.resetTransform();
+        layer->painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
+        layer->painter.drawPixmap(QPoint(), layer->alphaMask);
+    } else
+        --m_data->layerCount; // see the comment for layerCount
     layer->painter.end();
 
     QPainter* p = m_data->p();
@@ -882,8 +1044,9 @@ void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
             pattern.append(dashes[i % dashLength] / penWidth);
 
         pen.setDashPattern(pattern);
-        pen.setDashOffset(dashOffset);
-    }
+        pen.setDashOffset(dashOffset / penWidth);
+    } else
+        pen.setStyle(Qt::SolidLine);
     p->setPen(pen);
 }
 
@@ -936,7 +1099,12 @@ void GraphicsContext::clip(const Path& path)
 
 void GraphicsContext::canvasClip(const Path& path)
 {
-    clip(path);
+    if (paintingDisabled())
+        return;
+
+    QPainterPath clipPath = path.platformPath();
+    clipPath.setFillRule(Qt::WindingFill);
+    m_data->p()->setClipPath(clipPath, Qt::IntersectClip);
 }
 
 void GraphicsContext::clipOut(const Path& path)
@@ -949,11 +1117,12 @@ void GraphicsContext::clipOut(const Path& path)
     QPainterPath newClip;
     newClip.setFillRule(Qt::OddEvenFill);
     if (p->hasClipping()) {
-        newClip.addRect(p->clipRegion().boundingRect());
+        newClip.addRect(m_data->clipBoundingRect());
         newClip.addPath(clippedOut);
         p->setClipPath(newClip, Qt::IntersectClip);
     } else {
-        newClip.addRect(p->window());
+        QRect windowRect = p->transform().inverted().mapRect(p->window());
+        newClip.addRect(windowRect);
         newClip.addPath(clippedOut.intersected(newClip));
         p->setClipPath(newClip);
     }
@@ -973,24 +1142,16 @@ void GraphicsContext::translate(float x, float y)
     }
 }
 
-IntPoint GraphicsContext::origin()
-{
-    if (paintingDisabled())
-        return IntPoint();
-    const QTransform &transform = m_data->p()->transform();
-    return IntPoint(qRound(transform.dx()), qRound(transform.dy()));
-}
-
 void GraphicsContext::rotate(float radians)
 {
     if (paintingDisabled())
         return;
 
-    m_data->p()->rotate(180/M_PI*radians);
+    m_data->p()->rotate(180 / M_PI*radians);
 
     if (!m_data->currentPath.isEmpty()) {
         QTransform matrix;
-        m_data->currentPath = m_data->currentPath * matrix.rotate(-180/M_PI*radians);
+        m_data->currentPath = m_data->currentPath * matrix.rotate(-180 / M_PI*radians);
         m_common->state.pathTransform.rotate(radians);
     }
 }
@@ -1018,12 +1179,12 @@ void GraphicsContext::clipOut(const IntRect& rect)
     QPainterPath newClip;
     newClip.setFillRule(Qt::OddEvenFill);
     if (p->hasClipping()) {
-        newClip.addRect(p->clipRegion().boundingRect());
+        newClip.addRect(m_data->clipBoundingRect());
         newClip.addRect(QRect(rect));
         p->setClipPath(newClip, Qt::IntersectClip);
     } else {
         QRect clipOutRect(rect);
-        QRect window(p->window());
+        QRect window = p->transform().inverted().mapRect(p->window());
         clipOutRect &= window;
         newClip.addRect(window);
         newClip.addRect(clipOutRect);
@@ -1031,33 +1192,6 @@ void GraphicsContext::clipOut(const IntRect& rect)
     }
 }
 
-void GraphicsContext::clipOutEllipseInRect(const IntRect& rect)
-{
-    if (paintingDisabled())
-        return;
-
-    QPainter* p = m_data->p();
-    QPainterPath newClip;
-    newClip.setFillRule(Qt::OddEvenFill);
-    if (p->hasClipping()) {
-        newClip.addRect(p->clipRegion().boundingRect());
-        newClip.addEllipse(QRect(rect));
-        p->setClipPath(newClip, Qt::IntersectClip);
-    } else {
-        QRect clipOutRect(rect);
-        QRect window(p->window());
-        clipOutRect &= window;
-        newClip.addRect(window);
-        newClip.addEllipse(clipOutRect);
-        p->setClipPath(newClip);
-    }
-}
-
-void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*)
-{
-    notImplemented();
-}
-
 void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect,
                                               int thickness)
 {
@@ -1108,11 +1242,13 @@ void GraphicsContext::setURLForRect(const KURL&, const IntRect&)
 
 void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace)
 {
-    if (paintingDisabled())
+    if (paintingDisabled() || !color.isValid())
         return;
+
     QPainter* p = m_data->p();
     QPen newPen(p->pen());
-    newPen.setColor(color);
+    m_data->solidColor.setColor(color);
+    newPen.setBrush(m_data->solidColor);
     p->setPen(newPen);
 }
 
@@ -1138,8 +1274,9 @@ void GraphicsContext::setPlatformStrokeThickness(float thickness)
 
 void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
 {
-    if (paintingDisabled())
+    if (paintingDisabled() || !color.isValid())
         return;
+
     m_data->solidColor.setColor(color);
     m_data->p()->setBrush(m_data->solidColor);
 }
@@ -1242,13 +1379,13 @@ void GraphicsContext::setImageInterpolationQuality(InterpolationQuality quality)
     m_data->imageInterpolationQuality = quality;
 
     switch (quality) {
-    case InterpolationDefault:
     case InterpolationNone:
     case InterpolationLow:
         // use nearest-neigbor
         m_data->p()->setRenderHint(QPainter::SmoothPixmapTransform, false);
         break;
 
+    case InterpolationDefault:
     case InterpolationMedium:
     case InterpolationHigh:
     default: