2008-12-21 Dirk Schulze <krit@webkit.org>
authorkrit@webkit.org <krit@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 21 Dec 2008 23:44:16 +0000 (23:44 +0000)
committerkrit@webkit.org <krit@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 21 Dec 2008 23:44:16 +0000 (23:44 +0000)
        Reviewed by Darin Adler, Nikolas Zimmermann.

        Move the the platform dependent strokeBBox functionality out of RenderPath
        into Path with strokeBoundingRect.

        RenderPath clean-up for strokeBoundingBox
        [https://bugs.webkit.org/show_bug.cgi?id=22902]

        * GNUmakefile.am:
        * WebCore.xcodeproj/project.pbxproj:
        * platform/graphics/GraphicsContext.h:
        * platform/graphics/Path.h:
        * platform/graphics/StrokeStyleApplier.h: Added.
        (WebCore::StrokeStyleApplier::~StrokeStyleApplier):
        * platform/graphics/cairo/PathCairo.cpp:
        (WebCore::Path::strokeBoundingRect):
        * platform/graphics/cg/PathCG.cpp:
        (WebCore::createScratchContext):
        (WebCore::scratchContext):
        (WebCore::Path::strokeBoundingRect):
        * platform/graphics/qt/GraphicsContextQt.cpp:
        (WebCore::GraphicsContext::pen):
        * platform/graphics/qt/PathQt.cpp:
        (WebCore::Path::strokeBoundingRect):
        * rendering/RenderPath.cpp:
        (WebCore::StrokeBoundingRectStyleApplier::StrokeBoundingRectStyleApplier):
        (WebCore::StrokeBoundingRectStyleApplier::strokeStyle):
        (WebCore::RenderPath::relativeBBox):
        * rendering/RenderPath.h:
        * svg/graphics/cairo/RenderPathCairo.cpp:
        * svg/graphics/cg/RenderPathCg.cpp:
        * svg/graphics/qt/RenderPathQt.cpp:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@39427 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
WebCore/ChangeLog
WebCore/GNUmakefile.am
WebCore/WebCore.xcodeproj/project.pbxproj
WebCore/platform/graphics/GraphicsContext.h
WebCore/platform/graphics/Path.h
WebCore/platform/graphics/StrokeStyleApplier.h [new file with mode: 0644]
WebCore/platform/graphics/cairo/PathCairo.cpp
WebCore/platform/graphics/cg/PathCG.cpp
WebCore/platform/graphics/qt/GraphicsContextQt.cpp
WebCore/platform/graphics/qt/PathQt.cpp
WebCore/rendering/RenderPath.cpp
WebCore/rendering/RenderPath.h
WebCore/svg/graphics/cairo/RenderPathCairo.cpp
WebCore/svg/graphics/cg/RenderPathCg.cpp
WebCore/svg/graphics/qt/RenderPathQt.cpp

index 6bae695..7f04a11 100644 (file)
@@ -1,3 +1,38 @@
+2008-12-21  Dirk Schulze  <krit@webkit.org>
+
+        Reviewed by Darin Adler, Nikolas Zimmermann.
+
+        Move the the platform dependent strokeBBox functionality out of RenderPath
+        into Path with strokeBoundingRect.
+
+        RenderPath clean-up for strokeBoundingBox
+        [https://bugs.webkit.org/show_bug.cgi?id=22902]
+
+        * GNUmakefile.am:
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/graphics/GraphicsContext.h:
+        * platform/graphics/Path.h:
+        * platform/graphics/StrokeStyleApplier.h: Added.
+        (WebCore::StrokeStyleApplier::~StrokeStyleApplier):
+        * platform/graphics/cairo/PathCairo.cpp:
+        (WebCore::Path::strokeBoundingRect):
+        * platform/graphics/cg/PathCG.cpp:
+        (WebCore::createScratchContext):
+        (WebCore::scratchContext):
+        (WebCore::Path::strokeBoundingRect):
+        * platform/graphics/qt/GraphicsContextQt.cpp:
+        (WebCore::GraphicsContext::pen):
+        * platform/graphics/qt/PathQt.cpp:
+        (WebCore::Path::strokeBoundingRect):
+        * rendering/RenderPath.cpp:
+        (WebCore::StrokeBoundingRectStyleApplier::StrokeBoundingRectStyleApplier):
+        (WebCore::StrokeBoundingRectStyleApplier::strokeStyle):
+        (WebCore::RenderPath::relativeBBox):
+        * rendering/RenderPath.h:
+        * svg/graphics/cairo/RenderPathCairo.cpp:
+        * svg/graphics/cg/RenderPathCg.cpp:
+        * svg/graphics/qt/RenderPathQt.cpp:
+
 2008-12-20  David Kilzer  <ddkilzer@apple.com>
 
         Fix typo "CSSAferRuleValue" to "CSSAfterRuleValue"
index f49ad96..06d0599 100644 (file)
@@ -1326,6 +1326,7 @@ webcore_sources += \
        WebCore/platform/graphics/SimpleFontData.h \
        WebCore/platform/graphics/StringTruncator.cpp \
        WebCore/platform/graphics/StringTruncator.h \
+       WebCore/platform/graphics/StrokeStyleApplier.h \
        WebCore/platform/graphics/TextRun.h \
        WebCore/platform/graphics/UnitBezier.h \
        WebCore/platform/graphics/WidthIterator.cpp \
index 1b9e5df..f63e6b9 100644 (file)
                75793ED30D0CE85B007FC0AC /* DOMMessageEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 75793ED00D0CE85B007FC0AC /* DOMMessageEvent.h */; };
                75793ED40D0CE85B007FC0AC /* DOMMessageEvent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 75793ED10D0CE85B007FC0AC /* DOMMessageEvent.mm */; };
                75793ED50D0CE85B007FC0AC /* DOMMessageEventInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 75793ED20D0CE85B007FC0AC /* DOMMessageEventInternal.h */; };
