OSDN Git Service

Merge WebKit at r71558: Initial merge by git.
[android-x86/external-webkit.git] / WebCore / platform / graphics / qt / GraphicsContextQt.cpp
index 1632804..4f68577 100644 (file)
@@ -171,17 +171,13 @@ static inline Qt::FillRule toQtFillRule(WindRule rule)
 
 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;
     }
 
@@ -191,7 +187,6 @@ public:
     // Counting real layers. Required by inTransparencyLayer() calls
     // For example, layers with valid alphaMask are not real layers
     int layerCount;
-    QPainter* redirect;
 
     // reuse this brush for solid color (to prevent expensive QBrush construction)
     QBrush solidColor;
@@ -206,7 +201,23 @@ public:
 
     bool hasShadow() const
     {
-        return shadow.type != ContextShadow::NoShadow;
+        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:
@@ -214,40 +225,42 @@ private:
 };
 
 
-GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p)
+GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p, const QColor& initialSolidColor)
+    : antiAliasingForRectsAndLines(false)
+    , layerCount(0)
+    , solidColor(initialSolidColor)
+    , imageInterpolationQuality(InterpolationDefault)
+    , painter(p)
 {
-    painter = p;
-    layerCount = 0;
-    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);
-        painter->setRenderHint(QPainter::SmoothPixmapTransform, 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()
@@ -434,9 +447,9 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp
 
     if (m_data->hasShadow()) {
         p->save();
-        p->translate(m_data->shadow.offset);
+        p->translate(m_data->shadow.offset());
         QPen pen(p->pen());
-        pen.setColor(m_data->shadow.color);
+        pen.setColor(m_data->shadow.m_color);
         p->setPen(pen);
         p->drawArc(rect, startAngle, angleSpan);
         p->restore();
@@ -464,12 +477,12 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points
     p->setRenderHint(QPainter::Antialiasing, shouldAntialias);
     if (m_data->hasShadow()) {
         p->save();
-        p->translate(m_data->shadow.offset);
+        p->translate(m_data->shadow.offset());
         if (p->brush().style() != Qt::NoBrush)
-            p->setBrush(QBrush(m_data->shadow.color));
+            p->setBrush(QBrush(m_data->shadow.m_color));
         QPen pen(p->pen());
         if (pen.style() != Qt::NoPen) {
-            pen.setColor(m_data->shadow.color);
+            pen.setColor(m_data->shadow.m_color);
             p->setPen(pen);
         }
         p->drawConvexPolygon(polygon);
@@ -491,16 +504,18 @@ void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* poin
     for (size_t i = 1; i < numPoints; ++i)
         path.lineTo(points[i]);
     path.setFillRule(Qt::WindingFill);
-    m_data->p()->setClipPath(path, Qt::IntersectClip);
-}
-
-QPen GraphicsContext::pen()
-{
-    if (paintingDisabled())
-        return QPen();
 
     QPainter* p = m_data->p();
-    return p->pen();
+
+    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()
@@ -513,9 +528,9 @@ void GraphicsContext::fillPath()
     path.setFillRule(toQtFillRule(fillRule()));
 
     if (m_data->hasShadow()) {
-        p->translate(m_data->shadow.offset);
-        p->fillPath(path, m_data->shadow.color);
-        p->translate(-m_data->shadow.offset);
+        p->translate(m_data->shadow.offset());
+        p->fillPath(path, QColor(m_data->shadow.m_color));
+        p->translate(-m_data->shadow.offset());
     }
     if (m_common->state.fillPattern) {
         AffineTransform affine;
@@ -527,7 +542,7 @@ void GraphicsContext::fillPath()
     } else
         p->fillPath(path, p->brush());
 
-    m_data->currentPath = QPainterPath();
+    m_data->clearCurrentPath();
 }
 
 void GraphicsContext::strokePath()
@@ -541,11 +556,11 @@ void GraphicsContext::strokePath()
     path.setFillRule(toQtFillRule(fillRule()));
 
     if (m_data->hasShadow()) {
-        p->translate(m_data->shadow.offset);
+        p->translate(m_data->shadow.offset());
         QPen shadowPen(pen);
-        shadowPen.setColor(m_data->shadow.color);
+        shadowPen.setColor(m_data->shadow.m_color);
         p->strokePath(path, shadowPen);
-        p->translate(-m_data->shadow.offset);
+        p->translate(-m_data->shadow.offset());
     }
     if (m_common->state.strokePattern) {
         AffineTransform affine;
@@ -560,7 +575,7 @@ void GraphicsContext::strokePath()
         p->strokePath(path, pen);
     } else
         p->strokePath(path, pen);
-    m_data->currentPath = QPainterPath();
+    m_data->clearCurrentPath();
 }
 
 static inline void drawRepeatPattern(QPainter* p, QPixmap* image, const FloatRect& rect, const bool repeatX, const bool repeatY)
@@ -636,56 +651,50 @@ void GraphicsContext::fillRect(const FloatRect& rect)
         return;
 
     QPainter* p = m_data->p();
-    FloatRect normalizedRect = rect.normalized();
-
-    QRectF shadowDestRect;
-    QImage* shadowImage = 0;
-    QPainter* pShadow = 0;
-
-    if (m_data->hasShadow()) {
-        shadowImage = new QImage(roundedIntSize(normalizedRect.size()), QImage::Format_ARGB32_Premultiplied);
-        pShadow = new QPainter(shadowImage);
-        shadowDestRect = normalizedRect;
-        shadowDestRect.translate(m_data->shadow.offset);
-
-        pShadow->setCompositionMode(QPainter::CompositionMode_Source);
-        pShadow->fillRect(shadowImage->rect(), m_data->shadow.color);
-        pShadow->setCompositionMode(QPainter::CompositionMode_DestinationIn);
-    }
+    QRectF normalizedRect = rect.normalized();
+    ContextShadow* shadow = contextShadow();
 
     if (m_common->state.fillPattern) {
         AffineTransform affine;
-        FloatRect rectM(rect);
         QBrush brush(m_common->state.fillPattern->createPlatformPattern(affine));
         QPixmap* image = m_common->state.fillPattern->tileImage()->nativeImageForCurrentFrame();
-
-        if (m_data->hasShadow()) {
-            drawRepeatPattern(pShadow, image, FloatRect(static_cast<QRectF>(shadowImage->rect())), m_common->state.fillPattern->repeatX(), m_common->state.fillPattern->repeatY());
-            pShadow->end();
-            p->drawImage(shadowDestRect, *shadowImage, shadowImage->rect());
+        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());
-
-        if (m_data->hasShadow()) {
-            pShadow->fillRect(shadowImage->rect(), brush);
-            pShadow->end();
-            p->drawImage(shadowDestRect, *shadowImage, shadowImage->rect());
+        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()) {
-            pShadow->fillRect(shadowImage->rect(), p->brush());
-            pShadow->end();
-            p->drawImage(shadowDestRect, *shadowImage, shadowImage->rect());
+            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());
     }
-
-    delete shadowImage;
-    delete pShadow;
 }
 
 
