summaryrefslogtreecommitdiffstats
path: root/WebCore/rendering/RenderSVGRoot.cpp
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:30:52 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:30:52 -0800
commit8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2 (patch)
tree11425ea0b299d6fb89c6d3618a22d97d5bf68d0f /WebCore/rendering/RenderSVGRoot.cpp
parent648161bb0edfc3d43db63caed5cc5213bc6cb78f (diff)
downloadexternal_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.zip
external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.gz
external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'WebCore/rendering/RenderSVGRoot.cpp')
-rw-r--r--WebCore/rendering/RenderSVGRoot.cpp334
1 files changed, 334 insertions, 0 deletions
diff --git a/WebCore/rendering/RenderSVGRoot.cpp b/WebCore/rendering/RenderSVGRoot.cpp
new file mode 100644
index 0000000..1c59450
--- /dev/null
+++ b/WebCore/rendering/RenderSVGRoot.cpp
@@ -0,0 +1,334 @@
+/*
+ Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005, 2007, 2008 Rob Buis <buis@kde.org>
+ 2007 Eric Seidel <eric@webkit.org>
+
+ This file is part of the KDE project
+
+ 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
+ aint 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.
+*/
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "RenderSVGRoot.h"
+
+#include "GraphicsContext.h"
+#include "RenderPath.h"
+#include "RenderSVGContainer.h"
+#include "RenderView.h"
+#include "SVGLength.h"
+#include "SVGRenderSupport.h"
+#include "SVGResourceClipper.h"
+#include "SVGResourceFilter.h"
+#include "SVGResourceMasker.h"
+#include "SVGSVGElement.h"
+#include "SVGStyledElement.h"
+#include "SVGURIReference.h"
+
+using namespace std;
+
+namespace WebCore {
+
+RenderSVGRoot::RenderSVGRoot(SVGStyledElement* node)
+ : RenderContainer(node)
+{
+ setReplaced(true);
+}
+
+RenderSVGRoot::~RenderSVGRoot()
+{
+}
+
+int RenderSVGRoot::lineHeight(bool b, bool isRootLineBox) const
+{
+ return height() + marginTop() + marginBottom();
+}
+
+int RenderSVGRoot::baselinePosition(bool b, bool isRootLineBox) const
+{
+ return height() + marginTop() + marginBottom();
+}
+
+void RenderSVGRoot::calcPrefWidths()
+{
+ ASSERT(prefWidthsDirty());
+
+ int paddingAndBorders = paddingLeft() + paddingRight() + borderLeft() + borderRight();
+ int width = calcReplacedWidth(false) + paddingAndBorders;
+
+ if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength)
+ width = min(width, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? paddingAndBorders : 0));
+
+ if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent())) {
+ m_minPrefWidth = 0;
+ m_maxPrefWidth = width;
+ } else
+ m_minPrefWidth = m_maxPrefWidth = width;
+
+ setPrefWidthsDirty(false);
+}
+
+void RenderSVGRoot::layout()
+{
+ ASSERT(needsLayout());
+
+ calcViewport();
+
+ // Arbitrary affine transforms are incompatible with LayoutState.
+ view()->disableLayoutState();
+
+ IntRect oldBounds = m_absoluteBounds;
+ IntRect oldOutlineBox;
+ bool checkForRepaint = checkForRepaintDuringLayout() && selfNeedsLayout();
+ if (checkForRepaint)
+ oldOutlineBox = absoluteOutlineBox();
+
+ calcWidth();
+ calcHeight();
+
+ m_absoluteBounds = absoluteClippedOverflowRect();
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
+ m_width = static_cast<int>(m_width * svg->currentScale());
+ m_height = static_cast<int>(m_height * svg->currentScale());
+
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (selfNeedsLayout()) // either bounds or transform changed, force kids to relayout
+ child->setNeedsLayout(true);
+
+ child->layoutIfNeeded();
+ ASSERT(!child->needsLayout());
+ }
+
+ if (checkForRepaint)
+ repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
+
+ view()->enableLayoutState();
+ setNeedsLayout(false);
+}
+
+void RenderSVGRoot::applyContentTransforms(PaintInfo& paintInfo, int parentX, int parentY)
+{
+ // Translate from parent offsets (html renderers) to a relative transform (svg renderers)
+ IntPoint origin;
+ origin.move(parentX, parentY);
+ origin.move(m_x, m_y);
+ origin.move(borderLeft(), borderTop());
+ origin.move(paddingLeft(), paddingTop());
+
+ if (origin.x() || origin.y()) {
+ paintInfo.context->concatCTM(AffineTransform().translate(origin.x(), origin.y()));
+ paintInfo.rect.move(-origin.x(), -origin.y());
+ }
+
+ // Respect scroll offset caused by html parents
+ AffineTransform ctm = RenderContainer::absoluteTransform();
+ paintInfo.rect.move(static_cast<int>(ctm.e()), static_cast<int>(ctm.f()));
+
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
+ paintInfo.context->concatCTM(AffineTransform().scale(svg->currentScale()));
+
+ if (!viewport().isEmpty()) {
+ if (style()->overflowX() != OVISIBLE)
+ paintInfo.context->clip(enclosingIntRect(viewport())); // FIXME: Eventually we'll want float-precision clipping
+
+ paintInfo.context->concatCTM(AffineTransform().translate(viewport().x(), viewport().y()));
+ }
+
+ paintInfo.context->concatCTM(AffineTransform().translate(svg->currentTranslate().x(), svg->currentTranslate().y()));
+}
+
+void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY)
+{
+ if (paintInfo.context->paintingDisabled())
+ return;
+
+ calcViewport();
+
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
+ // A value of zero disables rendering of the element.
+ if (viewport().width() <= 0. || viewport().height() <= 0.)
+ return;
+
+ // This should only exist for <svg> renderers
+ if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection))
+ paintBoxDecorations(paintInfo, m_x + parentX, m_y + parentY);
+
+ if (!firstChild()) {
+#if ENABLE(SVG_FILTERS)
+ // Spec: groups w/o children still may render filter content.
+ const SVGRenderStyle* svgStyle = style()->svgStyle();
+ SVGResourceFilter* filter = getFilterById(document(), svgStyle->filter());
+ if (!filter)
+#endif
+ return;
+ }
+
+ RenderObject::PaintInfo childPaintInfo(paintInfo);
+ childPaintInfo.context->save();
+
+ applyContentTransforms(childPaintInfo, parentX, parentY);
+
+ SVGResourceFilter* filter = 0;
+
+ FloatRect boundingBox = relativeBBox(true);
+ if (childPaintInfo.phase == PaintPhaseForeground)
+ prepareToRenderSVGContent(this, childPaintInfo, boundingBox, filter);
+
+ childPaintInfo.context->concatCTM(svg->viewBoxToViewTransform(width(), height()));
+ RenderContainer::paint(childPaintInfo, 0, 0);
+
+ if (childPaintInfo.phase == PaintPhaseForeground)
+ finishRenderSVGContent(this, childPaintInfo, boundingBox, filter, paintInfo.context);
+
+ childPaintInfo.context->restore();
+
+ if ((childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE)
+ paintOutline(childPaintInfo.context, m_absoluteBounds.x(), m_absoluteBounds.y(), m_absoluteBounds.width(), m_absoluteBounds.height(), style());
+}
+
+FloatRect RenderSVGRoot::viewport() const
+{
+ return m_viewport;
+}
+
+void RenderSVGRoot::calcViewport()
+{
+ SVGElement* svgelem = static_cast<SVGElement*>(element());
+ if (svgelem->hasTagName(SVGNames::svgTag)) {
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
+
+ if (!selfNeedsLayout() && !svg->hasRelativeValues())
+ return;
+
+ float w, h;
+ SVGLength width = svg->width();
+ if (width.unitType() == LengthTypePercentage && svg->hasSetContainerSize())
+ w = svg->relativeWidthValue();
+ else
+ w = width.value(svg);
+
+ SVGLength height = svg->height();
+ if (height.unitType() == LengthTypePercentage && svg->hasSetContainerSize())
+ h = svg->relativeHeightValue();
+ else
+ h = height.value(svg);
+
+ m_viewport = FloatRect(0, 0, w, h);
+ }
+}
+
+IntRect RenderSVGRoot::absoluteClippedOverflowRect()
+{
+ IntRect repaintRect;
+
+ for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling())
+ repaintRect.unite(current->absoluteClippedOverflowRect());
+
+#if ENABLE(SVG_FILTERS)
+ // Filters can expand the bounding box
+ SVGResourceFilter* filter = getFilterById(document(), style()->svgStyle()->filter());
+ if (filter)
+ repaintRect.unite(enclosingIntRect(filter->filterBBoxForItemBBox(repaintRect)));
+#endif
+
+ return repaintRect;
+}
+
+void RenderSVGRoot::addFocusRingRects(GraphicsContext* graphicsContext, int, int)
+{
+ graphicsContext->addFocusRingRect(m_absoluteBounds);
+}
+
+void RenderSVGRoot::absoluteRects(Vector<IntRect>& rects, int, int)
+{
+ for (RenderObject* current = firstChild(); current != 0; current = current->nextSibling())
+ current->absoluteRects(rects, 0, 0);
+}
+
+AffineTransform RenderSVGRoot::absoluteTransform() const
+{
+ AffineTransform ctm = RenderContainer::absoluteTransform();
+ ctm.translate(m_x, m_y);
+ SVGSVGElement* svg = static_cast<SVGSVGElement*>(element());
+ ctm.scale(svg->currentScale());
+ ctm.translate(svg->currentTranslate().x(), svg->currentTranslate().y());
+ ctm.translate(viewport().x(), viewport().y());
+ return svg->viewBoxToViewTransform(width(), height()) * ctm;
+}
+
+FloatRect RenderSVGRoot::relativeBBox(bool includeStroke) const
+{
+ FloatRect rect;
+
+ RenderObject* current = firstChild();
+ for (; current != 0; current = current->nextSibling()) {
+ FloatRect childBBox = current->relativeBBox(includeStroke);
+ FloatRect mappedBBox = current->localTransform().mapRect(childBBox);
+ // <svg> can have a viewBox contributing to the bbox
+ if (current->isSVGContainer())
+ mappedBBox = static_cast<RenderSVGContainer*>(current)->viewportTransform().mapRect(mappedBBox);
+ rect.unite(mappedBBox);
+ }
+
+ return rect;
+}
+
+AffineTransform RenderSVGRoot::localTransform() const
+{
+ return AffineTransform();
+}
+
+bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
+{
+ AffineTransform ctm = RenderContainer::absoluteTransform();
+
+ int sx = (_tx - static_cast<int>(ctm.e())); // scroll offset
+ int sy = (_ty - static_cast<int>(ctm.f())); // scroll offset
+
+ if (!viewport().isEmpty()
+ && style()->overflowX() == OHIDDEN
+ && style()->overflowY() == OHIDDEN) {
+ int tx = m_x - _tx + sx;
+ int ty = m_y - _ty + sy;
+
+ // Check if we need to do anything at all.
+ IntRect overflowBox = overflowRect(false);
+ overflowBox.move(tx, ty);
+ ctm.translate(viewport().x(), viewport().y());
+ double localX, localY;
+ ctm.inverse().map(_x - _tx, _y - _ty, &localX, &localY);
+ if (!overflowBox.contains((int)localX, (int)localY))
+ return false;
+ }
+
+ for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
+ if (child->nodeAtPoint(request, result, _x - sx, _y - sy, 0, 0, hitTestAction)) {
+ updateHitTestResult(result, IntPoint(_x - _tx, _y - _ty));
+ return true;
+ }
+ }
+
+ // Spec: Only graphical elements can be targeted by the mouse, period.
+ // 16.4: "If there are no graphics elements whose relevant graphics content is under the pointer (i.e., there is no target element), the event is not dispatched."
+ return false;
+}
+
+}
+
+#endif // ENABLE(SVG)
+
+// vim:ts=4:noet