+               849F77760EFEC6200090849D /* StrokeStyleApplier.h in Headers */ = {isa = PBXBuildFile; fileRef = 849F77750EFEC6200090849D /* StrokeStyleApplier.h */; };
                85004D940ACEEAEF00C438F6 /* DOMSVGDefsElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 85004D880ACEEAEF00C438F6 /* DOMSVGDefsElement.h */; };
                85004D950ACEEAEF00C438F6 /* DOMSVGDefsElement.mm in Sources */ = {isa = PBXBuildFile; fileRef = 85004D890ACEEAEF00C438F6 /* DOMSVGDefsElement.mm */; };
                85004D960ACEEAEF00C438F6 /* DOMSVGDescElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 85004D8A0ACEEAEF00C438F6 /* DOMSVGDescElement.h */; };
                75793ED00D0CE85B007FC0AC /* DOMMessageEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DOMMessageEvent.h; sourceTree = "<group>"; };
                75793ED10D0CE85B007FC0AC /* DOMMessageEvent.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = DOMMessageEvent.mm; sourceTree = "<group>"; };
                75793ED20D0CE85B007FC0AC /* DOMMessageEventInternal.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DOMMessageEventInternal.h; sourceTree = "<group>"; };
+               849F77750EFEC6200090849D /* StrokeStyleApplier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StrokeStyleApplier.h; sourceTree = "<group>"; };
                84B2B1F7056BEF3A00D2B771 /* WebCoreKeyGenerator.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = WebCoreKeyGenerator.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                84B2B1F8056BEF3A00D2B771 /* WebCoreKeyGenerator.m */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = WebCoreKeyGenerator.m; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                84B2B24F056BF15F00D2B771 /* SSLKeyGeneratorMac.mm */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SSLKeyGeneratorMac.mm; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                                49E911BA0EF86D47009D0CAF /* ScaleTransformOperation.cpp */,
                                49E911BB0EF86D47009D0CAF /* ScaleTransformOperation.h */,
                                49E911BC0EF86D47009D0CAF /* SkewTransformOperation.cpp */,
+                               849F77750EFEC6200090849D /* StrokeStyleApplier.h */,
                                49E911BD0EF86D47009D0CAF /* SkewTransformOperation.h */,
                                49E911BE0EF86D47009D0CAF /* TransformOperation.h */,
                                49E911BF0EF86D47009D0CAF /* TransformOperations.cpp */,
                                49E912AB0EFAC906009D0CAF /* Animation.h in Headers */,
                                49E912AD0EFAC906009D0CAF /* AnimationList.h in Headers */,
                                49E912AE0EFAC906009D0CAF /* TimingFunction.h in Headers */,