@@ -696,11 +705,25 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorS
 
     m_data->solidColor.setColor(color);
     QPainter* p = m_data->p();
+    QRectF normalizedRect = rect.normalized();
 
-    if (m_data->hasShadow())
-        m_data->shadow.drawShadowRect(p, rect);
+    if (m_data->hasShadow()) {
+        ContextShadow* shadow = contextShadow();
 
-    p->fillRect(rect, m_data->solidColor);
+        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)
@@ -708,19 +731,32 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef
     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();
     if (m_data->hasShadow()) {
-        p->translate(m_data->shadow.offset);
-        p->fillPath(path.platformPath(), m_data->shadow.color);
-        p->translate(-m_data->shadow.offset);
+        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)
@@ -742,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())
@@ -758,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)
@@ -816,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;
@@ -864,10 +925,10 @@ void GraphicsContext::setPlatformShadow(const FloatSize& size, float blur, const
     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 = FloatSize(size.width(), -size.height());
-        m_data->shadow = ContextShadow(color, blur, 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, size.width(), size.height());
+        m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), size.height()));
     }
 }
 
@@ -893,7 +954,7 @@ 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));
@@ -983,7 +1044,7 @@ 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);
@@ -1056,7 +1117,7 @@ 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 {
@@ -1081,14 +1142,6 @@ 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())
@@ -1126,7 +1179,7 @@ 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 {
@@ -1139,28 +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::addInnerRoundedRectClip(const IntRect& rect,
                                               int thickness)
 {