webengine/osswebengine/WebCore/rendering/SVGRenderTreeAsText.cpp
changeset 0 dd21522fd290
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebCore/rendering/SVGRenderTreeAsText.cpp	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2004, 2005, 2007 Apple Inc. All rights reserved.
+ *           (C) 2005 Rob Buis <buis@kde.org>
+ *           (C) 2006 Alexander Kellett <lypanov@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+
+#include "SVGRenderTreeAsText.h"
+
+#include "GraphicsTypes.h"
+#include "HTMLNames.h"
+#include "KCanvasRenderingStyle.h"
+#include "RenderSVGContainer.h"
+#include "RenderTreeAsText.h"
+#include "SVGPaintServerGradient.h"
+#include "SVGPaintServerPattern.h"
+#include "SVGPaintServerSolid.h"
+#include "SVGResourceClipper.h"
+#include "SVGStyledElement.h"
+#include <math.h>
+
+namespace WebCore {
+
+/** class + iomanip to help streaming list separators, i.e. ", " in string "a, b, c, d"
+ * Can be used in cases where you don't know which item in the list is the first
+ * one to be printed, but still want to avoid strings like ", b, c".
+ */
+class TextStreamSeparator {
+public:
+    TextStreamSeparator(const String& s)
+        : m_separator(s)
+        , m_needToSeparate(false)
+    {
+    }
+
+private:
+    friend TextStream& operator<<(TextStream&, TextStreamSeparator&);
+
+    String m_separator;
+    bool m_needToSeparate;
+};
+
+TextStream& operator<<(TextStream& ts, TextStreamSeparator& sep)
+{
+    if (sep.m_needToSeparate)
+        ts << sep.m_separator;
+    else
+        sep.m_needToSeparate = true;
+    return ts;
+}
+
+TextStream& operator<<(TextStream& ts, const IntPoint& p)
+{
+    return ts << "(" << p.x() << "," << p.y() << ")";
+}
+
+TextStream& operator<<(TextStream& ts, const IntRect& r)
+{
+    return ts << "at (" << r.x() << "," << r.y() << ") size " << r.width() << "x" << r.height();
+}
+
+bool hasFractions(double val)
+{
+    double epsilon = 0.0001;
+    int ival = static_cast<int>(val);
+    double dval = static_cast<double>(ival);
+    return fabs(val - dval) > epsilon;
+}
+
+TextStream& operator<<(TextStream& ts, const FloatRect &r)
+{
+    ts << "at ("; 
+    if (hasFractions(r.x())) 
+        ts << r.x();
+    else 
+        ts << int(r.x());
+    ts << ",";
+    if (hasFractions(r.y())) 
+        ts << r.y();
+    else 
+        ts << int(r.y());
+    ts << ") size ";
+    if (hasFractions(r.width())) 
+        ts << r.width(); 
+    else 
+        ts << int(r.width()); 
+    ts << "x";
+    if (hasFractions(r.height())) 
+        ts << r.height();
+    else 
+        ts << int(r.height());
+    return ts;
+}
+
+TextStream& operator<<(TextStream& ts, const FloatPoint& p)
+{
+    ts << "(";    
+    if (hasFractions(p.x()))
+        ts << p.x();
+    else 
+        ts << int(p.x());    
+    ts << ",";
+    if (hasFractions(p.y())) 
+        ts << p.y();
+    else 
+        ts << int(p.y());    
+    return ts << ")";
+}
+
+TextStream& operator<<(TextStream& ts, const FloatSize& s)
+{
+    ts << "width=";
+    if (hasFractions(s.width()))
+        ts << s.width();
+    else
+        ts << int(s.width());
+    ts << " height=";
+    if (hasFractions(s.height())) 
+        ts << s.height();
+    else
+        ts << int(s.height());
+    return ts;
+}
+
+TextStream& operator<<(TextStream& ts, const AffineTransform& transform)
+{
+    if (transform.isIdentity())
+        ts << "identity";
+    else
+        ts << "{m=(("
+           << transform.a() << "," << transform.b()
+           << ")("
+           << transform.c() << "," << transform.d()
+           << ")) t=("
+           << transform.e() << "," << transform.f()
+           << ")}";
+
+    return ts;
+}
+
+TextStream& operator<<(TextStream& ts, const Color& c)
+{
+    return ts << c.name();
+}
+
+static void writeIndent(TextStream& ts, int indent)
+{
+    for (int i = 0; i != indent; ++i)
+        ts << "  ";
+}
+
+// FIXME: Maybe this should be in KCanvasRenderingStyle.cpp
+static TextStream& operator<<(TextStream& ts, const KCDashArray& a)
+{
+    ts << "{";
+    KCDashArray::const_iterator end = a.end();
+    for (KCDashArray::const_iterator it = a.begin(); it != end; ++it) {
+        if (it != a.begin())
+            ts << ", ";
+        ts << *it;
+    }
+    ts << "}";
+    return ts;
+}
+
+// FIXME: Maybe this should be in GraphicsTypes.cpp
+static TextStream& operator<<(TextStream& ts, LineCap style)
+{
+    switch (style) {
+        case ButtCap:
+            ts << "BUTT";
+            break;
+        case RoundCap:
+            ts << "ROUND";
+            break;
+        case SquareCap:
+            ts << "SQUARE";
+            break;
+    }
+    return ts;
+}
+
+// FIXME: Maybe this should be in GraphicsTypes.cpp
+static TextStream& operator<<(TextStream& ts, LineJoin style)
+{
+    switch (style) {
+        case MiterJoin:
+            ts << "MITER";
+            break;
+        case RoundJoin:
+            ts << "ROUND";
+            break;
+        case BevelJoin:
+            ts << "BEVEL";
+            break;
+    }
+    return ts;
+}
+
+static void writeStyle(TextStream& ts, const RenderObject& object)
+{
+    const RenderStyle* style = object.style();
+    const SVGRenderStyle* svgStyle = style->svgStyle();
+
+    if (!object.localTransform().isIdentity())
+        ts << " [transform=" << object.localTransform() << "]";
+    if (svgStyle->imageRendering() != SVGRenderStyle::initialImageRendering())
+        ts << " [image rendering=" << svgStyle->imageRendering() << "]";
+    if (style->opacity() != RenderStyle::initialOpacity())
+        ts << " [opacity=" << style->opacity() << "]";
+    if (object.isRenderPath()) {
+        const RenderPath& path = static_cast<const RenderPath&>(object);
+        SVGPaintServer* strokePaintServer = KSVGPainterFactory::strokePaintServer(style, &path);
+        if (strokePaintServer) {
+            TextStreamSeparator s(" ");
+            ts << " [stroke={";
+            if (strokePaintServer)
+                ts << s << *strokePaintServer;
+
+            double dashOffset = KSVGPainterFactory::cssPrimitiveToLength(&path, svgStyle->strokeDashOffset(), 0.0);
+            const KCDashArray& dashArray = KSVGPainterFactory::dashArrayFromRenderingStyle(style);
+            double strokeWidth = KSVGPainterFactory::cssPrimitiveToLength(&path, svgStyle->strokeWidth(), 1.0);
+
+            if (svgStyle->strokeOpacity() != 1.0f)
+                ts << s << "[opacity=" << svgStyle->strokeOpacity() << "]";
+            if (strokeWidth != 1.0f)
+                ts << s << "[stroke width=" << strokeWidth << "]";
+            if (svgStyle->strokeMiterLimit() != 4)
+                ts << s << "[miter limit=" << svgStyle->strokeMiterLimit() << "]";
+            if (svgStyle->capStyle() != 0)
+                ts << s << "[line cap=" << svgStyle->capStyle() << "]";
+            if (svgStyle->joinStyle() != 0)
+                ts << s << "[line join=" << svgStyle->joinStyle() << "]";
+            if (dashOffset != 0.0f)
+                ts << s << "[dash offset=" << dashOffset << "]";
+            if (!dashArray.isEmpty())
+                ts << s << "[dash array=" << dashArray << "]";
+            ts << "}]";
+        }
+        SVGPaintServer* fillPaintServer = KSVGPainterFactory::fillPaintServer(style, &path);
+        if (fillPaintServer) {
+            TextStreamSeparator s(" ");
+            ts << " [fill={";
+            if (fillPaintServer)
+                ts << s << *fillPaintServer;
+
+            if (style->svgStyle()->fillOpacity() != 1.0f)
+                ts << s << "[opacity=" << style->svgStyle()->fillOpacity() << "]";
+            if (style->svgStyle()->fillRule() != RULE_NONZERO)
+                ts << s << "[fill rule=" << style->svgStyle()->fillRule() << "]";
+            ts << "}]";
+        }
+    }
+    if (!svgStyle->clipPath().isEmpty())
+        ts << " [clip path=\"" << svgStyle->clipPath() << "\"]";
+    if (!svgStyle->startMarker().isEmpty())
+        ts << " [start marker=" << svgStyle->startMarker() << "]";
+    if (!svgStyle->midMarker().isEmpty())
+        ts << " [middle marker=" << svgStyle->midMarker() << "]";
+    if (!svgStyle->endMarker().isEmpty())
+        ts << " [end marker=" << svgStyle->endMarker() << "]";
+    if (!svgStyle->filter().isEmpty())
+        ts << " [filter=" << svgStyle->filter() << "]";
+}
+
+static TextStream& operator<<(TextStream& ts, const RenderPath& path)
+{
+    ts << " " << path.absoluteTransform().mapRect(path.relativeBBox());
+
+    writeStyle(ts, path);
+
+    ts << " [data=\"" << path.path().debugString() << "\"]";
+
+    return ts;
+}
+
+static TextStream& operator<<(TextStream& ts, const RenderSVGContainer& container)
+{
+    ts << " " << container.absoluteTransform().mapRect(container.relativeBBox());
+
+    writeStyle(ts, container);
+
+    return ts;
+}
+
+static String getTagName(SVGStyledElement* elem)
+{
+    if (elem)
+        return elem->nodeName();
+    return "";
+}
+
+void write(TextStream& ts, const RenderSVGContainer& container, int indent)
+{
+    writeIndent(ts, indent);
+    ts << container.renderName();
+
+    if (container.element()) {
+        String tagName = getTagName(static_cast<SVGStyledElement*>(container.element()));
+        if (!tagName.isEmpty())
+            ts << " {" << tagName << "}";
+    }
+
+    ts << container << endl;
+
+    for (RenderObject* child = container.firstChild(); child; child = child->nextSibling())
+        write(ts, *child, indent + 1);
+}
+
+void write(TextStream& ts, const RenderPath& path, int indent)
+{
+    writeIndent(ts, indent);
+    ts << path.renderName();
+
+    if (path.element()) {
+        String tagName = getTagName(static_cast<SVGStyledElement*>(path.element()));
+        if (!tagName.isEmpty())
+            ts << " {" << tagName << "}";
+    }
+
+    ts << path << endl;
+}
+
+void writeRenderResources(TextStream& ts, Node* parent)
+{
+    ASSERT(parent);
+    Node* node = parent;
+    do {
+        if (!node->isSVGElement())
+            continue;
+        SVGElement* svgElement = static_cast<SVGElement*>(node);
+        if (!svgElement->isStyled())
+            continue;
+
+        SVGStyledElement* styled = static_cast<SVGStyledElement*>(svgElement);
+        RefPtr<SVGResource> resource(styled->canvasResource());
+        if (!resource)
+            continue;
+
+        String elementId = svgElement->getAttribute(HTMLNames::idAttr);
+        if (resource->isPaintServer()) {
+            RefPtr<SVGPaintServer> paintServer = WTF::static_pointer_cast<SVGPaintServer>(resource);
+            ts << "KRenderingPaintServer {id=\"" << elementId << "\" " << *paintServer << "}" << endl;
+        } else
+            ts << "KCanvasResource {id=\"" << elementId << "\" " << *resource << "}" << endl;
+    } while ((node = node->traverseNextNode(parent)));
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)