+                               849F77760EFEC6200090849D /* StrokeStyleApplier.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 7bf1aae..54715dd 100644 (file)
@@ -312,6 +312,7 @@ namespace WebCore {
 #if PLATFORM(QT)
         bool inTransparencyLayer() const;
         PlatformPath* currentPath();
+        QPen pen();
 #endif
 
 #if PLATFORM(GTK)
index 4efd340..0e6a080 100644 (file)
@@ -56,7 +56,9 @@ namespace WebCore {
     class FloatPoint;
     class FloatSize;
     class FloatRect;
+    class GraphicsContext;
     class String;
+    class StrokeStyleApplier;
 
     enum WindRule {
         RULE_NONZERO = 0,
@@ -88,6 +90,7 @@ namespace WebCore {
 
         bool contains(const FloatPoint&, WindRule rule = RULE_NONZERO) const;
         FloatRect boundingRect() const;
+        FloatRect strokeBoundingRect(StrokeStyleApplier* applier = 0);
         
         float length();
         FloatPoint pointAtLength(float length, bool& ok);
diff --git a/WebCore/platform/graphics/StrokeStyleApplier.h b/WebCore/platform/graphics/StrokeStyleApplier.h
new file mode 100644 (file)
index 0000000..e40d3d1
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+    Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#ifndef StrokeStyleApplier_h
+#define StrokeStyleApplier_h
+
+namespace WebCore {
+
+    class GraphicsContext;
+
+    class StrokeStyleApplier {
+    public:
+        virtual void strokeStyle(GraphicsContext*) = 0;
+
+    protected:
+        StrokeStyleApplier() {}
+        virtual ~StrokeStyleApplier() {}
+    };
+}
+
+#endif
+
index 4695360..59d7318 100644 (file)
 #include "AffineTransform.h"
 #include "CairoPath.h"
 #include "FloatRect.h"
+#include "GraphicsContext.h"
 #include "NotImplemented.h"
 #include "PlatformString.h"
+#include "StrokeStyleApplier.h"
 
 #include <cairo.h>
 #include <math.h>
@@ -188,6 +190,18 @@ FloatRect Path::boundingRect() const
     return FloatRect(x0, y0, x1 - x0, y1 - y0);
 }
 
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+    cairo_t* cr = platformPath()->m_cr;
+    GraphicsContext gc(cr);
+    if (applier)
+        applier->strokeStyle(&gc);
+
+    double x0, x1, y0, y1;
+    cairo_stroke_extents(cr, &x0, &y0, &x1, &y1);
+    return FloatRect(x0, y0, x1 - x0, y1 - y0);
+}
+
 bool Path::contains(const FloatPoint& point, WindRule rule) const
 {
     if (!boundingRect().contains(point))
index ea0c000..bffb08b 100644 (file)
 #include "AffineTransform.h"
 #include <ApplicationServices/ApplicationServices.h>
 #include "FloatRect.h"
+#include "GraphicsContext.h"
 #include "IntRect.h"
 #include "PlatformString.h"
+#include "StrokeStyleApplier.h"
 
 #include <wtf/MathExtras.h>
 
@@ -62,6 +64,25 @@ Path& Path::operator=(const Path& other)
     return *this;
 }
 
+static CGContextRef createScratchContext()
+{
+    CFMutableDataRef empty = CFDataCreateMutable(NULL, 0);
+    CGDataConsumerRef consumer = CGDataConsumerCreateWithCFData(empty);
+    CGContextRef contextRef = CGPDFContextCreate(consumer, NULL, NULL);
+    CGDataConsumerRelease(consumer);
+    CFRelease(empty);
+
+    CGFloat black[4] = {0, 0, 0, 1};
+    CGContextSetFillColor(contextRef, black);
+    CGContextSetStrokeColor(contextRef, black);
+    return contextRef;
+}
+
+static inline CGContextRef scratchContext()
+{
+    static CGContextRef context = createScratchContext();
+    return context;
+}
 
 static void copyClosingSubpathsApplierFunction(void* info, const CGPathElement* element)
 {
@@ -123,6 +144,29 @@ FloatRect Path::boundingRect() const
     return CGPathGetBoundingBox(m_path);
 }
 
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+    CGContextRef context = scratchContext();
+
+    CGContextSaveGState(context);
+    CGContextBeginPath(context);
+    CGContextAddPath(context, platformPath());
+
+    GraphicsContext gc(context);
+    if (applier)
+        applier->strokeStyle(&gc);
+
+    CGContextReplacePathWithStrokedPath(context);
+    if (CGContextIsPathEmpty(context)) {
+        CGContextRestoreGState(context);
+        return FloatRect();
+    }
+    CGRect box = CGContextGetPathBoundingBox(context);
+    CGContextRestoreGState(context);
+
+    return box;
+}
+
 void Path::moveTo(const FloatPoint& point)
 {
     CGPathMoveToPoint(m_path, 0, point.x(), point.y());
index 635d873..79f4cf1 100644 (file)
@@ -525,6 +525,15 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points
     p->restore();
 }
 
+QPen GraphicsContext::pen()
+{
+    if (paintingDisabled())
+        return QPen();
+
+    QPainter *p = m_data->p();
+    return p->pen();
+}
+
 void GraphicsContext::fillPath()
 {
     if (paintingDisabled())
index 339c2d4..32f194a 100644 (file)
 #include "config.h"
 #include "Path.h"
 
+#include "AffineTransform.h"
 #include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
 #include "PlatformString.h"
-#include "AffineTransform.h"
+#include "StrokeStyleApplier.h"
 #include <QPainterPath>
 #include <QMatrix>
 #include <QString>
@@ -93,6 +96,27 @@ FloatRect Path::boundingRect() const
     return m_path->boundingRect();
 }
 
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+    // FIXME: We should try to use a 'shared Context' instead of creating a new ImageBuffer
+    // on each call.
+    std::auto_ptr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1), false);
+    GraphicsContext* gc = scratchImage->context();
+    QPainterPathStroker stroke;
+    if (applier) {
+        applier->strokeStyle(gc);
+
+        QPen pen = gc->pen();
+        stroke.setWidth(pen.widthF());
+        stroke.setCapStyle(pen.capStyle());
+        stroke.setJoinStyle(pen.joinStyle());
+        stroke.setMiterLimit(pen.miterLimit());
+        stroke.setDashPattern(pen.dashPattern());
+        stroke.setDashOffset(pen.dashOffset());
+    }
+    return (stroke.createStroke(*platformPath())).boundingRect();
+}
+
 void Path::moveTo(const FloatPoint& point)
 {
     m_path->moveTo(point);
index 067e4f6..e0e6cca 100644 (file)
@@ -32,6 +32,7 @@
 #include "GraphicsContext.h"
 #include "PointerEventsHitRules.h"
 #include "RenderSVGContainer.h"
+#include "StrokeStyleApplier.h"
 #include "SVGPaintServer.h"
 #include "SVGRenderSupport.h"
 #include "SVGResourceFilter.h"
 
 namespace WebCore {
 
+class BoundingRectStrokeStyleApplier : public StrokeStyleApplier {
+public:
+    BoundingRectStrokeStyleApplier(const RenderObject* object, RenderStyle* style)
+        : m_object(object)
+        , m_style(style)
+    {
+        ASSERT(style);
+        ASSERT(object);
+    }
+
+    void strokeStyle(GraphicsContext* gc)
+    {
+        applyStrokeStyleToContext(gc, m_style, m_object);
+    }
+
+private:
+    const RenderObject* m_object;
+    RenderStyle* m_style;
+};
+
 // RenderPath
 RenderPath::RenderPath(RenderStyle* style, SVGStyledTransformableElement* node)
     : RenderObject(node)
@@ -89,8 +110,17 @@ FloatRect RenderPath::relativeBBox(bool includeStroke) const
         return FloatRect();
 
     if (includeStroke) {
-        if (m_strokeBbox.isEmpty())
-            m_strokeBbox = strokeBBox();
+        if (m_strokeBbox.isEmpty()) {
+            if (style()->svgStyle()->hasStroke()) {
+                BoundingRectStrokeStyleApplier strokeStyle(this, style());
+                m_strokeBbox = m_path.strokeBoundingRect(&strokeStyle);
+            } else {
+                if (m_fillBBox.isEmpty())
+                    m_fillBBox = m_path.boundingRect();
+
+                m_strokeBbox = m_fillBBox;
+            }
+        }
 
         return m_strokeBbox;
     }
index d34ca1c..35c1782 100644 (file)
@@ -46,8 +46,8 @@ public:
     virtual ~RenderPath();
 
     // Hit-detection seperated for the fill and the stroke
-    virtual bool fillContains(const FloatPoint&, bool requiresFill = true) const;
-    virtual bool strokeContains(const FloatPoint&, bool requiresStroke = true) const;
+    bool fillContains(const FloatPoint&, bool requiresFill = true) const;
+    bool strokeContains(const FloatPoint&, bool requiresStroke = true) const;
 
     // Returns an unscaled bounding box (not even including localTransform()) for this vector path
     virtual FloatRect relativeBBox(bool includeStroke = true) const;
@@ -75,7 +75,6 @@ public:
     virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
 
     FloatRect drawMarkersIfNeeded(GraphicsContext*, const FloatRect&, const Path&) const;
-    virtual FloatRect strokeBBox() const;
     
 private:
     FloatPoint mapAbsolutePointToLocal(const FloatPoint&) const;
index 72379b5..085a4a7 100644 (file)
@@ -36,17 +36,4 @@ bool RenderPath::strokeContains(const FloatPoint& point, bool requiresStroke) co
     return cairo_in_stroke(cr, point.x(), point.y());
 }
 
-FloatRect RenderPath::strokeBBox() const
-{
-    // TODO: this implementation is naive
-
-    cairo_t* cr = path().platformPath()->m_cr;
-
-    double x0, x1, y0, y1;
-    cairo_stroke_extents(cr, &x0, &y0, &x1, &y1);
-    FloatRect bbox = FloatRect(x0, y0, x1 - x0, y1 - y0);
-
-    return bbox;
-}
-
 }
index eb8e482..ad47d29 100644 (file)
 
 namespace WebCore {
 
-FloatRect RenderPath::strokeBBox() const
-{
-    if (style()->svgStyle()->hasStroke())
-        return strokeBoundingBox(path(), style(), this);
-
-    return path().boundingRect();
-}
-
-
 bool RenderPath::strokeContains(const FloatPoint& point, bool requiresStroke) const
 {
     if (path().isEmpty())
index 8bee8b8..6bc2682 100644 (file)
@@ -42,48 +42,6 @@ bool RenderPath::strokeContains(const FloatPoint& point, bool requiresStroke) co
     return false;
 }
 
-static QPainterPath getPathStroke(const QPainterPath &path, const RenderObject* object, const RenderStyle* style)
-{ 
-    QPainterPathStroker s;
-    s.setWidth(SVGRenderStyle::cssPrimitiveToLength(object, style->svgStyle()->strokeWidth(), 1.0));
-
-    if (style->svgStyle()->capStyle() == ButtCap)
-        s.setCapStyle(Qt::FlatCap);
-    else if (style->svgStyle()->capStyle() == RoundCap)
-        s.setCapStyle(Qt::RoundCap);
-
-    if (style->svgStyle()->joinStyle() == MiterJoin) {
-        s.setJoinStyle(Qt::MiterJoin);
-        s.setMiterLimit((qreal) style->svgStyle()->strokeMiterLimit());
-    } else if(style->svgStyle()->joinStyle() == RoundJoin)
-        s.setJoinStyle(Qt::RoundJoin);
-
-    const DashArray& dashes = WebCore::dashArrayFromRenderingStyle(style);
-    double dashOffset = SVGRenderStyle::cssPrimitiveToLength(object, style->svgStyle()->strokeDashOffset(), 0.0);
-
-    unsigned int dashLength = !dashes.isEmpty() ? dashes.size() : 0;
-    if(dashLength) {
-        QVector<qreal> pattern;
-        unsigned int count = (dashLength % 2) == 0 ? dashLength : dashLength * 2;
-
-        for(unsigned int i = 0; i < count; i++)
-            pattern.append(dashes[i % dashLength] / (float)s.width());
-
-        s.setDashPattern(pattern);
-    
-        Q_UNUSED(dashOffset);
-        // TODO: dash-offset, does/will qt4 API allow it? (Rob)
-    }
-
-    return s.createStroke(path);
-}
-
-FloatRect RenderPath::strokeBBox() const
-{
-    QPainterPath outline = getPathStroke(*(path().platformPath()), this, style());
-    return outline.boundingRect();
-}
-
 }
 
 // vim:ts=4:noet