diff options
author | Ben Murdoch <benm@google.com> | 2011-05-13 16:23:25 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-05-16 11:35:02 +0100 |
commit | 65f03d4f644ce73618e5f4f50dd694b26f55ae12 (patch) | |
tree | f478babb801e720de7bfaee23443ffe029f58731 /Source/WebCore/rendering/svg | |
parent | 47de4a2fb7262c7ebdb9cd133ad2c54c187454d0 (diff) | |
download | external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.zip external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.tar.gz external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.tar.bz2 |
Merge WebKit at r75993: Initial merge by git.
Change-Id: I602bbdc3974787a3b0450456a30a7868286921c3
Diffstat (limited to 'Source/WebCore/rendering/svg')
85 files changed, 9035 insertions, 118 deletions
diff --git a/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp b/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp new file mode 100644 index 0000000..835bce8 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2009, 2010 Apple Inc. All Rights Reserved. + * + * 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 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 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. + */ + +// This all-in-one cpp file cuts down on template bloat to allow us to build our Windows release build. + +#include "RenderSVGBlock.cpp" +#include "RenderSVGContainer.cpp" +#include "RenderSVGForeignObject.cpp" +#include "RenderSVGGradientStop.cpp" +#include "RenderSVGHiddenContainer.cpp" +#include "RenderSVGImage.cpp" +#include "RenderSVGInline.cpp" +#include "RenderSVGInlineText.cpp" +#include "RenderSVGModelObject.cpp" +#include "RenderSVGResource.cpp" +#include "RenderSVGResourceClipper.cpp" +#include "RenderSVGResourceContainer.cpp" +#include "RenderSVGResourceFilter.cpp" +#include "RenderSVGResourceFilterPrimitive.cpp" +#include "RenderSVGResourceGradient.cpp" +#include "RenderSVGResourceLinearGradient.cpp" +#include "RenderSVGResourceMarker.cpp" +#include "RenderSVGResourceMasker.cpp" +#include "RenderSVGResourcePattern.cpp" +#include "RenderSVGResourceRadialGradient.cpp" +#include "RenderSVGResourceSolidColor.cpp" +#include "RenderSVGRoot.cpp" +#include "RenderSVGShadowTreeRootContainer.cpp" +#include "RenderSVGTSpan.cpp" +#include "RenderSVGText.cpp" +#include "RenderSVGTextPath.cpp" +#include "RenderSVGTransformableContainer.cpp" +#include "RenderSVGViewportContainer.cpp" +#include "SVGImageBufferTools.cpp" +#include "SVGInlineFlowBox.cpp" +#include "SVGInlineTextBox.cpp" +#include "SVGMarkerLayoutInfo.cpp" +#include "SVGRenderSupport.cpp" +#include "SVGRenderTreeAsText.cpp" +#include "SVGResources.cpp" +#include "SVGResourcesCache.cpp" +#include "SVGResourcesCycleSolver.cpp" +#include "SVGRootInlineBox.cpp" +#include "SVGShadowTreeElements.cpp" +#include "SVGTextChunk.cpp" +#include "SVGTextChunkBuilder.cpp" +#include "SVGTextLayoutAttributes.cpp" +#include "SVGTextLayoutAttributesBuilder.cpp" +#include "SVGTextLayoutEngine.cpp" +#include "SVGTextLayoutEngineBaseline.cpp" +#include "SVGTextLayoutEngineSpacing.cpp" +#include "SVGTextMetrics.cpp" +#include "SVGTextQuery.cpp" diff --git a/Source/WebCore/rendering/svg/RenderSVGBlock.cpp b/Source/WebCore/rendering/svg/RenderSVGBlock.cpp new file mode 100644 index 0000000..ed8e24e --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGBlock.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGBlock.h" + +#include "RenderSVGResource.h" +#include "SVGElement.h" + +namespace WebCore { + +RenderSVGBlock::RenderSVGBlock(SVGElement* node) + : RenderBlock(node) +{ +} + +void RenderSVGBlock::setStyle(PassRefPtr<RenderStyle> style) +{ + RefPtr<RenderStyle> useStyle = style; + + // SVG text layout code expects us to be a block-level style element. + if (useStyle->isDisplayInlineType()) { + RefPtr<RenderStyle> newStyle = RenderStyle::create(); + newStyle->inheritFrom(useStyle.get()); + newStyle->setDisplay(BLOCK); + useStyle = newStyle.release(); + } + + RenderBlock::setStyle(useStyle.release()); +} + +void RenderSVGBlock::updateBoxModelInfoFromStyle() +{ + RenderBlock::updateBoxModelInfoFromStyle(); + + // RenderSVGlock, used by Render(SVGText|ForeignObject), is not allowed to call setHasOverflowClip(true). + // RenderBlock assumes a layer to be present when the overflow clip functionality is requested. Both + // Render(SVGText|ForeignObject) return 'false' on 'requiresLayer'. Fine for RenderSVGText. + // + // If we want to support overflow rules for <foreignObject> we can choose between two solutions: + // a) make RenderSVGForeignObject require layers and SVG layer aware + // b) reactor overflow logic out of RenderLayer (as suggested by dhyatt), which is a large task + // + // Until this is resolved, disable overflow support. Opera/FF don't support it as well at the moment (Feb 2010). + // + // Note: This does NOT affect overflow handling on outer/inner <svg> elements - this is handled + // manually by RenderSVGRoot - which owns the documents enclosing root layer and thus works fine. + setHasOverflowClip(false); +} + +void RenderSVGBlock::absoluteRects(Vector<IntRect>&, int, int) +{ + // This code path should never be taken for SVG, as we're assuming useTransforms=true everywhere, absoluteQuads should be used. + ASSERT_NOT_REACHED(); +} + +void RenderSVGBlock::destroy() +{ + SVGResourcesCache::clientDestroyed(this); + RenderBlock::destroy(); +} + +void RenderSVGBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) +{ + if (diff == StyleDifferenceLayout) + setNeedsBoundariesUpdate(); + RenderBlock::styleWillChange(diff, newStyle); +} + +void RenderSVGBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderBlock::styleDidChange(diff, oldStyle); + SVGResourcesCache::clientStyleChanged(this, diff, style()); +} + +void RenderSVGBlock::updateFromElement() +{ + RenderBlock::updateFromElement(); + SVGResourcesCache::clientUpdatedFromElement(this, style()); +} + +} + +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGBlock.h b/Source/WebCore/rendering/svg/RenderSVGBlock.h new file mode 100644 index 0000000..350fdde --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGBlock.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * + * 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 RenderSVGBlock_h +#define RenderSVGBlock_h + +#if ENABLE(SVG) +#include "RenderBlock.h" +#include "SVGRenderSupport.h" + +namespace WebCore { + +class SVGElement; + +class RenderSVGBlock : public RenderBlock { +public: + explicit RenderSVGBlock(SVGElement*); + +private: + virtual void setStyle(PassRefPtr<RenderStyle>); + virtual void updateBoxModelInfoFromStyle(); + + virtual void absoluteRects(Vector<IntRect>&, int tx, int ty); + + virtual void destroy(); + virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void updateFromElement(); +}; + +} +#endif +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGContainer.cpp new file mode 100644 index 0000000..1897f53 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGContainer.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005, 2007, 2008 Rob Buis <buis@kde.org> + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Google, Inc. All rights reserved. + * Copyright (C) 2009 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGContainer.h" + +#include "GraphicsContext.h" +#include "RenderSVGResource.h" +#include "RenderSVGResourceFilter.h" +#include "RenderView.h" +#include "SVGRenderSupport.h" +#include "SVGResources.h" +#include "SVGStyledElement.h" + +namespace WebCore { + +RenderSVGContainer::RenderSVGContainer(SVGStyledElement* node) + : RenderSVGModelObject(node) + , m_needsBoundariesUpdate(true) +{ +} + +RenderSVGContainer::~RenderSVGContainer() +{ +} + +void RenderSVGContainer::layout() +{ + ASSERT(needsLayout()); + + // RenderSVGRoot disables layoutState for the SVG rendering tree. + ASSERT(!view()->layoutStateEnabled()); + + // Allow RenderSVGViewportContainer to update its viewport. + calcViewport(); + + LayoutRepainter repainter(*this, checkForRepaintDuringLayout() || selfWillPaint()); + + // Allow RenderSVGTransformableContainer to update its transform. + bool updatedTransform = calculateLocalTransform(); + + SVGRenderSupport::layoutChildren(this, selfNeedsLayout()); + + // Invalidate all resources of this client if our layout changed. + if (m_everHadLayout && selfNeedsLayout()) + SVGResourcesCache::clientLayoutChanged(this); + + // At this point LayoutRepainter already grabbed the old bounds, + // recalculate them now so repaintAfterLayout() uses the new bounds. + if (m_needsBoundariesUpdate || updatedTransform) { + updateCachedBoundaries(); + m_needsBoundariesUpdate = false; + + // If our bounds changed, notify the parents. + RenderSVGModelObject::setNeedsBoundariesUpdate(); + } + + repainter.repaintAfterLayout(); + setNeedsLayout(false); +} + +bool RenderSVGContainer::selfWillPaint() +{ +#if ENABLE(FILTERS) + SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); + return resources && resources->filter(); +#else + return false; +#endif +} + +void RenderSVGContainer::paint(PaintInfo& paintInfo, int, int) +{ + if (paintInfo.context->paintingDisabled()) + return; + + // Spec: groups w/o children still may render filter content. + if (!firstChild() && !selfWillPaint()) + return; + + FloatRect repaintRect = repaintRectInLocalCoordinates(); + if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(repaintRect, localToParentTransform(), paintInfo)) + return; + + PaintInfo childPaintInfo(paintInfo); + childPaintInfo.context->save(); + + // Let the RenderSVGViewportContainer subclass clip if necessary + applyViewportClip(childPaintInfo); + + childPaintInfo.applyTransform(localToParentTransform()); + + bool continueRendering = true; + if (childPaintInfo.phase == PaintPhaseForeground) + continueRendering = SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo); + + if (continueRendering) { + childPaintInfo.updatePaintingRootForChildren(this); + for (RenderObject* child = firstChild(); child; child = child->nextSibling()) + child->paint(childPaintInfo, 0, 0); + } + + if (paintInfo.phase == PaintPhaseForeground) + SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, paintInfo.context); + + childPaintInfo.context->restore(); + + // FIXME: This really should be drawn from local coordinates, but currently we hack it + // to avoid our clip killing our outline rect. Thus we translate our + // outline rect into parent coords before drawing. + // FIXME: This means our focus ring won't share our rotation like it should. + // We should instead disable our clip during PaintPhaseOutline + if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE) { + IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRect)); + paintOutline(paintInfo.context, paintRectInParent.x(), paintRectInParent.y(), paintRectInParent.width(), paintRectInParent.height()); + } +} + +// addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call +void RenderSVGContainer::addFocusRingRects(Vector<IntRect>& rects, int, int) +{ + IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates())); + if (!paintRectInParent.isEmpty()) + rects.append(paintRectInParent); +} + +void RenderSVGContainer::updateCachedBoundaries() +{ + m_objectBoundingBox = FloatRect(); + m_strokeBoundingBox = FloatRect(); + m_repaintBoundingBox = FloatRect(); + + SVGRenderSupport::computeContainerBoundingBoxes(this, m_objectBoundingBox, m_strokeBoundingBox, m_repaintBoundingBox); + SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingBox); +} + +bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) +{ + // Give RenderSVGViewportContainer a chance to apply its viewport clip + if (!pointIsInsideViewportClip(pointInParent)) + return false; + + FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); + + if (!SVGRenderSupport::pointInClippingArea(this, localPoint)) + return false; + + for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { + if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) { + updateHitTestResult(result, roundedIntPoint(localPoint)); + 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) diff --git a/Source/WebCore/rendering/svg/RenderSVGContainer.h b/Source/WebCore/rendering/svg/RenderSVGContainer.h new file mode 100644 index 0000000..d478c49 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGContainer.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005, 2007 Rob Buis <buis@kde.org> + * Copyright (C) 2009 Google, Inc. All rights reserved. + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * 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 RenderSVGContainer_h +#define RenderSVGContainer_h + +#if ENABLE(SVG) + +#include "RenderSVGModelObject.h" + +namespace WebCore { + +class SVGElement; + +class RenderSVGContainer : public RenderSVGModelObject { +public: + explicit RenderSVGContainer(SVGStyledElement*); + virtual ~RenderSVGContainer(); + + const RenderObjectChildList* children() const { return &m_children; } + RenderObjectChildList* children() { return &m_children; } + + virtual void paint(PaintInfo&, int parentX, int parentY); + virtual void setNeedsBoundariesUpdate() { m_needsBoundariesUpdate = true; } + +protected: + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + + virtual bool isSVGContainer() const { return true; } + virtual const char* renderName() const { return "RenderSVGContainer"; } + + virtual void layout(); + + virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty); + + virtual FloatRect objectBoundingBox() const { return m_objectBoundingBox; } + virtual FloatRect strokeBoundingBox() const { return m_strokeBoundingBox; } + virtual FloatRect repaintRectInLocalCoordinates() const { return m_repaintBoundingBox; } + + virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); + + // Allow RenderSVGTransformableContainer to hook in at the right time in layout() + virtual bool calculateLocalTransform() { return false; } + + // Allow RenderSVGViewportContainer to hook in at the right times in layout(), paint() and nodeAtFloatPoint() + virtual void calcViewport() { } + virtual void applyViewportClip(PaintInfo&) { } + virtual bool pointIsInsideViewportClip(const FloatPoint& /*pointInParent*/) { return true; } + + bool selfWillPaint(); + void updateCachedBoundaries(); + +private: + RenderObjectChildList m_children; + FloatRect m_objectBoundingBox; + FloatRect m_strokeBoundingBox; + FloatRect m_repaintBoundingBox; + bool m_needsBoundariesUpdate : 1; +}; + +inline RenderSVGContainer* toRenderSVGContainer(RenderObject* object) +{ + // Note: isSVGContainer is also true for RenderSVGViewportContainer, which is not derived from this. + ASSERT(!object || (object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer"))); + return static_cast<RenderSVGContainer*>(object); +} + +inline const RenderSVGContainer* toRenderSVGContainer(const RenderObject* object) +{ + // Note: isSVGContainer is also true for RenderSVGViewportContainer, which is not derived from this. + ASSERT(!object || (object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer"))); + return static_cast<const RenderSVGContainer*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderSVGContainer(const RenderSVGContainer*); + +} // namespace WebCore + +#endif // ENABLE(SVG) +#endif // RenderSVGContainer_h diff --git a/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp b/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp new file mode 100644 index 0000000..200fab2 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2009 Google, Inc. + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) && ENABLE(SVG_FOREIGN_OBJECT) +#include "RenderSVGForeignObject.h" + +#include "GraphicsContext.h" +#include "RenderSVGResource.h" +#include "RenderView.h" +#include "SVGForeignObjectElement.h" +#include "SVGRenderSupport.h" +#include "SVGSVGElement.h" +#include "TransformState.h" + +namespace WebCore { + +RenderSVGForeignObject::RenderSVGForeignObject(SVGForeignObjectElement* node) + : RenderSVGBlock(node) + , m_needsTransformUpdate(true) +{ +} + +RenderSVGForeignObject::~RenderSVGForeignObject() +{ +} + +void RenderSVGForeignObject::paint(PaintInfo& paintInfo, int, int) +{ + if (paintInfo.context->paintingDisabled()) + return; + + PaintInfo childPaintInfo(paintInfo); + childPaintInfo.context->save(); + childPaintInfo.applyTransform(localTransform()); + + if (SVGRenderSupport::isOverflowHidden(this)) + childPaintInfo.context->clip(m_viewport); + + float opacity = style()->opacity(); + if (opacity < 1.0f) + childPaintInfo.context->beginTransparencyLayer(opacity); + + RenderBlock::paint(childPaintInfo, 0, 0); + + if (opacity < 1.0f) + childPaintInfo.context->endTransparencyLayer(); + + childPaintInfo.context->restore(); +} + +IntRect RenderSVGForeignObject::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) +{ + return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer); +} + +void RenderSVGForeignObject::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed) +{ + SVGRenderSupport::computeRectForRepaint(this, repaintContainer, repaintRect, fixed); +} + +const AffineTransform& RenderSVGForeignObject::localToParentTransform() const +{ + m_localToParentTransform = localTransform(); + m_localToParentTransform.translate(m_viewport.x(), m_viewport.y()); + return m_localToParentTransform; +} + +void RenderSVGForeignObject::computeLogicalWidth() +{ + // FIXME: Investigate in size rounding issues + setWidth(static_cast<int>(roundf(m_viewport.width()))); +} + +void RenderSVGForeignObject::computeLogicalHeight() +{ + // FIXME: Investigate in size rounding issues + setHeight(static_cast<int>(roundf(m_viewport.height()))); +} + +void RenderSVGForeignObject::layout() +{ + ASSERT(needsLayout()); + ASSERT(!view()->layoutStateEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree. + + LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); + SVGForeignObjectElement* foreign = static_cast<SVGForeignObjectElement*>(node()); + + bool updateCachedBoundariesInParents = false; + if (m_needsTransformUpdate) { + m_localTransform = foreign->animatedLocalTransform(); + m_needsTransformUpdate = false; + updateCachedBoundariesInParents = true; + } + + FloatRect oldViewport = m_viewport; + + // Cache viewport boundaries + FloatPoint viewportLocation(foreign->x().value(foreign), foreign->y().value(foreign)); + m_viewport = FloatRect(viewportLocation, FloatSize(foreign->width().value(foreign), foreign->height().value(foreign))); + if (!updateCachedBoundariesInParents) + updateCachedBoundariesInParents = oldViewport != m_viewport; + + // Set box origin to the foreignObject x/y translation, so positioned objects in XHTML content get correct + // positions. A regular RenderBoxModelObject would pull this information from RenderStyle - in SVG those + // properties are ignored for non <svg> elements, so we mimic what happens when specifying them through CSS. + + // FIXME: Investigate in location rounding issues - only affects RenderSVGForeignObject & RenderSVGText + setLocation(roundedIntPoint(viewportLocation)); + + bool layoutChanged = m_everHadLayout && selfNeedsLayout(); + RenderBlock::layout(); + ASSERT(!needsLayout()); + + // If our bounds changed, notify the parents. + if (updateCachedBoundariesInParents) + RenderSVGBlock::setNeedsBoundariesUpdate(); + + // Invalidate all resources of this client if our layout changed. + if (layoutChanged) + SVGResourcesCache::clientLayoutChanged(this); + + repainter.repaintAfterLayout(); +} + +bool RenderSVGForeignObject::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) +{ + FloatPoint localPoint = localTransform().inverse().mapPoint(pointInParent); + + // Early exit if local point is not contained in clipped viewport area + if (SVGRenderSupport::isOverflowHidden(this) && !m_viewport.contains(localPoint)) + return false; + + IntPoint roundedLocalPoint = roundedIntPoint(localPoint); + return RenderBlock::nodeAtPoint(request, result, roundedLocalPoint.x(), roundedLocalPoint.y(), 0, 0, hitTestAction); +} + +bool RenderSVGForeignObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction) +{ + ASSERT_NOT_REACHED(); + return false; +} + +void RenderSVGForeignObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const +{ + // When crawling up the hierachy starting from foreignObject child content, useTransforms may not be set to true. + if (!useTransforms) + useTransforms = true; + SVGRenderSupport::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState); +} + +} + +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGForeignObject.h b/Source/WebCore/rendering/svg/RenderSVGForeignObject.h new file mode 100644 index 0000000..a1cf91a --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGForeignObject.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2009 Google, Inc. + * + * 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 RenderSVGForeignObject_h +#define RenderSVGForeignObject_h + +#if ENABLE(SVG) && ENABLE(SVG_FOREIGN_OBJECT) +#include "AffineTransform.h" +#include "FloatPoint.h" +#include "RenderSVGBlock.h" + +namespace WebCore { + +class SVGForeignObjectElement; + +class RenderSVGForeignObject : public RenderSVGBlock { +public: + explicit RenderSVGForeignObject(SVGForeignObjectElement*); + virtual ~RenderSVGForeignObject(); + + virtual const char* renderName() const { return "RenderSVGForeignObject"; } + + virtual void paint(PaintInfo&, int parentX, int parentY); + + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); + virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false); + + virtual bool requiresLayer() const { return false; } + virtual void layout(); + + virtual FloatRect objectBoundingBox() const { return m_viewport; } + virtual FloatRect strokeBoundingBox() const { return m_viewport; } + virtual FloatRect repaintRectInLocalCoordinates() const { return m_viewport; } + + virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); + virtual bool isSVGForeignObject() const { return true; } + + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState&) const; + virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } + +private: + virtual void computeLogicalWidth(); + virtual void computeLogicalHeight(); + + virtual const AffineTransform& localToParentTransform() const; + virtual AffineTransform localTransform() const { return m_localTransform; } + + bool m_needsTransformUpdate : 1; + FloatRect m_viewport; + AffineTransform m_localTransform; + mutable AffineTransform m_localToParentTransform; +}; + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGGradientStop.cpp b/Source/WebCore/rendering/svg/RenderSVGGradientStop.cpp new file mode 100644 index 0000000..46c3e2b --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGGradientStop.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2007 Eric Seidel <eric@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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGGradientStop.h" + +#include "RenderSVGResourceContainer.h" +#include "SVGGradientElement.h" +#include "SVGNames.h" +#include "SVGResourcesCache.h" +#include "SVGStopElement.h" + +namespace WebCore { + +using namespace SVGNames; + +RenderSVGGradientStop::RenderSVGGradientStop(SVGStopElement* element) + : RenderObject(element) +{ +} + +RenderSVGGradientStop::~RenderSVGGradientStop() +{ +} + +void RenderSVGGradientStop::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderObject::styleDidChange(diff, oldStyle); + if (diff == StyleDifferenceEqual) + return; + + // <stop> elements should only be allowed to make renderers under gradient elements + // but I can imagine a few cases we might not be catching, so let's not crash if our parent isn't a gradient. + SVGGradientElement* gradient = gradientElement(); + if (!gradient) + return; + + RenderObject* renderer = gradient->renderer(); + if (!renderer) + return; + + ASSERT(renderer->isSVGResourceContainer()); + RenderSVGResourceContainer* container = renderer->toRenderSVGResourceContainer(); + container->removeAllClientsFromCache(); +} + +void RenderSVGGradientStop::layout() +{ + setNeedsLayout(false); +} + +SVGGradientElement* RenderSVGGradientStop::gradientElement() const +{ + ContainerNode* parentNode = node()->parentNode(); + if (parentNode->hasTagName(linearGradientTag) || parentNode->hasTagName(radialGradientTag)) + return static_cast<SVGGradientElement*>(parentNode); + return 0; +} + +} + +#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGGradientStop.h b/Source/WebCore/rendering/svg/RenderSVGGradientStop.h new file mode 100644 index 0000000..ae90f37 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGGradientStop.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Google, Inc. + * + * 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 RenderSVGGradientStop_h +#define RenderSVGGradientStop_h + +#if ENABLE(SVG) +#include "RenderObject.h" + +namespace WebCore { + +class SVGGradientElement; +class SVGStopElement; + +// This class exists mostly so we can hear about gradient stop style changes +class RenderSVGGradientStop : public RenderObject { +public: + RenderSVGGradientStop(SVGStopElement*); + virtual ~RenderSVGGradientStop(); + + virtual bool isSVGGradientStop() const { return true; } + virtual const char* renderName() const { return "RenderSVGGradientStop"; } + + virtual void layout(); + + // This overrides are needed to prevent ASSERTs on <svg><stop /></svg> + // RenderObject's default implementations ASSERT_NOT_REACHED() + // https://bugs.webkit.org/show_bug.cgi?id=20400 + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject*) { return IntRect(); } + virtual FloatRect objectBoundingBox() const { return FloatRect(); } + virtual FloatRect strokeBoundingBox() const { return FloatRect(); } + virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(); } + +protected: + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + +private: + SVGGradientElement* gradientElement() const; +}; + +inline const RenderSVGGradientStop* toRenderSVGGradientStop(const RenderObject* object) +{ + ASSERT(!object || object->isSVGGradientStop()); + return static_cast<const RenderSVGGradientStop*>(object); +} + +} + +#endif // ENABLE(SVG) +#endif // RenderSVGGradientStop_h diff --git a/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.cpp new file mode 100644 index 0000000..9ddabef --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2007 Eric Seidel <eric@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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGHiddenContainer.h" + +#include "RenderSVGPath.h" +#include "SVGStyledElement.h" + +namespace WebCore { + +RenderSVGHiddenContainer::RenderSVGHiddenContainer(SVGStyledElement* element) + : RenderSVGContainer(element) +{ +} + +void RenderSVGHiddenContainer::layout() +{ + ASSERT(needsLayout()); + SVGRenderSupport::layoutChildren(this, selfNeedsLayout()); + setNeedsLayout(false); +} + +void RenderSVGHiddenContainer::paint(PaintInfo&, int, int) +{ + // This subtree does not paint. +} + +void RenderSVGHiddenContainer::absoluteQuads(Vector<FloatQuad>&) +{ + // This subtree does not take up space or paint +} + +bool RenderSVGHiddenContainer::nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint&, HitTestAction) +{ + return false; +} + +} + +#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.h b/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.h new file mode 100644 index 0000000..d35de2d --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2007 Eric Seidel <eric@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 RenderSVGHiddenContainer_h +#define RenderSVGHiddenContainer_h + +#if ENABLE(SVG) +#include "RenderSVGContainer.h" + +namespace WebCore { + +class SVGStyledElement; + +// This class is for containers which are never drawn, but do need to support style +// <defs>, <linearGradient>, <radialGradient> are all good examples +class RenderSVGHiddenContainer : public RenderSVGContainer { +public: + explicit RenderSVGHiddenContainer(SVGStyledElement*); + + virtual const char* renderName() const { return "RenderSVGHiddenContainer"; } + +protected: + virtual void layout(); + +private: + virtual bool isSVGHiddenContainer() const { return true; } + virtual bool requiresLayer() const { return false; } + + virtual void paint(PaintInfo&, int parentX, int parentY); + + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject*) { return IntRect(); } + virtual void absoluteQuads(Vector<FloatQuad>&); + + virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); +}; +} + +#endif // ENABLE(SVG) +#endif // RenderSVGHiddenContainer_h diff --git a/Source/WebCore/rendering/svg/RenderSVGImage.cpp b/Source/WebCore/rendering/svg/RenderSVGImage.cpp new file mode 100644 index 0000000..0f5a55e --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGImage.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2006 Alexander Kellett <lypanov@kde.org> + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2007, 2008, 2009 Rob Buis <buis@kde.org> + * Copyright (C) 2009 Google, Inc. + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com> + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGImage.h" + +#include "Attr.h" +#include "FloatConversion.h" +#include "FloatQuad.h" +#include "GraphicsContext.h" +#include "PointerEventsHitRules.h" +#include "RenderImageResource.h" +#include "RenderLayer.h" +#include "RenderSVGResourceContainer.h" +#include "RenderSVGResourceFilter.h" +#include "SVGImageElement.h" +#include "SVGLength.h" +#include "SVGPreserveAspectRatio.h" +#include "SVGRenderSupport.h" +#include "SVGResources.h" + +namespace WebCore { + +RenderSVGImage::RenderSVGImage(SVGImageElement* impl) + : RenderSVGModelObject(impl) + , m_updateCachedRepaintRect(true) + , m_needsTransformUpdate(true) + , m_imageResource(RenderImageResource::create()) +{ + m_imageResource->initialize(this); +} + +RenderSVGImage::~RenderSVGImage() +{ + m_imageResource->shutdown(); +} + +void RenderSVGImage::layout() +{ + ASSERT(needsLayout()); + + LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsLayout()); + SVGImageElement* image = static_cast<SVGImageElement*>(node()); + + bool transformOrBoundariesUpdate = m_needsTransformUpdate || m_updateCachedRepaintRect; + if (m_needsTransformUpdate) { + m_localTransform = image->animatedLocalTransform(); + m_needsTransformUpdate = false; + } + + if (m_updateCachedRepaintRect) { + m_repaintBoundingBox = m_objectBoundingBox; + SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingBox); + m_updateCachedRepaintRect = false; + } + + // Invalidate all resources of this client if our layout changed. + if (m_everHadLayout && selfNeedsLayout()) + SVGResourcesCache::clientLayoutChanged(this); + + // If our bounds changed, notify the parents. + if (transformOrBoundariesUpdate) + RenderSVGModelObject::setNeedsBoundariesUpdate(); + + repainter.repaintAfterLayout(); + setNeedsLayout(false); +} + +void RenderSVGImage::updateFromElement() +{ + SVGImageElement* image = static_cast<SVGImageElement*>(node()); + + FloatRect oldBoundaries = m_objectBoundingBox; + m_objectBoundingBox = FloatRect(image->x().value(image), image->y().value(image), image->width().value(image), image->height().value(image)); + if (m_objectBoundingBox != oldBoundaries) { + m_updateCachedRepaintRect = true; + setNeedsLayout(true); + } + RenderSVGModelObject::updateFromElement(); +} + +void RenderSVGImage::paint(PaintInfo& paintInfo, int, int) +{ + if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || !m_imageResource->hasImage()) + return; + + FloatRect boundingBox = repaintRectInLocalCoordinates(); + if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(boundingBox, m_localTransform, paintInfo)) + return; + + PaintInfo childPaintInfo(paintInfo); + bool drawsOutline = style()->outlineWidth() && (childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline); + if (drawsOutline || childPaintInfo.phase == PaintPhaseForeground) { + childPaintInfo.context->save(); + childPaintInfo.applyTransform(m_localTransform); + + if (childPaintInfo.phase == PaintPhaseForeground) { + PaintInfo savedInfo(childPaintInfo); + + if (SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo)) { + Image* image = m_imageResource->image(); + FloatRect destRect = m_objectBoundingBox; + FloatRect srcRect(0, 0, image->width(), image->height()); + + SVGImageElement* imageElement = static_cast<SVGImageElement*>(node()); + if (imageElement->preserveAspectRatio().align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) + imageElement->preserveAspectRatio().transformRect(destRect, srcRect); + + childPaintInfo.context->drawImage(image, ColorSpaceDeviceRGB, destRect, srcRect); + } + + SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, savedInfo.context); + } + + if (drawsOutline) + paintOutline(childPaintInfo.context, static_cast<int>(boundingBox.x()), static_cast<int>(boundingBox.y()), + static_cast<int>(boundingBox.width()), static_cast<int>(boundingBox.height())); + + childPaintInfo.context->restore(); + } +} + +bool RenderSVGImage::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) +{ + // We only draw in the forground phase, so we only hit-test then. + if (hitTestAction != HitTestForeground) + return false; + + PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_IMAGE_HITTESTING, request, style()->pointerEvents()); + bool isVisible = (style()->visibility() == VISIBLE); + if (isVisible || !hitRules.requireVisible) { + FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); + + if (!SVGRenderSupport::pointInClippingArea(this, localPoint)) + return false; + + if (hitRules.canHitFill) { + if (m_objectBoundingBox.contains(localPoint)) { + updateHitTestResult(result, roundedIntPoint(localPoint)); + return true; + } + } + } + + return false; +} + +void RenderSVGImage::imageChanged(WrappedImagePtr, const IntRect*) +{ + // The image resource defaults to nullImage until the resource arrives. + // This empty image may be cached by SVG resources which must be invalidated. + if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this)) + resources->removeClientFromCache(this); + + // Eventually notify parent resources, that we've changed. + RenderSVGResource::markForLayoutAndParentResourceInvalidation(this, false); + + repaint(); +} + +void RenderSVGImage::addFocusRingRects(Vector<IntRect>& rects, int, int) +{ + // this is called from paint() after the localTransform has already been applied + IntRect contentRect = enclosingIntRect(repaintRectInLocalCoordinates()); + if (!contentRect.isEmpty()) + rects.append(contentRect); +} + +} // namespace WebCore + +#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGImage.h b/Source/WebCore/rendering/svg/RenderSVGImage.h new file mode 100644 index 0000000..2c91b52 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGImage.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2006 Alexander Kellett <lypanov@kde.org> + * Copyright (C) 2006, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007 Rob Buis <buis@kde.org> + * Copyright (C) 2009 Google, Inc. + * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com> + * + * 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 RenderSVGImage_h +#define RenderSVGImage_h + +#if ENABLE(SVG) +#include "AffineTransform.h" +#include "FloatRect.h" +#include "RenderSVGModelObject.h" +#include "SVGPreserveAspectRatio.h" +#include "SVGRenderSupport.h" + +namespace WebCore { + +class RenderImageResource; +class SVGImageElement; + +class RenderSVGImage : public RenderSVGModelObject { +public: + RenderSVGImage(SVGImageElement*); + virtual ~RenderSVGImage(); + + virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } + virtual void updateFromElement(); + + RenderImageResource* imageResource() { return m_imageResource.get(); } + const RenderImageResource* imageResource() const { return m_imageResource.get(); } + +private: + virtual const char* renderName() const { return "RenderSVGImage"; } + virtual bool isSVGImage() const { return true; } + + virtual const AffineTransform& localToParentTransform() const { return m_localTransform; } + + virtual FloatRect objectBoundingBox() const { return m_objectBoundingBox; } + virtual FloatRect strokeBoundingBox() const { return m_objectBoundingBox; } + virtual FloatRect repaintRectInLocalCoordinates() const { return m_repaintBoundingBox; } + + virtual void addFocusRingRects(Vector<IntRect>&, int tx, int ty); + + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + + virtual void layout(); + virtual void paint(PaintInfo&, int parentX, int parentY); + + virtual bool requiresLayer() const { return false; } + + virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); + + virtual AffineTransform localTransform() const { return m_localTransform; } + + bool m_updateCachedRepaintRect : 1; + bool m_needsTransformUpdate : 1; + AffineTransform m_localTransform; + FloatRect m_objectBoundingBox; + FloatRect m_repaintBoundingBox; + OwnPtr<RenderImageResource> m_imageResource; +}; + +inline RenderSVGImage* toRenderSVGImage(RenderObject* object) +{ + ASSERT(!object || object->isSVGImage()); + return static_cast<RenderSVGImage*>(object); +} + +inline const RenderSVGImage* toRenderSVGImage(const RenderObject* object) +{ + ASSERT(!object || object->isSVGImage()); + return static_cast<const RenderSVGImage*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderSVGImage(const RenderSVGImage*); + +} // namespace WebCore + +#endif // ENABLE(SVG) +#endif // RenderSVGImage_h diff --git a/Source/WebCore/rendering/svg/RenderSVGInline.cpp b/Source/WebCore/rendering/svg/RenderSVGInline.cpp index 4d0c533..543d14b 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInline.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGInline.cpp @@ -17,7 +17,6 @@ * 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. - * */ #include "config.h" diff --git a/Source/WebCore/rendering/svg/RenderSVGInline.h b/Source/WebCore/rendering/svg/RenderSVGInline.h index d7b7e66..33d7d13 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInline.h +++ b/Source/WebCore/rendering/svg/RenderSVGInline.h @@ -1,8 +1,6 @@ /* - * This file is part of the WebKit project. - * * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> - * (C) 2006 Apple Computer Inc. + * Copyright (C) 2006 Apple Computer Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -18,7 +16,6 @@ * 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 RenderSVGInline_h diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp index b791f3e..91ffb5c 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp @@ -19,7 +19,6 @@ * 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. - * */ #include "config.h" diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.h b/Source/WebCore/rendering/svg/RenderSVGInlineText.h index 926ec43..f5247f6 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInlineText.h +++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.h @@ -1,9 +1,7 @@ /* - * This file is part of the WebKit project. - * * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. - * (C) 2008 Rob Buis <buis@kde.org> + * Copyright (C) 2008 Rob Buis <buis@kde.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,7 +17,6 @@ * 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 RenderSVGInlineText_h diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp new file mode 100644 index 0000000..28760a0 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 "RenderSVGModelObject.h" + +#include "RenderSVGResource.h" +#include "SVGStyledElement.h" + +namespace WebCore { + +RenderSVGModelObject::RenderSVGModelObject(SVGStyledElement* node) + : RenderObject(node) +{ +} + +IntRect RenderSVGModelObject::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) +{ + return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer); +} + +void RenderSVGModelObject::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed) +{ + SVGRenderSupport::computeRectForRepaint(this, repaintContainer, repaintRect, fixed); +} + +void RenderSVGModelObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) const +{ + SVGRenderSupport::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState); +} + +// Copied from RenderBox, this method likely requires further refactoring to work easily for both SVG and CSS Box Model content. +// FIXME: This may also need to move into SVGRenderSupport as the RenderBox version depends +// on borderBoundingBox() which SVG RenderBox subclases (like SVGRenderBlock) do not implement. +IntRect RenderSVGModelObject::outlineBoundsForRepaint(RenderBoxModelObject* repaintContainer, IntPoint*) const +{ + IntRect box = enclosingIntRect(repaintRectInLocalCoordinates()); + adjustRectForOutlineAndShadow(box); + + FloatQuad containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer); + return containerRelativeQuad.enclosingBoundingBox(); +} + +void RenderSVGModelObject::absoluteRects(Vector<IntRect>&, int, int) +{ + // This code path should never be taken for SVG, as we're assuming useTransforms=true everywhere, absoluteQuads should be used. + ASSERT_NOT_REACHED(); +} + +void RenderSVGModelObject::absoluteQuads(Vector<FloatQuad>& quads) +{ + quads.append(localToAbsoluteQuad(strokeBoundingBox())); +} + +void RenderSVGModelObject::destroy() +{ + SVGResourcesCache::clientDestroyed(this); + RenderObject::destroy(); +} + +void RenderSVGModelObject::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) +{ + if (diff == StyleDifferenceLayout) + setNeedsBoundariesUpdate(); + RenderObject::styleWillChange(diff, newStyle); +} + +void RenderSVGModelObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderObject::styleDidChange(diff, oldStyle); + SVGResourcesCache::clientStyleChanged(this, diff, style()); +} + +void RenderSVGModelObject::updateFromElement() +{ + RenderObject::updateFromElement(); + SVGResourcesCache::clientUpdatedFromElement(this, style()); +} + +bool RenderSVGModelObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction) +{ + ASSERT_NOT_REACHED(); + return false; +} + +} // namespace WebCore + +#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.h b/Source/WebCore/rendering/svg/RenderSVGModelObject.h new file mode 100644 index 0000000..a04db96 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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. + */ + +#ifndef RenderSVGModelObject_h +#define RenderSVGModelObject_h + +#if ENABLE(SVG) + +#include "RenderObject.h" +#include "SVGRenderSupport.h" + +namespace WebCore { + +// Most renderers in the SVG rendering tree will inherit from this class +// but not all. (e.g. RenderSVGForeignObject, RenderSVGBlock) thus methods +// required by SVG renders need to be declared on RenderObject, but shared +// logic can go in this class or in SVGRenderSupport. + +class SVGStyledElement; + +class RenderSVGModelObject : public RenderObject { +public: + explicit RenderSVGModelObject(SVGStyledElement*); + + virtual bool requiresLayer() const { return false; } + + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); + virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false); + virtual IntRect outlineBoundsForRepaint(RenderBoxModelObject* repaintContainer, IntPoint*) const; + + virtual void absoluteRects(Vector<IntRect>&, int tx, int ty); + virtual void absoluteQuads(Vector<FloatQuad>&); + + virtual void destroy(); + + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const; + virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void updateFromElement(); + +private: + // This method should never be called, SVG uses a different nodeAtPoint method + bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int xInContainer, int yInContainer, int dxParentToContainer, int dyParentToContainer, HitTestAction); +}; + +} + +#endif // ENABLE(SVG) +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGPath.cpp b/Source/WebCore/rendering/svg/RenderSVGPath.cpp index 0c8ac0c..1d9eca1 100644 --- a/Source/WebCore/rendering/svg/RenderSVGPath.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGPath.cpp @@ -1,27 +1,27 @@ /* - Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> - 2004, 2005, 2008 Rob Buis <buis@kde.org> - 2005, 2007 Eric Seidel <eric@webkit.org> - 2009 Google, Inc. - 2009 Dirk Schulze <krit@webkit.org> - Copyright (C) Research In Motion Limited 2010. All rights reserved. - 2009 Jeff Schiller <codedread@gmail.com> - - 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. -*/ + * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005, 2008 Rob Buis <buis@kde.org> + * Copyright (C) 2005, 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Google, Inc. + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * Copyright (C) 2009 Jeff Schiller <codedread@gmail.com> + * + * 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. + */ #include "config.h" diff --git a/Source/WebCore/rendering/svg/RenderSVGPath.h b/Source/WebCore/rendering/svg/RenderSVGPath.h index 41b0e51..c5c8377 100644 --- a/Source/WebCore/rendering/svg/RenderSVGPath.h +++ b/Source/WebCore/rendering/svg/RenderSVGPath.h @@ -1,25 +1,25 @@ /* - Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> - 2004, 2005 Rob Buis <buis@kde.org> - 2005 Eric Seidel <eric@webkit.org> - 2006 Apple Computer, Inc - 2009 Google, Inc. - - 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. -*/ + * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2006 Apple Computer, Inc + * Copyright (C) 2009 Google, Inc. + * + * 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 RenderSVGPath_h #define RenderSVGPath_h diff --git a/Source/WebCore/rendering/svg/RenderSVGResource.cpp b/Source/WebCore/rendering/svg/RenderSVGResource.cpp new file mode 100644 index 0000000..c0b16c5 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResource.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2007 Rob Buis <buis@kde.org> + * Copyright (C) 2008 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGResource.h" + +#include "RenderSVGResourceContainer.h" +#include "RenderSVGResourceSolidColor.h" +#include "SVGResources.h" +#include "SVGURIReference.h" + +namespace WebCore { + +static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode mode, RenderObject* object, const RenderStyle* style, Color& fallbackColor) +{ + ASSERT(object); + ASSERT(style); + + // If we have no style at all, ignore it. + const SVGRenderStyle* svgStyle = style->svgStyle(); + if (!svgStyle) + return 0; + + // If we have no fill/stroke, return 0. + if (mode == ApplyToFillMode) { + if (!svgStyle->hasFill()) + return 0; + } else { + if (!svgStyle->hasStroke()) + return 0; + } + + SVGPaint* paint = mode == ApplyToFillMode ? svgStyle->fillPaint() : svgStyle->strokePaint(); + ASSERT(paint); + + SVGPaint::SVGPaintType paintType = paint->paintType(); + if (paintType == SVGPaint::SVG_PAINTTYPE_NONE) + return 0; + + Color color; + if (paintType == SVGPaint::SVG_PAINTTYPE_RGBCOLOR + || paintType == SVGPaint::SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR + || paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR + || paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR) + color = paint->color(); + else if (paintType == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR || paintType == SVGPaint::SVG_PAINTTYPE_URI_CURRENTCOLOR) + color = style->visitedDependentColor(CSSPropertyColor); + + if (style->insideLink() == InsideVisitedLink) { + RenderStyle* visitedStyle = style->getCachedPseudoStyle(VISITED_LINK); + ASSERT(visitedStyle); + + if (SVGPaint* visitedPaint = mode == ApplyToFillMode ? visitedStyle->svgStyle()->fillPaint() : visitedStyle->svgStyle()->strokePaint()) { + // For SVG_PAINTTYPE_CURRENTCOLOR, 'color' already contains the 'visitedColor'. + if (visitedPaint->paintType() < SVGPaint::SVG_PAINTTYPE_URI_NONE && visitedPaint->paintType() != SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR) { + const Color& visitedColor = visitedPaint->color(); + if (visitedColor.isValid()) + color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha()); + } + } + } + + // If the primary resource is just a color, return immediately. + RenderSVGResourceSolidColor* colorResource = RenderSVGResource::sharedSolidPaintingResource(); + if (paintType < SVGPaint::SVG_PAINTTYPE_URI_NONE) { + // If an invalid fill color is specified, fallback to fill/stroke="none". + if (!color.isValid()) + return 0; + + colorResource->setColor(color); + return colorResource; + } + + // If no resources are associated with the given renderer, return the color resource. + SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object); + if (!resources) { + // If a paint server is specified, and no or an invalid fallback color is given, default to fill/stroke="black". + if (!color.isValid()) + color = Color::black; + + colorResource->setColor(color); + return colorResource; + } + + // If the requested resource is not available, return the color resource. + RenderSVGResource* uriResource = mode == ApplyToFillMode ? resources->fill() : resources->stroke(); + if (!uriResource) { + // If a paint server is specified, and no or an invalid fallback color is given, default to fill/stroke="black". + if (!color.isValid()) + color = Color::black; + + colorResource->setColor(color); + return colorResource; + } + + // The paint server resource exists, though it may be invalid (pattern with width/height=0). Pass the fallback color to our caller + // so it can use the solid color painting resource, if applyResource() on the URI resource failed. + fallbackColor = color; + return uriResource; +} + +RenderSVGResource* RenderSVGResource::fillPaintingResource(RenderObject* object, const RenderStyle* style, Color& fallbackColor) +{ + return requestPaintingResource(ApplyToFillMode, object, style, fallbackColor); +} + +RenderSVGResource* RenderSVGResource::strokePaintingResource(RenderObject* object, const RenderStyle* style, Color& fallbackColor) +{ + return requestPaintingResource(ApplyToStrokeMode, object, style, fallbackColor); +} + +RenderSVGResourceSolidColor* RenderSVGResource::sharedSolidPaintingResource() +{ + static RenderSVGResourceSolidColor* s_sharedSolidPaintingResource = 0; + if (!s_sharedSolidPaintingResource) + s_sharedSolidPaintingResource = new RenderSVGResourceSolidColor; + return s_sharedSolidPaintingResource; +} + +void RenderSVGResource::markForLayoutAndParentResourceInvalidation(RenderObject* object, bool needsLayout) +{ + ASSERT(object); + if (needsLayout) + object->setNeedsLayout(true); + + // Invalidate resources in ancestor chain, if needed. + RenderObject* current = object->parent(); + while (current) { + if (current->isSVGResourceContainer()) { + current->toRenderSVGResourceContainer()->removeAllClientsFromCache(); + break; + } + + current = current->parent(); + } +} + +} + +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResource.h b/Source/WebCore/rendering/svg/RenderSVGResource.h new file mode 100644 index 0000000..a67ba73 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResource.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. + * + * 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 RenderSVGResource_h +#define RenderSVGResource_h + +#if ENABLE(SVG) +#include "RenderStyleConstants.h" +#include "SVGDocumentExtensions.h" + +namespace WebCore { + +enum RenderSVGResourceType { + MaskerResourceType, + MarkerResourceType, + PatternResourceType, + LinearGradientResourceType, + RadialGradientResourceType, + SolidColorResourceType, + FilterResourceType, + ClipperResourceType +}; + +enum RenderSVGResourceMode { + ApplyToDefaultMode = 1 << 0, // used for all resources except gradient/pattern + ApplyToFillMode = 1 << 1, + ApplyToStrokeMode = 1 << 2, + ApplyToTextMode = 1 << 3 // used in combination with ApplyTo{Fill|Stroke}Mode +}; + +class Color; +class FloatRect; +class GraphicsContext; +class Path; +class RenderObject; +class RenderStyle; +class RenderSVGResourceSolidColor; + +class RenderSVGResource { +public: + RenderSVGResource() { } + virtual ~RenderSVGResource() { } + + virtual void removeAllClientsFromCache(bool markForInvalidation = true) = 0; + virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true) = 0; + + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode) = 0; + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short, const Path*) { } + virtual FloatRect resourceBoundingBox(RenderObject*) = 0; + + virtual RenderSVGResourceType resourceType() const = 0; + + template<class Renderer> + Renderer* cast() + { + if (Renderer::s_resourceType == resourceType()) + return static_cast<Renderer*>(this); + + return 0; + } + + // Helper utilities used in the render tree to access resources used for painting shapes/text (gradients & patterns & solid colors only) + static RenderSVGResource* fillPaintingResource(RenderObject*, const RenderStyle*, Color& fallbackColor); + static RenderSVGResource* strokePaintingResource(RenderObject*, const RenderStyle*, Color& fallbackColor); + static RenderSVGResourceSolidColor* sharedSolidPaintingResource(); + + static void markForLayoutAndParentResourceInvalidation(RenderObject*, bool needsLayout = true); +}; + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp new file mode 100644 index 0000000..c57f8b0 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp @@ -0,0 +1,349 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Rob Buis <buis@kde.org> + * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGResourceClipper.h" + +#include "AffineTransform.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "HitTestRequest.h" +#include "HitTestResult.h" +#include "ImageBuffer.h" +#include "IntRect.h" +#include "RenderObject.h" +#include "RenderSVGResource.h" +#include "RenderStyle.h" +#include "SVGClipPathElement.h" +#include "SVGElement.h" +#include "SVGImageBufferTools.h" +#include "SVGNames.h" +#include "SVGRenderSupport.h" +#include "SVGResources.h" +#include "SVGStyledElement.h" +#include "SVGStyledTransformableElement.h" +#include "SVGUnitTypes.h" +#include "SVGUseElement.h" +#include <wtf/UnusedParam.h> + +namespace WebCore { + +RenderSVGResourceType RenderSVGResourceClipper::s_resourceType = ClipperResourceType; + +RenderSVGResourceClipper::RenderSVGResourceClipper(SVGClipPathElement* node) + : RenderSVGResourceContainer(node) + , m_invalidationBlocked(false) +{ +} + +RenderSVGResourceClipper::~RenderSVGResourceClipper() +{ + if (m_clipper.isEmpty()) + return; + + deleteAllValues(m_clipper); + m_clipper.clear(); +} + +void RenderSVGResourceClipper::removeAllClientsFromCache(bool markForInvalidation) +{ + if (m_invalidationBlocked) + return; + + m_clipBoundaries = FloatRect(); + if (!m_clipper.isEmpty()) { + deleteAllValues(m_clipper); + m_clipper.clear(); + } + + markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation); +} + +void RenderSVGResourceClipper::removeClientFromCache(RenderObject* client, bool markForInvalidation) +{ + ASSERT(client); + if (m_invalidationBlocked) + return; + + if (m_clipper.contains(client)) + delete m_clipper.take(client); + + markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation); +} + +bool RenderSVGResourceClipper::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) +{ + ASSERT(object); + ASSERT(context); +#ifndef NDEBUG + ASSERT(resourceMode == ApplyToDefaultMode); +#else + UNUSED_PARAM(resourceMode); +#endif + + return applyClippingToContext(object, object->objectBoundingBox(), object->repaintRectInLocalCoordinates(), context); +} + +bool RenderSVGResourceClipper::pathOnlyClipping(GraphicsContext* context, const FloatRect& objectBoundingBox) +{ + // If the current clip-path gets clipped itself, we have to fallback to masking. + if (!style()->svgStyle()->clipperResource().isEmpty()) + return false; + WindRule clipRule = RULE_NONZERO; + Path clipPath = Path(); + + // If clip-path only contains one visible shape or path, we can use path-based clipping. Invisible + // shapes don't affect the clipping and can be ignored. If clip-path contains more than one + // visible shape, the additive clipping may not work, caused by the clipRule. EvenOdd + // as well as NonZero can cause self-clipping of the elements. + // See also http://www.w3.org/TR/SVG/painting.html#FillRuleProperty + for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) { + RenderObject* renderer = childNode->renderer(); + if (!renderer) + continue; + // Only shapes or paths are supported for direct clipping. We need to fallback to masking for texts. + if (renderer->isSVGText()) + return false; + if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyledTransformable()) + continue; + SVGStyledTransformableElement* styled = static_cast<SVGStyledTransformableElement*>(childNode); + RenderStyle* style = renderer->style(); + if (!style || style->display() == NONE || style->visibility() != VISIBLE) + continue; + const SVGRenderStyle* svgStyle = style->svgStyle(); + // Current shape in clip-path gets clipped too. Fallback to masking. + if (!svgStyle->clipperResource().isEmpty()) + return false; + // Fallback to masking, if there is more than one clipping path. + if (clipPath.isEmpty()) { + styled->toClipPath(clipPath); + clipRule = svgStyle->clipRule(); + } else + return false; + } + // Only one visible shape/path was found. Directly continue clipping and transform the content to userspace if necessary. + if (static_cast<SVGClipPathElement*>(node())->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + AffineTransform transform; + transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); + transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); + clipPath.transform(transform); + } + // The SVG specification wants us to clip everything, if clip-path doesn't have a child. + if (clipPath.isEmpty()) + clipPath.addRect(FloatRect()); + context->clipPath(clipPath, clipRule); + return true; +} + +bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* object, const FloatRect& objectBoundingBox, + const FloatRect& repaintRect, GraphicsContext* context) +{ + if (!m_clipper.contains(object)) + m_clipper.set(object, new ClipperData); + + bool shouldCreateClipData = false; + ClipperData* clipperData = m_clipper.get(object); + if (!clipperData->clipMaskImage) { + if (pathOnlyClipping(context, objectBoundingBox)) + return true; + shouldCreateClipData = true; + } + + AffineTransform absoluteTransform; + SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform); + + FloatRect absoluteTargetRect = absoluteTransform.mapRect(repaintRect); + FloatRect clampedAbsoluteTargetRect = SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(object, absoluteTargetRect); + + if (shouldCreateClipData && !clampedAbsoluteTargetRect.isEmpty()) { + if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, clipperData->clipMaskImage, ColorSpaceDeviceRGB)) + return false; + + GraphicsContext* maskContext = clipperData->clipMaskImage->context(); + ASSERT(maskContext); + + // The save/restore pair is needed for clipToImageBuffer - it doesn't work without it on non-Cg platforms. + maskContext->save(); + maskContext->translate(-clampedAbsoluteTargetRect.x(), -clampedAbsoluteTargetRect.y()); + maskContext->concatCTM(absoluteTransform); + + // clipPath can also be clipped by another clipPath. + if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this)) { + if (RenderSVGResourceClipper* clipper = resources->clipper()) { + if (!clipper->applyClippingToContext(this, objectBoundingBox, repaintRect, maskContext)) { + maskContext->restore(); + return false; + } + } + } + + drawContentIntoMaskImage(clipperData, objectBoundingBox); + maskContext->restore(); + } + + if (!clipperData->clipMaskImage) + return false; + + SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, clampedAbsoluteTargetRect, clipperData->clipMaskImage); + return true; +} + +bool RenderSVGResourceClipper::drawContentIntoMaskImage(ClipperData* clipperData, const FloatRect& objectBoundingBox) +{ + ASSERT(clipperData); + ASSERT(clipperData->clipMaskImage); + + GraphicsContext* maskContext = clipperData->clipMaskImage->context(); + ASSERT(maskContext); + + AffineTransform maskContentTransformation; + SVGClipPathElement* clipPath = static_cast<SVGClipPathElement*>(node()); + if (clipPath->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + maskContentTransformation.translate(objectBoundingBox.x(), objectBoundingBox.y()); + maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); + maskContext->concatCTM(maskContentTransformation); + } + + // Draw all clipPath children into a global mask. + for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) { + RenderObject* renderer = childNode->renderer(); + if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer) + continue; + RenderStyle* style = renderer->style(); + if (!style || style->display() == NONE || style->visibility() != VISIBLE) + continue; + + WindRule newClipRule = style->svgStyle()->clipRule(); + bool isUseElement = renderer->isSVGShadowTreeRootContainer(); + if (isUseElement) { + SVGUseElement* useElement = static_cast<SVGUseElement*>(childNode); + renderer = useElement->rendererClipChild(); + if (!renderer) + continue; + if (!useElement->hasAttribute(SVGNames::clip_ruleAttr)) + newClipRule = renderer->style()->svgStyle()->clipRule(); + } + + // Only shapes, paths and texts are allowed for clipping. + if (!renderer->isSVGPath() && !renderer->isSVGText()) + continue; + + // Save the old RenderStyle of the current object for restoring after drawing + // it to the MaskImage. The new intermediate RenderStyle needs to inherit from + // the old one. + RefPtr<RenderStyle> oldRenderStyle = renderer->style(); + RefPtr<RenderStyle> newRenderStyle = RenderStyle::clone(oldRenderStyle.get()); + SVGRenderStyle* svgStyle = newRenderStyle.get()->accessSVGStyle(); + svgStyle->setFillPaint(SVGPaint::defaultFill()); + svgStyle->setStrokePaint(SVGPaint::defaultStroke()); + svgStyle->setFillRule(newClipRule); + newRenderStyle.get()->setOpacity(1.0f); + svgStyle->setFillOpacity(1.0f); + svgStyle->setStrokeOpacity(1.0f); + svgStyle->setFilterResource(String()); + svgStyle->setMaskerResource(String()); + + // The setStyle() call results in a styleDidChange() call, which in turn invalidations the resources. + // As we're mutating the resource on purpose, block updates until we've resetted the style again. + m_invalidationBlocked = true; + renderer->setStyle(newRenderStyle.release()); + + // In the case of a <use> element, we obtained its renderere above, to retrieve its clipRule. + // We have to pass the <use> renderer itself to renderSubtreeToImageBuffer() to apply it's x/y/transform/etc. values when rendering. + // So if isUseElement is true, refetch the childNode->renderer(), as renderer got overriden above. + SVGImageBufferTools::renderSubtreeToImageBuffer(clipperData->clipMaskImage.get(), isUseElement ? childNode->renderer() : renderer, maskContentTransformation); + + renderer->setStyle(oldRenderStyle.release()); + m_invalidationBlocked = false; + } + + return true; +} + +void RenderSVGResourceClipper::calculateClipContentRepaintRect() +{ + // This is a rough heuristic to appraise the clip size and doesn't consider clip on clip. + for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) { + RenderObject* renderer = childNode->renderer(); + if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer) + continue; + if (!renderer->isSVGPath() && !renderer->isSVGText() && !renderer->isSVGShadowTreeRootContainer()) + continue; + RenderStyle* style = renderer->style(); + if (!style || style->display() == NONE || style->visibility() != VISIBLE) + continue; + m_clipBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates())); + } +} + +bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundingBox, const FloatPoint& nodeAtPoint) +{ + FloatPoint point = nodeAtPoint; + if (!SVGRenderSupport::pointInClippingArea(this, point)) + return false; + + if (static_cast<SVGClipPathElement*>(node())->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + AffineTransform transform; + transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); + transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); + point = transform.inverse().mapPoint(point); + } + + for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) { + RenderObject* renderer = childNode->renderer(); + if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer) + continue; + if (!renderer->isSVGPath() && !renderer->isSVGText() && !renderer->isSVGShadowTreeRootContainer()) + continue; + IntPoint hitPoint; + HitTestResult result(hitPoint); + if (renderer->nodeAtFloatPoint(HitTestRequest(HitTestRequest::SVGClipContent), result, point, HitTestForeground)) + return true; + } + + return false; +} + +FloatRect RenderSVGResourceClipper::resourceBoundingBox(RenderObject* object) +{ + // Resource was not layouted yet. Give back the boundingBox of the object. + if (selfNeedsLayout()) + return object->objectBoundingBox(); + + if (m_clipBoundaries.isEmpty()) + calculateClipContentRepaintRect(); + + if (static_cast<SVGClipPathElement*>(node())->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + FloatRect objectBoundingBox = object->objectBoundingBox(); + AffineTransform transform; + transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); + transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); + return transform.mapRect(m_clipBoundaries); + } + + return m_clipBoundaries; +} + +} + +#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceClipper.h b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.h new file mode 100644 index 0000000..7f862a7 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. + * + * 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 RenderSVGResourceClipper_h +#define RenderSVGResourceClipper_h + +#if ENABLE(SVG) +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "ImageBuffer.h" +#include "IntSize.h" +#include "Path.h" +#include "RenderSVGResourceContainer.h" +#include "SVGClipPathElement.h" +#include "SVGUnitTypes.h" + +#include <wtf/HashMap.h> +#include <wtf/OwnPtr.h> + +namespace WebCore { + +struct ClipperData : FastAllocBase { + OwnPtr<ImageBuffer> clipMaskImage; +}; + +class RenderSVGResourceClipper : public RenderSVGResourceContainer { +public: + RenderSVGResourceClipper(SVGClipPathElement*); + virtual ~RenderSVGResourceClipper(); + + virtual const char* renderName() const { return "RenderSVGResourceClipper"; } + + virtual void removeAllClientsFromCache(bool markForInvalidation = true); + virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); + + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); + virtual FloatRect resourceBoundingBox(RenderObject*); + + virtual RenderSVGResourceType resourceType() const { return ClipperResourceType; } + + bool hitTestClipContent(const FloatRect&, const FloatPoint&); + + SVGUnitTypes::SVGUnitType clipPathUnits() const { return toUnitType(static_cast<SVGClipPathElement*>(node())->clipPathUnits()); } + + static RenderSVGResourceType s_resourceType; +private: + // clipPath can be clipped too, but don't have a boundingBox or repaintRect. So we can't call + // applyResource directly and use the rects from the object, since they are empty for RenderSVGResources + bool applyClippingToContext(RenderObject*, const FloatRect&, const FloatRect&, GraphicsContext*); + bool pathOnlyClipping(GraphicsContext*, const FloatRect&); + bool drawContentIntoMaskImage(ClipperData*, const FloatRect& objectBoundingBox); + void calculateClipContentRepaintRect(); + + bool m_invalidationBlocked; + FloatRect m_clipBoundaries; + HashMap<RenderObject*, ClipperData*> m_clipper; +}; + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp new file mode 100644 index 0000000..2a8a47f --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGResourceContainer.h" + +#include "RenderSVGShadowTreeRootContainer.h" +#include "SVGStyledTransformableElement.h" + +namespace WebCore { + +static inline SVGDocumentExtensions* svgExtensionsFromNode(Node* node) +{ + ASSERT(node); + ASSERT(node->document()); + return node->document()->accessSVGExtensions(); +} + +RenderSVGResourceContainer::RenderSVGResourceContainer(SVGStyledElement* node) + : RenderSVGHiddenContainer(node) + , m_id(node->hasID() ? node->getIdAttribute() : nullAtom) + , m_registered(false) +{ +} + +RenderSVGResourceContainer::~RenderSVGResourceContainer() +{ + if (m_registered) + svgExtensionsFromNode(node())->removeResource(m_id); +} + +void RenderSVGResourceContainer::layout() +{ + // Invalidate all resources if our layout changed. + if (m_everHadLayout && selfNeedsLayout()) + removeAllClientsFromCache(); + + RenderSVGHiddenContainer::layout(); +} + +void RenderSVGResourceContainer::destroy() +{ + SVGResourcesCache::resourceDestroyed(this); + RenderSVGHiddenContainer::destroy(); +} + +void RenderSVGResourceContainer::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderSVGHiddenContainer::styleDidChange(diff, oldStyle); + + if (!m_registered) { + m_registered = true; + registerResource(); + } +} + +void RenderSVGResourceContainer::idChanged() +{ + // Invalidate all our current clients. + removeAllClientsFromCache(); + + // Remove old id, that is guaranteed to be present in cache. + SVGDocumentExtensions* extensions = svgExtensionsFromNode(node()); + extensions->removeResource(m_id); + m_id = static_cast<Element*>(node())->getIdAttribute(); + + registerResource(); +} + +void RenderSVGResourceContainer::markAllClientsForInvalidation(InvalidationMode mode) +{ + if (m_clients.isEmpty()) + return; + + bool needsLayout = mode == LayoutAndBoundariesInvalidation; + bool markForInvalidation = mode != ParentOnlyInvalidation; + + HashSet<RenderObject*>::iterator end = m_clients.end(); + for (HashSet<RenderObject*>::iterator it = m_clients.begin(); it != end; ++it) { + RenderObject* client = *it; + if (client->isSVGResourceContainer()) { + client->toRenderSVGResourceContainer()->removeAllClientsFromCache(markForInvalidation); + continue; + } + + if (markForInvalidation) + markClientForInvalidation(client, mode); + + if (needsLayout) + client->setNeedsLayout(true); + + // Invalidate resources in ancestor chain, if needed. + RenderObject* current = client->parent(); + while (current) { + if (current->isSVGResourceContainer()) { + current->toRenderSVGResourceContainer()->removeAllClientsFromCache(markForInvalidation); + break; + } + + current = current->parent(); + } + } +} + +void RenderSVGResourceContainer::markClientForInvalidation(RenderObject* client, InvalidationMode mode) +{ + ASSERT(client); + ASSERT(!m_clients.isEmpty()); + + switch (mode) { + case LayoutAndBoundariesInvalidation: + case BoundariesInvalidation: + client->setNeedsBoundariesUpdate(); + break; + case RepaintInvalidation: + if (client->view()) + client->repaint(); + break; + case ParentOnlyInvalidation: + break; + } +} + +void RenderSVGResourceContainer::addClient(RenderObject* client) +{ + ASSERT(client); + m_clients.add(client); +} + +void RenderSVGResourceContainer::removeClient(RenderObject* client) +{ + ASSERT(client); + m_clients.remove(client); +} + +void RenderSVGResourceContainer::registerResource() +{ + SVGDocumentExtensions* extensions = svgExtensionsFromNode(node()); + if (!extensions->isPendingResource(m_id)) { + extensions->addResource(m_id, this); + return; + } + + OwnPtr<SVGDocumentExtensions::SVGPendingElements> clients(extensions->removePendingResource(m_id)); + + // Cache us with the new id. + extensions->addResource(m_id, this); + + // Update cached resources of pending clients. + const SVGDocumentExtensions::SVGPendingElements::const_iterator end = clients->end(); + for (SVGDocumentExtensions::SVGPendingElements::const_iterator it = clients->begin(); it != end; ++it) { + RenderObject* renderer = (*it)->renderer(); + if (!renderer) + continue; + SVGResourcesCache::clientUpdatedFromElement(renderer, renderer->style()); + renderer->setNeedsLayout(true); + } +} + +// FIXME: This does not belong here. +AffineTransform RenderSVGResourceContainer::transformOnNonScalingStroke(RenderObject* object, const AffineTransform& resourceTransform) +{ + if (!object->isSVGPath()) + return resourceTransform; + + SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(object->node()); + AffineTransform transform = resourceTransform; + transform.multiply(element->getScreenCTM(SVGLocatable::DisallowStyleUpdate)); + return transform; +} + +} + +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.h b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.h new file mode 100644 index 0000000..d98a83a --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 RenderSVGResourceContainer_h +#define RenderSVGResourceContainer_h + +#if ENABLE(SVG) +#include "RenderSVGHiddenContainer.h" +#include "RenderSVGResource.h" + +namespace WebCore { + +class RenderSVGResourceContainer : public RenderSVGHiddenContainer, + public RenderSVGResource { +public: + RenderSVGResourceContainer(SVGStyledElement*); + virtual ~RenderSVGResourceContainer(); + + virtual void layout(); + virtual void destroy(); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + + virtual bool isSVGResourceContainer() const { return true; } + virtual RenderSVGResourceContainer* toRenderSVGResourceContainer() { return this; } + + static AffineTransform transformOnNonScalingStroke(RenderObject*, const AffineTransform& resourceTransform); + + void idChanged(); + +protected: + enum InvalidationMode { + LayoutAndBoundariesInvalidation, + BoundariesInvalidation, + RepaintInvalidation, + ParentOnlyInvalidation + }; + + // Used from the invalidateClient/invalidateClients methods from classes, inheriting from us. + void markAllClientsForInvalidation(InvalidationMode); + void markClientForInvalidation(RenderObject*, InvalidationMode); + +private: + friend class SVGResourcesCache; + void addClient(RenderObject*); + void removeClient(RenderObject*); + +private: + void registerResource(); + + AtomicString m_id; + bool m_registered; + HashSet<RenderObject*> m_clients; +}; + +inline RenderSVGResourceContainer* getRenderSVGResourceContainerById(Document* document, const AtomicString& id) +{ + if (id.isEmpty()) + return 0; + + if (RenderSVGResourceContainer* renderResource = document->accessSVGExtensions()->resourceById(id)) + return renderResource; + + return 0; +} + +template<typename Renderer> +Renderer* getRenderSVGResourceById(Document* document, const AtomicString& id) +{ + if (RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id)) + return container->cast<Renderer>(); + + return 0; +} + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp new file mode 100644 index 0000000..4ba4e0a --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) && ENABLE(FILTERS) +#include "RenderSVGResourceFilter.h" + +#include "AffineTransform.h" +#include "FloatPoint.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "Image.h" +#include "ImageBuffer.h" +#include "ImageData.h" +#include "IntRect.h" +#include "RenderSVGResource.h" +#include "RenderSVGResourceFilterPrimitive.h" +#include "SVGElement.h" +#include "SVGFilter.h" +#include "SVGFilterElement.h" +#include "SVGFilterPrimitiveStandardAttributes.h" +#include "SVGImageBufferTools.h" +#include "SVGNames.h" +#include "SVGStyledElement.h" +#include "SVGUnitTypes.h" + +#include <wtf/UnusedParam.h> +#include <wtf/Vector.h> + +static const float kMaxFilterSize = 5000.0f; + +using namespace std; + +namespace WebCore { + +RenderSVGResourceType RenderSVGResourceFilter::s_resourceType = FilterResourceType; + +RenderSVGResourceFilter::RenderSVGResourceFilter(SVGFilterElement* node) + : RenderSVGResourceContainer(node) +{ +} + +RenderSVGResourceFilter::~RenderSVGResourceFilter() +{ + if (m_filter.isEmpty()) + return; + + deleteAllValues(m_filter); + m_filter.clear(); +} + +void RenderSVGResourceFilter::removeAllClientsFromCache(bool markForInvalidation) +{ + if (!m_filter.isEmpty()) { + deleteAllValues(m_filter); + m_filter.clear(); + } + + markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation); +} + +void RenderSVGResourceFilter::removeClientFromCache(RenderObject* client, bool markForInvalidation) +{ + ASSERT(client); + + if (m_filter.contains(client)) + delete m_filter.take(client); + + markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation); +} + +PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(Filter* filter) +{ + SVGFilterElement* filterElement = static_cast<SVGFilterElement*>(node()); + bool primitiveBoundingBoxMode = filterElement->primitiveUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; + + // Add effects to the builder + RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(filter); + for (Node* node = filterElement->firstChild(); node; node = node->nextSibling()) { + if (!node->isSVGElement()) + continue; + + SVGElement* element = static_cast<SVGElement*>(node); + if (!element->isFilterEffect()) + continue; + + SVGFilterPrimitiveStandardAttributes* effectElement = static_cast<SVGFilterPrimitiveStandardAttributes*>(element); + RefPtr<FilterEffect> effect = effectElement->build(builder.get(), filter); + if (!effect) { + builder->clearEffects(); + return 0; + } + builder->appendEffectToEffectReferences(effect); + effectElement->setStandardAttributes(primitiveBoundingBoxMode, effect.get()); + builder->add(effectElement->result(), effect); + } + return builder.release(); +} + +bool RenderSVGResourceFilter::fitsInMaximumImageSize(const FloatSize& size, FloatSize& scale) +{ + bool matchesFilterSize = true; + if (size.width() > kMaxFilterSize) { + scale.setWidth(scale.width() * kMaxFilterSize / size.width()); + matchesFilterSize = false; + } + if (size.height() > kMaxFilterSize) { + scale.setHeight(scale.height() * kMaxFilterSize / size.height()); + matchesFilterSize = false; + } + + return matchesFilterSize; +} + +bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) +{ + ASSERT(object); + ASSERT(context); +#ifndef NDEBUG + ASSERT(resourceMode == ApplyToDefaultMode); +#else + UNUSED_PARAM(resourceMode); +#endif + + // Returning false here, to avoid drawings onto the context. We just want to + // draw the stored filter output, not the unfiltered object as well. + if (m_filter.contains(object)) { + FilterData* filterData = m_filter.get(object); + if (filterData->builded) + return false; + + delete m_filter.take(object); // Oops, have to rebuild, go through normal code path + } + + OwnPtr<FilterData> filterData(new FilterData); + FloatRect targetBoundingBox = object->objectBoundingBox(); + + SVGFilterElement* filterElement = static_cast<SVGFilterElement*>(node()); + filterData->boundaries = filterElement->filterBoundingBox(targetBoundingBox); + if (filterData->boundaries.isEmpty()) + return false; + + // Determine absolute transformation matrix for filter. + AffineTransform absoluteTransform; + SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform); + if (!absoluteTransform.isInvertible()) + return false; + + // Eliminate shear of the absolute transformation matrix, to be able to produce unsheared tile images for feTile. + filterData->shearFreeAbsoluteTransform = AffineTransform(absoluteTransform.xScale(), 0, 0, absoluteTransform.yScale(), absoluteTransform.e(), absoluteTransform.f()); + + // Determine absolute boundaries of the filter and the drawing region. + FloatRect absoluteFilterBoundaries = filterData->shearFreeAbsoluteTransform.mapRect(filterData->boundaries); + FloatRect drawingRegion = object->strokeBoundingBox(); + drawingRegion.intersect(filterData->boundaries); + FloatRect absoluteDrawingRegion = filterData->shearFreeAbsoluteTransform.mapRect(drawingRegion); + + // Create the SVGFilter object. + bool primitiveBoundingBoxMode = filterElement->primitiveUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; + filterData->filter = SVGFilter::create(filterData->shearFreeAbsoluteTransform, absoluteDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundingBoxMode); + + // Create all relevant filter primitives. + filterData->builder = buildPrimitives(filterData->filter.get()); + if (!filterData->builder) + return false; + + // Calculate the scale factor for the use of filterRes. + // Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion + FloatSize scale(1, 1); + if (filterElement->hasAttribute(SVGNames::filterResAttr)) { + scale.setWidth(filterElement->filterResX() / absoluteFilterBoundaries.width()); + scale.setHeight(filterElement->filterResY() / absoluteFilterBoundaries.height()); + } + + if (scale.isEmpty()) + return false; + + // Determine scale factor for filter. The size of intermediate ImageBuffers shouldn't be bigger than kMaxFilterSize. + FloatRect tempSourceRect = absoluteDrawingRegion; + tempSourceRect.scale(scale.width(), scale.height()); + fitsInMaximumImageSize(tempSourceRect.size(), scale); + + // Set the scale level in SVGFilter. + filterData->filter->setFilterResolution(scale); + + FilterEffect* lastEffect = filterData->builder->lastEffect(); + if (!lastEffect) + return false; + + RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect, filterData->filter.get()); + FloatRect subRegion = lastEffect->maxEffectRect(); + // At least one FilterEffect has a too big image size, + // recalculate the effect sizes with new scale factors. + if (!fitsInMaximumImageSize(subRegion.size(), scale)) { + filterData->filter->setFilterResolution(scale); + RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect, filterData->filter.get()); + } + + // If the drawingRegion is empty, we have something like <g filter=".."/>. + // Even if the target objectBoundingBox() is empty, we still have to draw the last effect result image in postApplyResource. + if (drawingRegion.isEmpty()) { + ASSERT(!m_filter.contains(object)); + filterData->savedContext = context; + m_filter.set(object, filterData.leakPtr()); + return false; + } + + absoluteDrawingRegion.scale(scale.width(), scale.height()); + + OwnPtr<ImageBuffer> sourceGraphic; + if (!SVGImageBufferTools::createImageBuffer(absoluteDrawingRegion, absoluteDrawingRegion, sourceGraphic, ColorSpaceLinearRGB)) { + ASSERT(!m_filter.contains(object)); + filterData->savedContext = context; + m_filter.set(object, filterData.leakPtr()); + return false; + } + + GraphicsContext* sourceGraphicContext = sourceGraphic->context(); + ASSERT(sourceGraphicContext); + + sourceGraphicContext->translate(-absoluteDrawingRegion.x(), -absoluteDrawingRegion.y()); + if (scale.width() != 1 || scale.height() != 1) + sourceGraphicContext->scale(scale); + + sourceGraphicContext->concatCTM(filterData->shearFreeAbsoluteTransform); + sourceGraphicContext->clearRect(FloatRect(FloatPoint(), absoluteDrawingRegion.size())); + filterData->sourceGraphicBuffer = sourceGraphic.release(); + filterData->savedContext = context; + + context = sourceGraphicContext; + + ASSERT(!m_filter.contains(object)); + m_filter.set(object, filterData.leakPtr()); + + return true; +} + +void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsContext*& context, unsigned short resourceMode, const Path*) +{ + ASSERT(object); + ASSERT(context); +#ifndef NDEBUG + ASSERT(resourceMode == ApplyToDefaultMode); +#else + UNUSED_PARAM(resourceMode); +#endif + + if (!m_filter.contains(object)) + return; + + FilterData* filterData = m_filter.get(object); + if (!filterData->builded) { + if (!filterData->savedContext) { + removeClientFromCache(object); + return; + } + + context = filterData->savedContext; + filterData->savedContext = 0; +#if !PLATFORM(CG) + if (filterData->sourceGraphicBuffer) + filterData->sourceGraphicBuffer->transformColorSpace(ColorSpaceDeviceRGB, ColorSpaceLinearRGB); +#endif + } + + FilterEffect* lastEffect = filterData->builder->lastEffect(); + + if (lastEffect && !filterData->boundaries.isEmpty() && !lastEffect->filterPrimitiveSubregion().isEmpty()) { + // This is the real filtering of the object. It just needs to be called on the + // initial filtering process. We just take the stored filter result on a + // second drawing. + if (!filterData->builded) { + filterData->filter->setSourceImage(filterData->sourceGraphicBuffer.release()); + lastEffect->apply(); +#if !PLATFORM(CG) + ImageBuffer* resultImage = lastEffect->asImageBuffer(); + if (resultImage) + resultImage->transformColorSpace(ColorSpaceLinearRGB, ColorSpaceDeviceRGB); +#endif + filterData->builded = true; + } + + ImageBuffer* resultImage = lastEffect->asImageBuffer(); + if (resultImage) { + context->concatCTM(filterData->shearFreeAbsoluteTransform.inverse()); + + context->scale(FloatSize(1 / filterData->filter->filterResolution().width(), 1 / filterData->filter->filterResolution().height())); + context->clip(lastEffect->maxEffectRect()); + context->drawImageBuffer(resultImage, object->style()->colorSpace(), lastEffect->absolutePaintRect()); + context->scale(filterData->filter->filterResolution()); + + context->concatCTM(filterData->shearFreeAbsoluteTransform); + } + } + filterData->sourceGraphicBuffer.clear(); +} + +FloatRect RenderSVGResourceFilter::resourceBoundingBox(RenderObject* object) +{ + if (SVGFilterElement* element = static_cast<SVGFilterElement*>(node())) + return element->filterBoundingBox(object->objectBoundingBox()); + + return FloatRect(); +} + +} +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h new file mode 100644 index 0000000..f9a15ce --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 RenderSVGResourceFilter_h +#define RenderSVGResourceFilter_h + +#if ENABLE(SVG) && ENABLE(FILTERS) +#include "FloatRect.h" +#include "ImageBuffer.h" +#include "RenderSVGResourceContainer.h" +#include "SVGFilter.h" +#include "SVGFilterBuilder.h" +#include "SVGFilterElement.h" +#include "SVGUnitTypes.h" + +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +struct FilterData { + FilterData() + : savedContext(0) + , builded(false) + { + } + + RefPtr<SVGFilter> filter; + RefPtr<SVGFilterBuilder> builder; + OwnPtr<ImageBuffer> sourceGraphicBuffer; + GraphicsContext* savedContext; + AffineTransform shearFreeAbsoluteTransform; + FloatRect boundaries; + FloatSize scale; + bool builded; +}; + +class GraphicsContext; + +class RenderSVGResourceFilter : public RenderSVGResourceContainer { +public: + RenderSVGResourceFilter(SVGFilterElement*); + virtual ~RenderSVGResourceFilter(); + + virtual const char* renderName() const { return "RenderSVGResourceFilter"; } + + virtual void removeAllClientsFromCache(bool markForInvalidation = true); + virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); + + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*); + + virtual FloatRect resourceBoundingBox(RenderObject*); + + PassRefPtr<SVGFilterBuilder> buildPrimitives(Filter*); + + SVGUnitTypes::SVGUnitType filterUnits() const { return toUnitType(static_cast<SVGFilterElement*>(node())->filterUnits()); } + SVGUnitTypes::SVGUnitType primitiveUnits() const { return toUnitType(static_cast<SVGFilterElement*>(node())->primitiveUnits()); } + + virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + static RenderSVGResourceType s_resourceType; + +private: + bool fitsInMaximumImageSize(const FloatSize&, FloatSize&); + + HashMap<RenderObject*, FilterData*> m_filter; +}; + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp new file mode 100644 index 0000000..fc7362e --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2010 University of Szeged + * Copyright (C) 2010 Zoltan Herczeg + * + * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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) && ENABLE(FILTERS) +#include "RenderSVGResourceFilterPrimitive.h" + +#include "SVGFEImage.h" + +namespace WebCore { + +FloatRect RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(FilterEffect* effect, SVGFilter* filter) +{ + FloatRect uniteRect; + FloatRect subregionBoundingBox = effect->effectBoundaries(); + FloatRect subregion = subregionBoundingBox; + + if (effect->filterEffectType() != FilterEffectTypeTile) { + // FETurbulence, FEImage and FEFlood don't have input effects, take the filter region as unite rect. + if (unsigned numberOfInputEffects = effect->inputEffects().size()) { + for (unsigned i = 0; i < numberOfInputEffects; ++i) + uniteRect.unite(determineFilterPrimitiveSubregion(effect->inputEffect(i), filter)); + } else + uniteRect = filter->filterRegionInUserSpace(); + } else { + determineFilterPrimitiveSubregion(effect->inputEffect(0), filter); + uniteRect = filter->filterRegionInUserSpace(); + } + + if (filter->effectBoundingBoxMode()) { + subregion = uniteRect; + // Avoid the calling of a virtual method several times. + FloatRect targetBoundingBox = filter->targetBoundingBox(); + + if (effect->hasX()) + subregion.setX(targetBoundingBox.x() + subregionBoundingBox.x() * targetBoundingBox.width()); + + if (effect->hasY()) + subregion.setY(targetBoundingBox.y() + subregionBoundingBox.y() * targetBoundingBox.height()); + + if (effect->hasWidth()) + subregion.setWidth(subregionBoundingBox.width() * targetBoundingBox.width()); + + if (effect->hasHeight()) + subregion.setHeight(subregionBoundingBox.height() * targetBoundingBox.height()); + } else { + if (!effect->hasX()) + subregion.setX(uniteRect.x()); + + if (!effect->hasY()) + subregion.setY(uniteRect.y()); + + if (!effect->hasWidth()) + subregion.setWidth(uniteRect.width()); + + if (!effect->hasHeight()) + subregion.setHeight(uniteRect.height()); + } + + effect->setFilterPrimitiveSubregion(subregion); + + FloatRect absoluteSubregion = filter->mapLocalRectToAbsoluteRect(subregion); + FloatSize filterResolution = filter->filterResolution(); + absoluteSubregion.scale(filterResolution.width(), filterResolution.height()); + + // FEImage needs the unclipped subregion in absolute coordinates to determine the correct + // destination rect in combination with preserveAspectRatio. + if (effect->filterEffectType() == FilterEffectTypeImage) + reinterpret_cast<FEImage*>(effect)->setAbsoluteSubregion(absoluteSubregion); + + // Clip every filter effect to the filter region. + FloatRect absoluteScaledFilterRegion = filter->filterRegion(); + absoluteScaledFilterRegion.scale(filterResolution.width(), filterResolution.height()); + absoluteSubregion.intersect(absoluteScaledFilterRegion); + + effect->setMaxEffectRect(enclosingIntRect(absoluteSubregion)); + return subregion; +} + +} // namespace WebCore + +#endif // ENABLE(SVG) && ENABLE(FILTERS) diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h new file mode 100644 index 0000000..f25f62e --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2010 University of Szeged + * Copyright (C) 2010 Zoltan Herczeg + * + * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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. + */ + +#ifndef RenderSVGResourceFilterPrimitive_h +#define RenderSVGResourceFilterPrimitive_h + +#if ENABLE(SVG) && ENABLE(FILTERS) + +#include "RenderSVGHiddenContainer.h" +#include "SVGFilter.h" +#include "SVGFilterPrimitiveStandardAttributes.h" + +namespace WebCore { + +class RenderSVGResourceFilterPrimitive : public RenderSVGHiddenContainer { +public: + + explicit RenderSVGResourceFilterPrimitive(SVGFilterPrimitiveStandardAttributes* filterPrimitiveElement) + : RenderSVGHiddenContainer(filterPrimitiveElement) + { + } + + // They depend on the RenderObject argument of RenderSVGResourceFilter::applyResource. + static FloatRect determineFilterPrimitiveSubregion(FilterEffect*, SVGFilter*); + +private: + virtual const char* renderName() const { return "RenderSVGResourceFilterPrimitive"; } + virtual bool isSVGResourceFilterPrimitive() const { return true; } +}; + +} // namespace WebCore + +#endif // ENABLE(SVG) && ENABLE(FILTERS) + +#endif // RenderSVGResourceFilterPrimitive_h diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp new file mode 100644 index 0000000..5ad5d84 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2008 Eric Seidel <eric@webkit.org> + * Copyright (C) 2008 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGResourceGradient.h" + +#include "GradientAttributes.h" +#include "GraphicsContext.h" +#include "RenderSVGText.h" +#include "SVGImageBufferTools.h" +#include "SVGRenderSupport.h" +#include <wtf/UnusedParam.h> + +namespace WebCore { + +RenderSVGResourceGradient::RenderSVGResourceGradient(SVGGradientElement* node) + : RenderSVGResourceContainer(node) + , m_shouldCollectGradientAttributes(true) +#if PLATFORM(CG) + , m_savedContext(0) +#endif +{ +} + +RenderSVGResourceGradient::~RenderSVGResourceGradient() +{ + if (m_gradient.isEmpty()) + return; + + deleteAllValues(m_gradient); + m_gradient.clear(); +} + +void RenderSVGResourceGradient::removeAllClientsFromCache(bool markForInvalidation) +{ + if (!m_gradient.isEmpty()) { + deleteAllValues(m_gradient); + m_gradient.clear(); + } + + m_shouldCollectGradientAttributes = true; + markAllClientsForInvalidation(markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation); +} + +void RenderSVGResourceGradient::removeClientFromCache(RenderObject* client, bool markForInvalidation) +{ + ASSERT(client); + + if (m_gradient.contains(client)) + delete m_gradient.take(client); + + markClientForInvalidation(client, markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation); +} + +#if PLATFORM(CG) +static inline bool createMaskAndSwapContextForTextGradient(GraphicsContext*& context, + GraphicsContext*& savedContext, + OwnPtr<ImageBuffer>& imageBuffer, + RenderObject* object) +{ + RenderObject* textRootBlock = RenderSVGText::locateRenderSVGTextAncestor(object); + ASSERT(textRootBlock); + + AffineTransform absoluteTransform; + SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(textRootBlock, absoluteTransform); + + FloatRect absoluteTargetRect = absoluteTransform.mapRect(textRootBlock->repaintRectInLocalCoordinates()); + FloatRect clampedAbsoluteTargetRect = SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(textRootBlock, absoluteTargetRect); + if (clampedAbsoluteTargetRect.isEmpty()) + return false; + + OwnPtr<ImageBuffer> maskImage; + if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, maskImage, ColorSpaceDeviceRGB)) + return false; + + GraphicsContext* maskImageContext = maskImage->context(); + ASSERT(maskImageContext); + + maskImageContext->translate(-clampedAbsoluteTargetRect.x(), -clampedAbsoluteTargetRect.y()); + maskImageContext->concatCTM(absoluteTransform); + + ASSERT(maskImage); + savedContext = context; + context = maskImageContext; + imageBuffer = maskImage.release(); + return true; +} + +static inline AffineTransform clipToTextMask(GraphicsContext* context, + OwnPtr<ImageBuffer>& imageBuffer, + FloatRect& targetRect, + RenderObject* object, + bool boundingBoxMode, + const AffineTransform& gradientTransform) +{ + RenderObject* textRootBlock = RenderSVGText::locateRenderSVGTextAncestor(object); + ASSERT(textRootBlock); + + targetRect = textRootBlock->repaintRectInLocalCoordinates(); + + AffineTransform absoluteTransform; + SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(textRootBlock, absoluteTransform); + + FloatRect absoluteTargetRect = absoluteTransform.mapRect(targetRect); + FloatRect clampedAbsoluteTargetRect = SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(textRootBlock, absoluteTargetRect); + + SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, clampedAbsoluteTargetRect, imageBuffer); + + AffineTransform matrix; + if (boundingBoxMode) { + FloatRect maskBoundingBox = textRootBlock->objectBoundingBox(); + matrix.translate(maskBoundingBox.x(), maskBoundingBox.y()); + matrix.scaleNonUniform(maskBoundingBox.width(), maskBoundingBox.height()); + } + matrix.multLeft(gradientTransform); + return matrix; +} +#endif + +bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle* style, GraphicsContext*& context, unsigned short resourceMode) +{ + ASSERT(object); + ASSERT(style); + ASSERT(context); + ASSERT(resourceMode != ApplyToDefaultMode); + + // Be sure to synchronize all SVG properties on the gradientElement _before_ processing any further. + // Otherwhise the call to collectGradientAttributes() in createTileImage(), may cause the SVG DOM property + // synchronization to kick in, which causes removeAllClientsFromCache() to be called, which in turn deletes our + // GradientData object! Leaving out the line below will cause svg/dynamic-updates/SVG*GradientElement-svgdom* to crash. + SVGGradientElement* gradientElement = static_cast<SVGGradientElement*>(node()); + if (!gradientElement) + return false; + + if (m_shouldCollectGradientAttributes) { + gradientElement->updateAnimatedSVGAttribute(anyQName()); + collectGradientAttributes(gradientElement); + m_shouldCollectGradientAttributes = false; + } + + // Spec: When the geometry of the applicable element has no width or height and objectBoundingBox is specified, + // then the given effect (e.g. a gradient or a filter) will be ignored. + FloatRect objectBoundingBox = object->objectBoundingBox(); + if (boundingBoxMode() && objectBoundingBox.isEmpty()) + return false; + + if (!m_gradient.contains(object)) + m_gradient.set(object, new GradientData); + + GradientData* gradientData = m_gradient.get(object); + bool isPaintingText = resourceMode & ApplyToTextMode; + + // Create gradient object + if (!gradientData->gradient) { + buildGradient(gradientData, gradientElement); + + // CG platforms will handle the gradient space transform for text after applying the + // resource, so don't apply it here. For non-CG platforms, we want the text bounding + // box applied to the gradient space transform now, so the gradient shader can use it. +#if PLATFORM(CG) + if (boundingBoxMode() && !objectBoundingBox.isEmpty() && !isPaintingText) { +#else + if (boundingBoxMode() && !objectBoundingBox.isEmpty()) { +#endif + gradientData->userspaceTransform.translate(objectBoundingBox.x(), objectBoundingBox.y()); + gradientData->userspaceTransform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); + } + + AffineTransform gradientTransform; + calculateGradientTransform(gradientTransform); + + gradientData->userspaceTransform.multLeft(gradientTransform); + gradientData->gradient->setGradientSpaceTransform(gradientData->userspaceTransform); + } + + if (!gradientData->gradient) + return false; + + // Draw gradient + context->save(); + + if (isPaintingText) { +#if PLATFORM(CG) + if (!createMaskAndSwapContextForTextGradient(context, m_savedContext, m_imageBuffer, object)) { + context->restore(); + return false; + } +#endif + + context->setTextDrawingMode(resourceMode & ApplyToFillMode ? TextModeFill : TextModeStroke); + } + + const SVGRenderStyle* svgStyle = style->svgStyle(); + ASSERT(svgStyle); + + if (resourceMode & ApplyToFillMode) { + context->setAlpha(svgStyle->fillOpacity()); + context->setFillGradient(gradientData->gradient); + context->setFillRule(svgStyle->fillRule()); + } else if (resourceMode & ApplyToStrokeMode) { + if (svgStyle->vectorEffect() == VE_NON_SCALING_STROKE) + gradientData->gradient->setGradientSpaceTransform(transformOnNonScalingStroke(object, gradientData->userspaceTransform)); + context->setAlpha(svgStyle->strokeOpacity()); + context->setStrokeGradient(gradientData->gradient); + SVGRenderSupport::applyStrokeStyleToContext(context, style, object); + } + + return true; +} + +void RenderSVGResourceGradient::postApplyResource(RenderObject* object, GraphicsContext*& context, unsigned short resourceMode, const Path* path) +{ + ASSERT(context); + ASSERT(resourceMode != ApplyToDefaultMode); + + if (resourceMode & ApplyToTextMode) { +#if PLATFORM(CG) + // CG requires special handling for gradient on text + if (m_savedContext && m_gradient.contains(object)) { + GradientData* gradientData = m_gradient.get(object); + + // Restore on-screen drawing context + context = m_savedContext; + m_savedContext = 0; + + AffineTransform gradientTransform; + calculateGradientTransform(gradientTransform); + + FloatRect targetRect; + gradientData->gradient->setGradientSpaceTransform(clipToTextMask(context, m_imageBuffer, targetRect, object, boundingBoxMode(), gradientTransform)); + context->setFillGradient(gradientData->gradient); + + context->fillRect(targetRect); + m_imageBuffer.clear(); + } +#else + UNUSED_PARAM(object); +#endif + } else if (path) { + if (resourceMode & ApplyToFillMode) + context->fillPath(*path); + else if (resourceMode & ApplyToStrokeMode) + context->strokePath(*path); + } + + context->restore(); +} + +void RenderSVGResourceGradient::addStops(GradientData* gradientData, const Vector<Gradient::ColorStop>& stops) const +{ + ASSERT(gradientData->gradient); + + const Vector<Gradient::ColorStop>::const_iterator end = stops.end(); + for (Vector<Gradient::ColorStop>::const_iterator it = stops.begin(); it != end; ++it) + gradientData->gradient->addColorStop(*it); +} + +} + +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h new file mode 100644 index 0000000..ad40b53 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2008 Eric Seidel <eric@webkit.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 RenderSVGResourceGradient_h +#define RenderSVGResourceGradient_h + +#if ENABLE(SVG) +#include "AffineTransform.h" +#include "FloatRect.h" +#include "Gradient.h" +#include "ImageBuffer.h" +#include "RenderSVGResourceContainer.h" +#include "SVGGradientElement.h" + +#include <wtf/HashMap.h> + +namespace WebCore { + +struct GradientData { + RefPtr<Gradient> gradient; + AffineTransform userspaceTransform; +}; + +class GraphicsContext; + +class RenderSVGResourceGradient : public RenderSVGResourceContainer { +public: + RenderSVGResourceGradient(SVGGradientElement*); + virtual ~RenderSVGResourceGradient(); + + virtual void removeAllClientsFromCache(bool markForInvalidation = true); + virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); + + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*); + virtual FloatRect resourceBoundingBox(RenderObject*) { return FloatRect(); } + +protected: + void addStops(GradientData*, const Vector<Gradient::ColorStop>&) const; + + virtual bool boundingBoxMode() const = 0; + virtual void calculateGradientTransform(AffineTransform&) = 0; + virtual void collectGradientAttributes(SVGGradientElement*) = 0; + virtual void buildGradient(GradientData*, SVGGradientElement*) const = 0; + +private: + bool m_shouldCollectGradientAttributes : 1; + HashMap<RenderObject*, GradientData*> m_gradient; + +#if PLATFORM(CG) + GraphicsContext* m_savedContext; + OwnPtr<ImageBuffer> m_imageBuffer; +#endif +}; + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp new file mode 100644 index 0000000..14dbd8c --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGResourceLinearGradient.h" + +#include "LinearGradientAttributes.h" +#include "SVGLinearGradientElement.h" + +namespace WebCore { + +RenderSVGResourceType RenderSVGResourceLinearGradient::s_resourceType = LinearGradientResourceType; + +RenderSVGResourceLinearGradient::RenderSVGResourceLinearGradient(SVGLinearGradientElement* node) + : RenderSVGResourceGradient(node) +{ +} + +RenderSVGResourceLinearGradient::~RenderSVGResourceLinearGradient() +{ +} + +void RenderSVGResourceLinearGradient::collectGradientAttributes(SVGGradientElement* gradientElement) +{ + m_attributes = LinearGradientAttributes(); + static_cast<SVGLinearGradientElement*>(gradientElement)->collectGradientAttributes(m_attributes); +} + +void RenderSVGResourceLinearGradient::buildGradient(GradientData* gradientData, SVGGradientElement* gradientElement) const +{ + SVGLinearGradientElement* linearGradientElement = static_cast<SVGLinearGradientElement*>(gradientElement); + + // Determine gradient start/end points + FloatPoint startPoint; + FloatPoint endPoint; + linearGradientElement->calculateStartEndPoints(m_attributes, startPoint, endPoint); + + gradientData->gradient = Gradient::create(startPoint, endPoint); + gradientData->gradient->setSpreadMethod(m_attributes.spreadMethod()); + + // Add stops + addStops(gradientData, m_attributes.stops()); +} + +} + +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.h b/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.h new file mode 100644 index 0000000..2d35418 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 RenderSVGResourceLinearGradient_h +#define RenderSVGResourceLinearGradient_h + +#if ENABLE(SVG) +#include "LinearGradientAttributes.h" +#include "RenderSVGResourceGradient.h" + +namespace WebCore { + +class SVGLinearGradientElement; + +class RenderSVGResourceLinearGradient : public RenderSVGResourceGradient { +public: + RenderSVGResourceLinearGradient(SVGLinearGradientElement*); + virtual ~RenderSVGResourceLinearGradient(); + + virtual const char* renderName() const { return "RenderSVGResourceLinearGradient"; } + + virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + static RenderSVGResourceType s_resourceType; + + virtual bool boundingBoxMode() const { return m_attributes.boundingBoxMode(); } + virtual void calculateGradientTransform(AffineTransform& transform) { transform = m_attributes.gradientTransform(); } + virtual void collectGradientAttributes(SVGGradientElement*); + virtual void buildGradient(GradientData*, SVGGradientElement*) const; + +private: + LinearGradientAttributes m_attributes; +}; + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp new file mode 100644 index 0000000..2a68d92 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Rob Buis <buis@kde.org> + * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGResourceMarker.h" + +#include "GraphicsContext.h" +#include "RenderSVGContainer.h" +#include "SVGElement.h" +#include "SVGMarkerElement.h" +#include "SVGRenderSupport.h" +#include "SVGStyledElement.h" +#include "SVGStyledTransformableElement.h" + +namespace WebCore { + +RenderSVGResourceType RenderSVGResourceMarker::s_resourceType = MarkerResourceType; + +RenderSVGResourceMarker::RenderSVGResourceMarker(SVGMarkerElement* node) + : RenderSVGResourceContainer(node) +{ +} + +RenderSVGResourceMarker::~RenderSVGResourceMarker() +{ +} + +void RenderSVGResourceMarker::layout() +{ + // Invalidate all resources if our layout changed. + if (m_everHadLayout && selfNeedsLayout()) + removeAllClientsFromCache(); + + // RenderSVGHiddenContainer overwrites layout(). We need the + // layouting of RenderSVGContainer for calculating local + // transformations and repaint. + RenderSVGContainer::layout(); +} + +void RenderSVGResourceMarker::removeAllClientsFromCache(bool markForInvalidation) +{ + markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation); +} + +void RenderSVGResourceMarker::removeClientFromCache(RenderObject* client, bool markForInvalidation) +{ + ASSERT(client); + markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation); +} + +void RenderSVGResourceMarker::applyViewportClip(PaintInfo& paintInfo) +{ + if (SVGRenderSupport::isOverflowHidden(this)) + paintInfo.context->clip(m_viewport); +} + +FloatRect RenderSVGResourceMarker::markerBoundaries(const AffineTransform& markerTransformation) const +{ + FloatRect coordinates = RenderSVGContainer::repaintRectInLocalCoordinates(); + + // Map repaint rect into parent coordinate space, in which the marker boundaries have to be evaluated + coordinates = localToParentTransform().mapRect(coordinates); + + return markerTransformation.mapRect(coordinates); +} + +const AffineTransform& RenderSVGResourceMarker::localToParentTransform() const +{ + AffineTransform viewportTranslation(viewportTransform()); + m_localToParentTransform = viewportTranslation.translateRight(m_viewport.x(), m_viewport.y()); + return m_localToParentTransform; + // If this class were ever given a localTransform(), then the above would read: + // return viewportTransform() * localTransform() * viewportTranslation; +} + +FloatPoint RenderSVGResourceMarker::referencePoint() const +{ + SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node()); + ASSERT(marker); + + return FloatPoint(marker->refX().value(marker), marker->refY().value(marker)); +} + +float RenderSVGResourceMarker::angle() const +{ + SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node()); + ASSERT(marker); + + float angle = -1; + if (marker->orientType() == SVGMarkerElement::SVG_MARKER_ORIENT_ANGLE) + angle = marker->orientAngle().value(); + + return angle; +} + +AffineTransform RenderSVGResourceMarker::markerTransformation(const FloatPoint& origin, float autoAngle, float strokeWidth) const +{ + SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node()); + ASSERT(marker); + + float markerAngle = angle(); + bool useStrokeWidth = (marker->markerUnits() == SVGMarkerElement::SVG_MARKERUNITS_STROKEWIDTH); + + AffineTransform transform; + transform.translate(origin.x(), origin.y()); + transform.rotate(markerAngle == -1 ? autoAngle : markerAngle); + transform = markerContentTransformation(transform, referencePoint(), useStrokeWidth ? strokeWidth : -1); + return transform; +} + +void RenderSVGResourceMarker::draw(PaintInfo& paintInfo, const AffineTransform& transform) +{ + PaintInfo info(paintInfo); + info.context->save(); + info.applyTransform(transform); + RenderSVGContainer::paint(info, 0, 0); + info.context->restore(); +} + +AffineTransform RenderSVGResourceMarker::markerContentTransformation(const AffineTransform& contentTransformation, const FloatPoint& origin, float strokeWidth) const +{ + // The 'origin' coordinate maps to SVGs refX/refY, given in coordinates relative to the viewport established by the marker + FloatPoint mappedOrigin = viewportTransform().mapPoint(origin); + + AffineTransform transformation = contentTransformation; + if (strokeWidth != -1) + transformation.scaleNonUniform(strokeWidth, strokeWidth); + + transformation.translate(-mappedOrigin.x(), -mappedOrigin.y()); + return transformation; +} + +AffineTransform RenderSVGResourceMarker::viewportTransform() const +{ + SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node()); + ASSERT(marker); + + return marker->viewBoxToViewTransform(m_viewport.width(), m_viewport.height()); +} + +void RenderSVGResourceMarker::calcViewport() +{ + if (!selfNeedsLayout()) + return; + + SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node()); + ASSERT(marker); + + float w = marker->markerWidth().value(marker); + float h = marker->markerHeight().value(marker); + m_viewport = FloatRect(0, 0, w, h); +} + +} + +#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h new file mode 100644 index 0000000..fd3b5e3 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. + * + * 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 RenderSVGResourceMarker_h +#define RenderSVGResourceMarker_h + +#if ENABLE(SVG) +#include "FloatRect.h" +#include "RenderObject.h" +#include "RenderSVGResourceContainer.h" +#include "SVGMarkerElement.h" +#include "SVGStyledElement.h" + +#include <wtf/HashSet.h> + +namespace WebCore { + +class AffineTransform; + +class RenderSVGResourceMarker : public RenderSVGResourceContainer { +public: + RenderSVGResourceMarker(SVGMarkerElement*); + virtual ~RenderSVGResourceMarker(); + + virtual const char* renderName() const { return "RenderSVGResourceMarker"; } + + virtual void removeAllClientsFromCache(bool markForInvalidation = true); + virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); + + void draw(PaintInfo&, const AffineTransform&); + + // Calculates marker boundaries, mapped to the target element's coordinate space + FloatRect markerBoundaries(const AffineTransform& markerTransformation) const; + + virtual void applyViewportClip(PaintInfo&); + virtual void layout(); + virtual void calcViewport(); + + virtual const AffineTransform& localToParentTransform() const; + AffineTransform markerTransformation(const FloatPoint& origin, float angle, float strokeWidth) const; + + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short) { return false; } + virtual FloatRect resourceBoundingBox(RenderObject*) { return FloatRect(); } + + FloatPoint referencePoint() const; + float angle() const; + SVGMarkerElement::SVGMarkerUnitsType markerUnits() const { return static_cast<SVGMarkerElement::SVGMarkerUnitsType>(static_cast<SVGMarkerElement*>(node())->markerUnits()); } + + virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + static RenderSVGResourceType s_resourceType; + +private: + // Generates a transformation matrix usable to render marker content. Handles scaling the marker content + // acording to SVGs markerUnits="strokeWidth" concept, when a strokeWidth value != -1 is passed in. + AffineTransform markerContentTransformation(const AffineTransform& contentTransformation, const FloatPoint& origin, float strokeWidth = -1) const; + + AffineTransform viewportTransform() const; + + mutable AffineTransform m_localToParentTransform; + FloatRect m_viewport; +}; + +} +#endif + +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp new file mode 100644 index 0000000..7b24248 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp @@ -0,0 +1,223 @@ +/* + * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGResourceMasker.h" + +#include "AffineTransform.h" +#include "Element.h" +#include "FloatPoint.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "Image.h" +#include "ImageBuffer.h" +#include "IntRect.h" +#include "RenderSVGResource.h" +#include "SVGElement.h" +#include "SVGImageBufferTools.h" +#include "SVGMaskElement.h" +#include "SVGStyledElement.h" +#include "SVGUnitTypes.h" + +#include <wtf/ByteArray.h> +#include <wtf/UnusedParam.h> +#include <wtf/Vector.h> + +namespace WebCore { + +RenderSVGResourceType RenderSVGResourceMasker::s_resourceType = MaskerResourceType; + +RenderSVGResourceMasker::RenderSVGResourceMasker(SVGMaskElement* node) + : RenderSVGResourceContainer(node) +{ +} + +RenderSVGResourceMasker::~RenderSVGResourceMasker() +{ + if (m_masker.isEmpty()) + return; + + deleteAllValues(m_masker); + m_masker.clear(); +} + +void RenderSVGResourceMasker::removeAllClientsFromCache(bool markForInvalidation) +{ + m_maskContentBoundaries = FloatRect(); + if (!m_masker.isEmpty()) { + deleteAllValues(m_masker); + m_masker.clear(); + } + + markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation); +} + +void RenderSVGResourceMasker::removeClientFromCache(RenderObject* client, bool markForInvalidation) +{ + ASSERT(client); + + if (m_masker.contains(client)) + delete m_masker.take(client); + + markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation); +} + +bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) +{ + ASSERT(object); + ASSERT(context); +#ifndef NDEBUG + ASSERT(resourceMode == ApplyToDefaultMode); +#else + UNUSED_PARAM(resourceMode); +#endif + + if (!m_masker.contains(object)) + m_masker.set(object, new MaskerData); + + MaskerData* maskerData = m_masker.get(object); + + AffineTransform absoluteTransform; + SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform); + + FloatRect absoluteTargetRect = absoluteTransform.mapRect(object->repaintRectInLocalCoordinates()); + FloatRect clampedAbsoluteTargetRect = SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(object, absoluteTargetRect); + + if (!maskerData->maskImage && !clampedAbsoluteTargetRect.isEmpty()) { + SVGMaskElement* maskElement = static_cast<SVGMaskElement*>(node()); + if (!maskElement) + return false; + + if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, maskerData->maskImage, ColorSpaceLinearRGB)) + return false; + + GraphicsContext* maskImageContext = maskerData->maskImage->context(); + ASSERT(maskImageContext); + + // The save/restore pair is needed for clipToImageBuffer - it doesn't work without it on non-Cg platforms. + maskImageContext->save(); + maskImageContext->translate(-clampedAbsoluteTargetRect.x(), -clampedAbsoluteTargetRect.y()); + maskImageContext->concatCTM(absoluteTransform); + + drawContentIntoMaskImage(maskerData, maskElement, object); + } + + if (!maskerData->maskImage) + return false; + + SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, clampedAbsoluteTargetRect, maskerData->maskImage); + return true; +} + +void RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, const SVGMaskElement* maskElement, RenderObject* object) +{ + GraphicsContext* maskImageContext = maskerData->maskImage->context(); + ASSERT(maskImageContext); + + // Eventually adjust the mask image context according to the target objectBoundingBox. + AffineTransform maskContentTransformation; + if (maskElement->maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + FloatRect objectBoundingBox = object->objectBoundingBox(); + maskContentTransformation.translate(objectBoundingBox.x(), objectBoundingBox.y()); + maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); + maskImageContext->concatCTM(maskContentTransformation); + } + + // Draw the content into the ImageBuffer. + for (Node* node = maskElement->firstChild(); node; node = node->nextSibling()) { + RenderObject* renderer = node->renderer(); + if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !renderer) + continue; + RenderStyle* style = renderer->style(); + if (!style || style->display() == NONE || style->visibility() != VISIBLE) + continue; + SVGImageBufferTools::renderSubtreeToImageBuffer(maskerData->maskImage.get(), renderer, maskContentTransformation); + } + + maskImageContext->restore(); + +#if !PLATFORM(CG) + maskerData->maskImage->transformColorSpace(ColorSpaceDeviceRGB, ColorSpaceLinearRGB); +#endif + + // Create the luminance mask. + IntRect maskImageRect(IntPoint(), maskerData->maskImage->size()); + RefPtr<ByteArray> srcPixelArray = maskerData->maskImage->getUnmultipliedImageData(maskImageRect); + + unsigned pixelArrayLength = srcPixelArray->length(); + for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) { + unsigned char a = srcPixelArray->get(pixelOffset + 3); + if (!a) + continue; + unsigned char r = srcPixelArray->get(pixelOffset); + unsigned char g = srcPixelArray->get(pixelOffset + 1); + unsigned char b = srcPixelArray->get(pixelOffset + 2); + + double luma = (r * 0.2125 + g * 0.7154 + b * 0.0721) * ((double)a / 255.0); + srcPixelArray->set(pixelOffset + 3, luma); + } + + maskerData->maskImage->putUnmultipliedImageData(srcPixelArray.get(), maskImageRect.size(), maskImageRect, IntPoint()); +} + +void RenderSVGResourceMasker::calculateMaskContentRepaintRect() +{ + for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) { + RenderObject* renderer = childNode->renderer(); + if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer) + continue; + RenderStyle* style = renderer->style(); + if (!style || style->display() == NONE || style->visibility() != VISIBLE) + continue; + m_maskContentBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates())); + } +} + +FloatRect RenderSVGResourceMasker::resourceBoundingBox(RenderObject* object) +{ + SVGMaskElement* maskElement = static_cast<SVGMaskElement*>(node()); + ASSERT(maskElement); + + FloatRect objectBoundingBox = object->objectBoundingBox(); + FloatRect maskBoundaries = maskElement->maskBoundingBox(objectBoundingBox); + + // Resource was not layouted yet. Give back clipping rect of the mask. + if (selfNeedsLayout()) + return maskBoundaries; + + if (m_maskContentBoundaries.isEmpty()) + calculateMaskContentRepaintRect(); + + FloatRect maskRect = m_maskContentBoundaries; + if (maskElement->maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + AffineTransform transform; + transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); + transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); + maskRect = transform.mapRect(maskRect); + } + + maskRect.intersect(maskBoundaries); + return maskRect; +} + +} + +#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMasker.h b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.h new file mode 100644 index 0000000..0a7deb1 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. + * + * 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 RenderSVGResourceMasker_h +#define RenderSVGResourceMasker_h + +#if ENABLE(SVG) +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "ImageBuffer.h" +#include "IntSize.h" +#include "RenderSVGResourceContainer.h" +#include "SVGMaskElement.h" +#include "SVGUnitTypes.h" + +#include <wtf/HashMap.h> +#include <wtf/OwnPtr.h> + +namespace WebCore { + +struct MaskerData { + OwnPtr<ImageBuffer> maskImage; +}; + +class RenderSVGResourceMasker : public RenderSVGResourceContainer { +public: + RenderSVGResourceMasker(SVGMaskElement*); + virtual ~RenderSVGResourceMasker(); + + virtual const char* renderName() const { return "RenderSVGResourceMasker"; } + + virtual void removeAllClientsFromCache(bool markForInvalidation = true); + virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); + virtual FloatRect resourceBoundingBox(RenderObject*); + + SVGUnitTypes::SVGUnitType maskUnits() const { return toUnitType(static_cast<SVGMaskElement*>(node())->maskUnits()); } + SVGUnitTypes::SVGUnitType maskContentUnits() const { return toUnitType(static_cast<SVGMaskElement*>(node())->maskContentUnits()); } + + virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + static RenderSVGResourceType s_resourceType; + +private: + void drawContentIntoMaskImage(MaskerData*, const SVGMaskElement*, RenderObject*); + void calculateMaskContentRepaintRect(); + + FloatRect m_maskContentBoundaries; + HashMap<RenderObject*, MaskerData*> m_masker; +}; + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp new file mode 100644 index 0000000..330a21a --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGResourcePattern.h" + +#include "FrameView.h" +#include "GraphicsContext.h" +#include "PatternAttributes.h" +#include "RenderSVGRoot.h" +#include "SVGImageBufferTools.h" +#include "SVGRenderSupport.h" + +namespace WebCore { + +RenderSVGResourceType RenderSVGResourcePattern::s_resourceType = PatternResourceType; + +RenderSVGResourcePattern::RenderSVGResourcePattern(SVGPatternElement* node) + : RenderSVGResourceContainer(node) + , m_shouldCollectPatternAttributes(true) +{ +} + +RenderSVGResourcePattern::~RenderSVGResourcePattern() +{ + if (m_pattern.isEmpty()) + return; + + deleteAllValues(m_pattern); + m_pattern.clear(); +} + +void RenderSVGResourcePattern::removeAllClientsFromCache(bool markForInvalidation) +{ + if (!m_pattern.isEmpty()) { + deleteAllValues(m_pattern); + m_pattern.clear(); + } + + m_shouldCollectPatternAttributes = true; + markAllClientsForInvalidation(markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation); +} + +void RenderSVGResourcePattern::removeClientFromCache(RenderObject* client, bool markForInvalidation) +{ + ASSERT(client); + + if (m_pattern.contains(client)) + delete m_pattern.take(client); + + markClientForInvalidation(client, markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation); +} + +bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle* style, GraphicsContext*& context, unsigned short resourceMode) +{ + ASSERT(object); + ASSERT(style); + ASSERT(context); + ASSERT(resourceMode != ApplyToDefaultMode); + + // Be sure to synchronize all SVG properties on the patternElement _before_ processing any further. + // Otherwhise the call to collectPatternAttributes() below, may cause the SVG DOM property + // synchronization to kick in, which causes removeAllClientsFromCache() to be called, which in turn deletes our + // PatternData object! Leaving out the line below will cause svg/dynamic-updates/SVGPatternElement-svgdom* to crash. + SVGPatternElement* patternElement = static_cast<SVGPatternElement*>(node()); + if (!patternElement) + return false; + + if (m_shouldCollectPatternAttributes) { + patternElement->updateAnimatedSVGAttribute(anyQName()); + + m_attributes = PatternAttributes(); + patternElement->collectPatternAttributes(m_attributes); + m_shouldCollectPatternAttributes = false; + } + + // Spec: When the geometry of the applicable element has no width or height and objectBoundingBox is specified, + // then the given effect (e.g. a gradient or a filter) will be ignored. + FloatRect objectBoundingBox = object->objectBoundingBox(); + if (m_attributes.boundingBoxMode() && objectBoundingBox.isEmpty()) + return false; + + if (!m_pattern.contains(object)) + m_pattern.set(object, new PatternData); + + PatternData* patternData = m_pattern.get(object); + if (!patternData->pattern) { + // If we couldn't determine the pattern content element root, stop here. + if (!m_attributes.patternContentElement()) + return false; + + // Compute all necessary transformations to build the tile image & the pattern. + FloatRect tileBoundaries; + AffineTransform tileImageTransform; + if (!buildTileImageTransform(object, m_attributes, patternElement, tileBoundaries, tileImageTransform)) + return false; + + AffineTransform absoluteTransform; + SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform); + + FloatRect absoluteTileBoundaries = absoluteTransform.mapRect(tileBoundaries); + + // Build tile image. + OwnPtr<ImageBuffer> tileImage = createTileImage(object, m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform); + if (!tileImage) + return false; + + RefPtr<Image> copiedImage = tileImage->copyImage(); + if (!copiedImage) + return false; + + // Build pattern. + patternData->pattern = Pattern::create(copiedImage, true, true); + if (!patternData->pattern) + return false; + + // Compute pattern space transformation. + patternData->transform.translate(tileBoundaries.x(), tileBoundaries.y()); + patternData->transform.scale(tileBoundaries.width() / absoluteTileBoundaries.width(), tileBoundaries.height() / absoluteTileBoundaries.height()); + + AffineTransform patternTransform = m_attributes.patternTransform(); + if (!patternTransform.isIdentity()) + patternData->transform.multiply(patternTransform); + + patternData->pattern->setPatternSpaceTransform(patternData->transform); + } + + // Draw pattern + context->save(); + + const SVGRenderStyle* svgStyle = style->svgStyle(); + ASSERT(svgStyle); + + if (resourceMode & ApplyToFillMode) { + context->setAlpha(svgStyle->fillOpacity()); + context->setFillPattern(patternData->pattern); + context->setFillRule(svgStyle->fillRule()); + } else if (resourceMode & ApplyToStrokeMode) { + if (svgStyle->vectorEffect() == VE_NON_SCALING_STROKE) + patternData->pattern->setPatternSpaceTransform(transformOnNonScalingStroke(object, patternData->transform)); + context->setAlpha(svgStyle->strokeOpacity()); + context->setStrokePattern(patternData->pattern); + SVGRenderSupport::applyStrokeStyleToContext(context, style, object); + } + + if (resourceMode & ApplyToTextMode) { + if (resourceMode & ApplyToFillMode) { + context->setTextDrawingMode(TextModeFill); + +#if PLATFORM(CG) + context->applyFillPattern(); +#endif + } else if (resourceMode & ApplyToStrokeMode) { + context->setTextDrawingMode(TextModeStroke); + +#if PLATFORM(CG) + context->applyStrokePattern(); +#endif + } + } + + return true; +} + +void RenderSVGResourcePattern::postApplyResource(RenderObject*, GraphicsContext*& context, unsigned short resourceMode, const Path* path) +{ + ASSERT(context); + ASSERT(resourceMode != ApplyToDefaultMode); + + if (path && !(resourceMode & ApplyToTextMode)) { + if (resourceMode & ApplyToFillMode) + context->fillPath(*path); + else if (resourceMode & ApplyToStrokeMode) + context->strokePath(*path); + } + + context->restore(); +} + +static inline FloatRect calculatePatternBoundaries(const PatternAttributes& attributes, + const FloatRect& objectBoundingBox, + const SVGPatternElement* patternElement) +{ + ASSERT(patternElement); + + if (attributes.boundingBoxMode()) + return FloatRect(attributes.x().valueAsPercentage() * objectBoundingBox.width() + objectBoundingBox.x(), + attributes.y().valueAsPercentage() * objectBoundingBox.height() + objectBoundingBox.y(), + attributes.width().valueAsPercentage() * objectBoundingBox.width(), + attributes.height().valueAsPercentage() * objectBoundingBox.height()); + + return FloatRect(attributes.x().value(patternElement), + attributes.y().value(patternElement), + attributes.width().value(patternElement), + attributes.height().value(patternElement)); +} + +bool RenderSVGResourcePattern::buildTileImageTransform(RenderObject* renderer, + const PatternAttributes& attributes, + const SVGPatternElement* patternElement, + FloatRect& patternBoundaries, + AffineTransform& tileImageTransform) const +{ + ASSERT(renderer); + ASSERT(patternElement); + + FloatRect objectBoundingBox = renderer->objectBoundingBox(); + patternBoundaries = calculatePatternBoundaries(attributes, objectBoundingBox, patternElement); + if (patternBoundaries.width() <= 0 || patternBoundaries.height() <= 0) + return false; + + AffineTransform viewBoxCTM = patternElement->viewBoxToViewTransform(patternElement->viewBox(), patternElement->preserveAspectRatio(), patternBoundaries.width(), patternBoundaries.height()); + + // Apply viewBox/objectBoundingBox transformations. + if (!viewBoxCTM.isIdentity()) + tileImageTransform = viewBoxCTM; + else if (attributes.boundingBoxModeContent()) { + tileImageTransform.translate(objectBoundingBox.x(), objectBoundingBox.y()); + tileImageTransform.scale(objectBoundingBox.width(), objectBoundingBox.height()); + } + + return true; +} + +PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(RenderObject* object, + const PatternAttributes& attributes, + const FloatRect& tileBoundaries, + const FloatRect& absoluteTileBoundaries, + const AffineTransform& tileImageTransform) const +{ + ASSERT(object); + + // Clamp tile image size against SVG viewport size, as last resort, to avoid allocating huge image buffers. + FloatRect contentBoxRect = SVGRenderSupport::findTreeRootObject(object)->contentBoxRect(); + + FloatRect clampedAbsoluteTileBoundaries = absoluteTileBoundaries; + if (clampedAbsoluteTileBoundaries.width() > contentBoxRect.width()) + clampedAbsoluteTileBoundaries.setWidth(contentBoxRect.width()); + + if (clampedAbsoluteTileBoundaries.height() > contentBoxRect.height()) + clampedAbsoluteTileBoundaries.setHeight(contentBoxRect.height()); + + OwnPtr<ImageBuffer> tileImage; + + if (!SVGImageBufferTools::createImageBuffer(absoluteTileBoundaries, clampedAbsoluteTileBoundaries, tileImage, ColorSpaceDeviceRGB)) + return PassOwnPtr<ImageBuffer>(); + + GraphicsContext* tileImageContext = tileImage->context(); + ASSERT(tileImageContext); + + // The image buffer represents the final rendered size, so the content has to be scaled (to avoid pixelation). + tileImageContext->scale(FloatSize(absoluteTileBoundaries.width() / tileBoundaries.width(), + absoluteTileBoundaries.height() / tileBoundaries.height())); + + // Apply tile image transformations. + if (!tileImageTransform.isIdentity()) + tileImageContext->concatCTM(tileImageTransform); + + AffineTransform contentTransformation; + + // Draw the content into the ImageBuffer. + for (Node* node = attributes.patternContentElement()->firstChild(); node; node = node->nextSibling()) { + if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !node->renderer()) + continue; + SVGImageBufferTools::renderSubtreeToImageBuffer(tileImage.get(), node->renderer(), contentTransformation); + } + + return tileImage.release(); +} + +} + +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.h b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.h new file mode 100644 index 0000000..a697c71 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 RenderSVGResourcePattern_h +#define RenderSVGResourcePattern_h + +#if ENABLE(SVG) +#include "AffineTransform.h" +#include "FloatRect.h" +#include "ImageBuffer.h" +#include "Pattern.h" +#include "PatternAttributes.h" +#include "RenderSVGResourceContainer.h" +#include "SVGPatternElement.h" +#include "SVGUnitTypes.h" + +#include <wtf/HashMap.h> +#include <wtf/OwnPtr.h> + +namespace WebCore { + +struct PatternData { + RefPtr<Pattern> pattern; + AffineTransform transform; +}; + +class RenderSVGResourcePattern : public RenderSVGResourceContainer { +public: + RenderSVGResourcePattern(SVGPatternElement*); + virtual ~RenderSVGResourcePattern(); + + virtual const char* renderName() const { return "RenderSVGResourcePattern"; } + + virtual void removeAllClientsFromCache(bool markForInvalidation = true); + virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); + + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*); + virtual FloatRect resourceBoundingBox(RenderObject*) { return FloatRect(); } + + virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + static RenderSVGResourceType s_resourceType; + +private: + bool buildTileImageTransform(RenderObject*, const PatternAttributes&, const SVGPatternElement*, FloatRect& patternBoundaries, AffineTransform& tileImageTransform) const; + + PassOwnPtr<ImageBuffer> createTileImage(RenderObject*, const PatternAttributes&, const FloatRect& tileBoundaries, + const FloatRect& absoluteTileBoundaries, const AffineTransform& tileImageTransform) const; + + bool m_shouldCollectPatternAttributes : 1; + PatternAttributes m_attributes; + HashMap<RenderObject*, PatternData*> m_pattern; +}; + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp new file mode 100644 index 0000000..a8830fc --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGResourceRadialGradient.h" + +#include "RadialGradientAttributes.h" +#include "SVGRadialGradientElement.h" + +namespace WebCore { + +RenderSVGResourceType RenderSVGResourceRadialGradient::s_resourceType = RadialGradientResourceType; + +RenderSVGResourceRadialGradient::RenderSVGResourceRadialGradient(SVGRadialGradientElement* node) + : RenderSVGResourceGradient(node) +{ +} + +RenderSVGResourceRadialGradient::~RenderSVGResourceRadialGradient() +{ +} + +void RenderSVGResourceRadialGradient::collectGradientAttributes(SVGGradientElement* gradientElement) +{ + m_attributes = RadialGradientAttributes(); + static_cast<SVGRadialGradientElement*>(gradientElement)->collectGradientAttributes(m_attributes); +} + +void RenderSVGResourceRadialGradient::buildGradient(GradientData* gradientData, SVGGradientElement* gradientElement) const +{ + SVGRadialGradientElement* radialGradientElement = static_cast<SVGRadialGradientElement*>(gradientElement); + + // Determine gradient focal/center points and radius + FloatPoint focalPoint; + FloatPoint centerPoint; + float radius; + radialGradientElement->calculateFocalCenterPointsAndRadius(m_attributes, focalPoint, centerPoint, radius); + + gradientData->gradient = Gradient::create(focalPoint, + 0, // SVG does not support a "focus radius" + centerPoint, + radius); + + gradientData->gradient->setSpreadMethod(m_attributes.spreadMethod()); + + // Add stops + addStops(gradientData, m_attributes.stops()); +} + +} + +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.h b/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.h new file mode 100644 index 0000000..9d37d11 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 RenderSVGResourceRadialGradient_h +#define RenderSVGResourceRadialGradient_h + +#if ENABLE(SVG) +#include "RadialGradientAttributes.h" +#include "RenderSVGResourceGradient.h" + +namespace WebCore { + +class SVGRadialGradientElement; + +class RenderSVGResourceRadialGradient : public RenderSVGResourceGradient { +public: + RenderSVGResourceRadialGradient(SVGRadialGradientElement*); + virtual ~RenderSVGResourceRadialGradient(); + + virtual const char* renderName() const { return "RenderSVGResourceRadialGradient"; } + + virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + static RenderSVGResourceType s_resourceType; + + virtual bool boundingBoxMode() const { return m_attributes.boundingBoxMode(); } + virtual void calculateGradientTransform(AffineTransform& transform) { transform = m_attributes.gradientTransform(); } + virtual void collectGradientAttributes(SVGGradientElement*); + virtual void buildGradient(GradientData*, SVGGradientElement*) const; + +private: + RadialGradientAttributes m_attributes; +}; + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp new file mode 100644 index 0000000..9f6c063 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGResourceSolidColor.h" + +#include "GraphicsContext.h" +#include "RenderStyle.h" +#include "SVGRenderSupport.h" + +#if PLATFORM(SKIA) +#include "PlatformContextSkia.h" +#endif + +namespace WebCore { + +RenderSVGResourceType RenderSVGResourceSolidColor::s_resourceType = SolidColorResourceType; + +RenderSVGResourceSolidColor::RenderSVGResourceSolidColor() +{ +} + +RenderSVGResourceSolidColor::~RenderSVGResourceSolidColor() +{ +} + +bool RenderSVGResourceSolidColor::applyResource(RenderObject* object, RenderStyle* style, GraphicsContext*& context, unsigned short resourceMode) +{ + // We are NOT allowed to ASSERT(object) here, unlike all other resources. + // RenderSVGResourceSolidColor is the only resource which may be used from HTML, when rendering + // SVG Fonts for a HTML document. This will be indicated by a null RenderObject pointer. + ASSERT(context); + ASSERT(resourceMode != ApplyToDefaultMode); + + const SVGRenderStyle* svgStyle = style ? style->svgStyle() : 0; + ColorSpace colorSpace = style ? style->colorSpace() : ColorSpaceDeviceRGB; + + if (resourceMode & ApplyToFillMode) { + context->setAlpha(svgStyle ? svgStyle->fillOpacity() : 1.0f); + context->setFillColor(m_color, colorSpace); + context->setFillRule(svgStyle ? svgStyle->fillRule() : RULE_NONZERO); + + if (resourceMode & ApplyToTextMode) + context->setTextDrawingMode(TextModeFill); + } else if (resourceMode & ApplyToStrokeMode) { + context->setAlpha(svgStyle ? svgStyle->strokeOpacity() : 1.0f); + context->setStrokeColor(m_color, colorSpace); + + if (style) + SVGRenderSupport::applyStrokeStyleToContext(context, style, object); + + if (resourceMode & ApplyToTextMode) + context->setTextDrawingMode(TextModeStroke); + } + + return true; +} + +void RenderSVGResourceSolidColor::postApplyResource(RenderObject*, GraphicsContext*& context, unsigned short resourceMode, const Path* path) +{ + ASSERT(context); + ASSERT(resourceMode != ApplyToDefaultMode); + + if (path && !(resourceMode & ApplyToTextMode)) { + if (resourceMode & ApplyToFillMode) + context->fillPath(*path); + else if (resourceMode & ApplyToStrokeMode) + context->strokePath(*path); + } +} + +} + +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.h b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.h new file mode 100644 index 0000000..02ceb31 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 RenderSVGResourceSolidColor_h +#define RenderSVGResourceSolidColor_h + +#if ENABLE(SVG) +#include "Color.h" +#include "FloatRect.h" +#include "RenderSVGResource.h" + +namespace WebCore { + +class RenderSVGResourceSolidColor : public RenderSVGResource { +public: + RenderSVGResourceSolidColor(); + virtual ~RenderSVGResourceSolidColor(); + + virtual void removeAllClientsFromCache(bool = true) { } + virtual void removeClientFromCache(RenderObject*, bool = true) { } + + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*); + virtual FloatRect resourceBoundingBox(RenderObject*) { return FloatRect(); } + + virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + static RenderSVGResourceType s_resourceType; + + const Color& color() const { return m_color; } + void setColor(const Color& color) { m_color = color; } + +private: + Color m_color; +}; + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp new file mode 100644 index 0000000..aa87b09 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005, 2007, 2008, 2009 Rob Buis <buis@kde.org> + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Google, Inc. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGRoot.h" + +#include "GraphicsContext.h" +#include "HitTestResult.h" +#include "RenderSVGContainer.h" +#include "RenderSVGResource.h" +#include "RenderView.h" +#include "SVGLength.h" +#include "SVGRenderSupport.h" +#include "SVGResources.h" +#include "SVGSVGElement.h" +#include "SVGStyledElement.h" +#include "TransformState.h" + +#if ENABLE(FILTERS) +#include "RenderSVGResourceFilter.h" +#endif + +using namespace std; + +namespace WebCore { + +RenderSVGRoot::RenderSVGRoot(SVGStyledElement* node) + : RenderBox(node) + , m_isLayoutSizeChanged(false) + , m_needsBoundariesOrTransformUpdate(true) +{ + setReplaced(true); +} + +RenderSVGRoot::~RenderSVGRoot() +{ +} + +void RenderSVGRoot::computePreferredLogicalWidths() +{ + ASSERT(preferredLogicalWidthsDirty()); + + int borderAndPadding = borderAndPaddingWidth(); + int width = computeReplacedLogicalWidth(false) + borderAndPadding; + + if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) + width = min(width, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? borderAndPadding : 0)); + + if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent())) { + m_minPreferredLogicalWidth = 0; + m_maxPreferredLogicalWidth = width; + } else + m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = width; + + setPreferredLogicalWidthsDirty(false); +} + +int RenderSVGRoot::computeReplacedLogicalWidth(bool includeMaxWidth) const +{ + int replacedWidth = RenderBox::computeReplacedLogicalWidth(includeMaxWidth); + if (!style()->logicalWidth().isPercent()) + return replacedWidth; + + // FIXME: Investigate in size rounding issues + SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); + return static_cast<int>(roundf(replacedWidth * svg->currentScale())); +} + +int RenderSVGRoot::computeReplacedLogicalHeight() const +{ + int replacedHeight = RenderBox::computeReplacedLogicalHeight(); + if (!style()->logicalHeight().isPercent()) + return replacedHeight; + + // FIXME: Investigate in size rounding issues + SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); + return static_cast<int>(roundf(replacedHeight * svg->currentScale())); +} + +void RenderSVGRoot::layout() +{ + ASSERT(needsLayout()); + + // Arbitrary affine transforms are incompatible with LayoutState. + view()->disableLayoutState(); + + bool needsLayout = selfNeedsLayout(); + LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && needsLayout); + + IntSize oldSize(width(), height()); + computeLogicalWidth(); + computeLogicalHeight(); + calcViewport(); + + SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); + m_isLayoutSizeChanged = svg->hasRelativeLengths() && oldSize != size(); + + SVGRenderSupport::layoutChildren(this, needsLayout); + m_isLayoutSizeChanged = false; + + // At this point LayoutRepainter already grabbed the old bounds, + // recalculate them now so repaintAfterLayout() uses the new bounds. + if (m_needsBoundariesOrTransformUpdate) { + updateCachedBoundaries(); + m_needsBoundariesOrTransformUpdate = false; + } + + repainter.repaintAfterLayout(); + + view()->enableLayoutState(); + setNeedsLayout(false); +} + +bool RenderSVGRoot::selfWillPaint() +{ +#if ENABLE(FILTERS) + SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); + return resources && resources->filter(); +#else + return false; +#endif +} + +void RenderSVGRoot::paint(PaintInfo& paintInfo, int parentX, int parentY) +{ + if (paintInfo.context->paintingDisabled()) + return; + + bool isVisible = style()->visibility() == VISIBLE; + IntPoint parentOriginInContainer(parentX, parentY); + IntPoint borderBoxOriginInContainer = parentOriginInContainer + parentOriginToBorderBox(); + + if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseChildBlockBackground) && isVisible) + paintBoxDecorations(paintInfo, borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y()); + + if (paintInfo.phase == PaintPhaseBlockBackground) + return; + + // An empty viewport disables rendering. FIXME: Should we still render filters? + if (m_viewportSize.isEmpty()) + return; + + // Don't paint if we don't have kids, except if we have filters we should paint those. + if (!firstChild() && !selfWillPaint()) + return; + + // Make a copy of the PaintInfo because applyTransform will modify the damage rect. + PaintInfo childPaintInfo(paintInfo); + childPaintInfo.context->save(); + + // Apply initial viewport clip - not affected by overflow handling + childPaintInfo.context->clip(overflowClipRect(borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y())); + + // Convert from container offsets (html renderers) to a relative transform (svg renderers). + // Transform from our paint container's coordinate system to our local coords. + childPaintInfo.applyTransform(localToRepaintContainerTransform(parentOriginInContainer)); + + bool continueRendering = true; + if (childPaintInfo.phase == PaintPhaseForeground) + continueRendering = SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo); + + if (continueRendering) + RenderBox::paint(childPaintInfo, 0, 0); + + if (childPaintInfo.phase == PaintPhaseForeground) + SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, paintInfo.context); + + childPaintInfo.context->restore(); + + if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && isVisible) + paintOutline(paintInfo.context, borderBoxOriginInContainer.x(), borderBoxOriginInContainer.y(), width(), height()); +} + +void RenderSVGRoot::destroy() +{ + SVGResourcesCache::clientDestroyed(this); + RenderBox::destroy(); +} + +void RenderSVGRoot::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) +{ + if (diff == StyleDifferenceLayout) + setNeedsBoundariesUpdate(); + RenderBox::styleWillChange(diff, newStyle); +} + +void RenderSVGRoot::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderBox::styleDidChange(diff, oldStyle); + SVGResourcesCache::clientStyleChanged(this, diff, style()); +} + +void RenderSVGRoot::updateFromElement() +{ + RenderBox::updateFromElement(); + SVGResourcesCache::clientUpdatedFromElement(this, style()); +} + +void RenderSVGRoot::calcViewport() +{ + SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); + + if (!svg->hasSetContainerSize()) { + // In the normal case of <svg> being stand-alone or in a CSSBoxModel object we use + // RenderBox::width()/height() (which pulls data from RenderStyle) + m_viewportSize = FloatSize(width(), height()); + return; + } + + // In the SVGImage case grab the SVGLength values off of SVGSVGElement and use + // the special relativeWidthValue accessors which respect the specified containerSize + // FIXME: Check how SVGImage + zooming is supposed to be handled? + SVGLength width = svg->width(); + SVGLength height = svg->height(); + m_viewportSize = FloatSize(width.unitType() == LengthTypePercentage ? svg->relativeWidthValue() : width.value(svg), + height.unitType() == LengthTypePercentage ? svg->relativeHeightValue() : height.value(svg)); +} + +// RenderBox methods will expect coordinates w/o any transforms in coordinates +// relative to our borderBox origin. This method gives us exactly that. +AffineTransform RenderSVGRoot::localToBorderBoxTransform() const +{ + IntSize borderAndPadding = borderOriginToContentBox(); + SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); + float scale = svg->currentScale(); + FloatPoint translate = svg->currentTranslate(); + AffineTransform ctm(scale, 0, 0, scale, borderAndPadding.width() + translate.x(), borderAndPadding.height() + translate.y()); + return svg->viewBoxToViewTransform(width() / scale, height() / scale) * ctm; +} + +IntSize RenderSVGRoot::parentOriginToBorderBox() const +{ + return IntSize(x(), y()); +} + +IntSize RenderSVGRoot::borderOriginToContentBox() const +{ + return IntSize(borderLeft() + paddingLeft(), borderTop() + paddingTop()); +} + +AffineTransform RenderSVGRoot::localToRepaintContainerTransform(const IntPoint& parentOriginInContainer) const +{ + AffineTransform parentToContainer(localToParentTransform()); + return parentToContainer.translateRight(parentOriginInContainer.x(), parentOriginInContainer.y()); +} + +const AffineTransform& RenderSVGRoot::localToParentTransform() const +{ + IntSize parentToBorderBoxOffset = parentOriginToBorderBox(); + + AffineTransform borderBoxOriginToParentOrigin(localToBorderBoxTransform()); + borderBoxOriginToParentOrigin.translateRight(parentToBorderBoxOffset.width(), parentToBorderBoxOffset.height()); + + m_localToParentTransform = borderBoxOriginToParentOrigin; + return m_localToParentTransform; +} + +IntRect RenderSVGRoot::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) +{ + return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer); +} + +void RenderSVGRoot::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed) +{ + // Apply our local transforms (except for x/y translation), then our shadow, + // and then call RenderBox's method to handle all the normal CSS Box model bits + repaintRect = localToBorderBoxTransform().mapRect(repaintRect); + + // Apply initial viewport clip - not affected by overflow settings + repaintRect.intersect(enclosingIntRect(FloatRect(FloatPoint(), m_viewportSize))); + + const SVGRenderStyle* svgStyle = style()->svgStyle(); + if (const ShadowData* shadow = svgStyle->shadow()) + shadow->adjustRectForShadow(repaintRect); + + RenderBox::computeRectForRepaint(repaintContainer, repaintRect, fixed); +} + +void RenderSVGRoot::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) const +{ + ASSERT(!fixed); // We should have no fixed content in the SVG rendering tree. + ASSERT(useTransforms); // mapping a point through SVG w/o respecting trasnforms is useless. + + // Transform to our border box and let RenderBox transform the rest of the way. + transformState.applyTransform(localToBorderBoxTransform()); + RenderBox::mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState); +} + +void RenderSVGRoot::updateCachedBoundaries() +{ + m_objectBoundingBox = FloatRect(); + m_strokeBoundingBox = FloatRect(); + m_repaintBoundingBox = FloatRect(); + + SVGRenderSupport::computeContainerBoundingBoxes(this, m_objectBoundingBox, m_strokeBoundingBox, m_repaintBoundingBox); + SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingBox); + m_repaintBoundingBox.inflate(borderAndPaddingWidth()); +} + +bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) +{ + IntPoint pointInContainer(x, y); + IntSize containerToParentOffset(tx, ty); + + IntPoint pointInParent = pointInContainer - containerToParentOffset; + IntPoint pointInBorderBox = pointInParent - parentOriginToBorderBox(); + + // Note: For now, we're ignoring hits to border and padding for <svg> + IntPoint pointInContentBox = pointInBorderBox - borderOriginToContentBox(); + if (!contentBoxRect().contains(pointInContentBox)) + return false; + + IntPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); + + for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { + if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) { + // FIXME: CSS/HTML assumes the local point is relative to the border box, right? + updateHitTestResult(result, pointInBorderBox); + // FIXME: nodeAtFloatPoint() doesn't handle rect-based hit tests yet. + result.addNodeToRectBasedTestResult(child->node(), x, y); + return true; + } + } + + // If we didn't early exit above, we've just hit the container <svg> element. Unlike SVG 1.1, 2nd Edition allows container elements to be hit. + if (hitTestAction == HitTestBlockBackground) { + // Only return true here, if the last hit testing phase 'BlockBackground' is executed. If we'd return true in the 'Foreground' phase, + // hit testing would stop immediately. For SVG only trees this doesn't matter. Though when we have a <foreignObject> subtree we need + // to be able to detect hits on the background of a <div> element. If we'd return true here in the 'Foreground' phase, we are not able + // to detect these hits anymore. + updateHitTestResult(result, roundedIntPoint(localPoint)); + return true; + } + + return false; +} + +} + +#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.h b/Source/WebCore/rendering/svg/RenderSVGRoot.h new file mode 100644 index 0000000..7aec3f8 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGRoot.h @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005, 2007 Rob Buis <buis@kde.org> + * Copyright (C) 2009 Google, Inc. All rights reserved. + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * 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 RenderSVGRoot_h +#define RenderSVGRoot_h + +#if ENABLE(SVG) +#include "FloatRect.h" +#include "RenderBox.h" + +#include "SVGRenderSupport.h" + +namespace WebCore { + +class SVGStyledElement; +class AffineTransform; + +class RenderSVGRoot : public RenderBox { +public: + explicit RenderSVGRoot(SVGStyledElement*); + virtual ~RenderSVGRoot(); + + const RenderObjectChildList* children() const { return &m_children; } + RenderObjectChildList* children() { return &m_children; } + + bool isLayoutSizeChanged() const { return m_isLayoutSizeChanged; } + virtual void setNeedsBoundariesUpdate() { m_needsBoundariesOrTransformUpdate = true; } + virtual void setNeedsTransformUpdate() { m_needsBoundariesOrTransformUpdate = true; } + +private: + virtual RenderObjectChildList* virtualChildren() { return children(); } + virtual const RenderObjectChildList* virtualChildren() const { return children(); } + + virtual bool isSVGRoot() const { return true; } + virtual const char* renderName() const { return "RenderSVGRoot"; } + + virtual void computePreferredLogicalWidths(); + virtual int computeReplacedLogicalWidth(bool includeMaxWidth = true) const; + virtual int computeReplacedLogicalHeight() const; + virtual void layout(); + virtual void paint(PaintInfo&, int parentX, int parentY); + + virtual void destroy(); + virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void updateFromElement(); + + virtual const AffineTransform& localToParentTransform() const; + + bool fillContains(const FloatPoint&) const; + bool strokeContains(const FloatPoint&) const; + + virtual FloatRect objectBoundingBox() const { return m_objectBoundingBox; } + virtual FloatRect strokeBoundingBox() const { return m_strokeBoundingBox; } + virtual FloatRect repaintRectInLocalCoordinates() const { return m_repaintBoundingBox; } + + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); + + virtual IntRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer); + virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed); + + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&) const; + + void calcViewport(); + + bool selfWillPaint(); + void updateCachedBoundaries(); + + IntSize parentOriginToBorderBox() const; + IntSize borderOriginToContentBox() const; + AffineTransform localToRepaintContainerTransform(const IntPoint& parentOriginInContainer) const; + AffineTransform localToBorderBoxTransform() const; + + RenderObjectChildList m_children; + FloatSize m_viewportSize; + FloatRect m_objectBoundingBox; + FloatRect m_strokeBoundingBox; + FloatRect m_repaintBoundingBox; + mutable AffineTransform m_localToParentTransform; + bool m_isLayoutSizeChanged : 1; + bool m_needsBoundariesOrTransformUpdate : 1; +}; + +inline RenderSVGRoot* toRenderSVGRoot(RenderObject* object) +{ + ASSERT(!object || object->isSVGRoot()); + return static_cast<RenderSVGRoot*>(object); +} + +inline const RenderSVGRoot* toRenderSVGRoot(const RenderObject* object) +{ + ASSERT(!object || object->isSVGRoot()); + return static_cast<const RenderSVGRoot*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderSVGRoot(const RenderSVGRoot*); + +} // namespace WebCore + +#endif // ENABLE(SVG) +#endif // RenderSVGRoot_h diff --git a/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.cpp new file mode 100644 index 0000000..5736333 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGShadowTreeRootContainer.h" + +#include "MouseEvent.h" +#include "SVGShadowTreeElements.h" +#include "SVGUseElement.h" + +namespace WebCore { + +RenderSVGShadowTreeRootContainer::RenderSVGShadowTreeRootContainer(SVGUseElement* node) + : RenderSVGTransformableContainer(node) + , m_recreateTree(false) +{ +} + +RenderSVGShadowTreeRootContainer::~RenderSVGShadowTreeRootContainer() +{ + if (m_shadowRoot && m_shadowRoot->attached()) { + m_shadowRoot->detach(); + m_shadowRoot->clearShadowHost(); + } +} + +void RenderSVGShadowTreeRootContainer::updateStyle(Node::StyleChange change) +{ + if (m_shadowRoot && m_shadowRoot->attached()) + m_shadowRoot->recalcStyle(change); +} + +void RenderSVGShadowTreeRootContainer::updateFromElement() +{ + bool hadExistingTree = m_shadowRoot; + + SVGUseElement* useElement = static_cast<SVGUseElement*>(node()); + if (!m_shadowRoot) { + ASSERT(!m_recreateTree); + m_shadowRoot = SVGShadowTreeRootElement::create(document(), useElement); + useElement->buildPendingResource(); + } + + ASSERT(m_shadowRoot->shadowHost() == useElement); + + bool shouldRecreateTree = m_recreateTree; + if (m_recreateTree) { + ASSERT(hadExistingTree); + + if (m_shadowRoot->attached()) + m_shadowRoot->detach(); + + m_shadowRoot->removeAllChildren(); + m_recreateTree = false; + } + + // Only rebuild the shadow tree, if we a) never had a tree or b) we were specifically asked to do so + // If the use element is a pending resource, and a) or b) is true, do nothing, and wait for the use + // element to be asked to buildPendingResource(), this will call us again, with m_recreateTrue=true. + if ((shouldRecreateTree || !hadExistingTree) && !useElement->isPendingResource()) { + useElement->buildShadowAndInstanceTree(m_shadowRoot.get()); + + // Attach shadow root element + m_shadowRoot->attachElement(style(), renderArena()); + + // Attach subtree, as if it was a regular non-shadow tree + for (Node* child = m_shadowRoot->firstChild(); child; child = child->nextSibling()) + child->attach(); + } + + ASSERT(!m_recreateTree); + RenderSVGTransformableContainer::updateFromElement(); +} + +void RenderSVGShadowTreeRootContainer::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +{ + RenderSVGTransformableContainer::styleDidChange(diff, oldStyle); + + if (RenderObject* shadowRootRenderer = m_shadowRoot ? m_shadowRoot->renderer() : 0) + shadowRootRenderer->setStyle(style()); +} + +Node* RenderSVGShadowTreeRootContainer::rootElement() const +{ + return m_shadowRoot.get(); +} + +} + +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.h b/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.h new file mode 100644 index 0000000..cee8409 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 RenderSVGShadowTreeRootContainer_h +#define RenderSVGShadowTreeRootContainer_h + +#if ENABLE(SVG) +#include "RenderSVGTransformableContainer.h" + +namespace WebCore { + +class SVGUseElement; +class SVGShadowTreeRootElement; + +class RenderSVGShadowTreeRootContainer : public RenderSVGTransformableContainer { +public: + RenderSVGShadowTreeRootContainer(SVGUseElement*); + virtual ~RenderSVGShadowTreeRootContainer(); + + virtual bool isSVGShadowTreeRootContainer() const { return true; } + + void markShadowTreeForRecreation() { m_recreateTree = true; } + void updateStyle(Node::StyleChange); + virtual void updateFromElement(); + + Node* rootElement() const; + +private: + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + + bool m_recreateTree; + RefPtr<SVGShadowTreeRootElement> m_shadowRoot; +}; + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGTSpan.cpp b/Source/WebCore/rendering/svg/RenderSVGTSpan.cpp index 90ff36c..872d076 100644 --- a/Source/WebCore/rendering/svg/RenderSVGTSpan.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGTSpan.cpp @@ -2,7 +2,7 @@ * This file is part of the WebKit project. * * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> - * (C) 2006 Apple Computer Inc. + * Copyright (C) 2006 Apple Computer Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -18,7 +18,6 @@ * 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. - * */ #include "config.h" diff --git a/Source/WebCore/rendering/svg/RenderSVGTSpan.h b/Source/WebCore/rendering/svg/RenderSVGTSpan.h index 97e0eb0..d5e2ed7 100644 --- a/Source/WebCore/rendering/svg/RenderSVGTSpan.h +++ b/Source/WebCore/rendering/svg/RenderSVGTSpan.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> - * (C) 2006 Apple Computer Inc. - * (C) 2009 Google Inc. + * Copyright (C) 2006 Apple Computer Inc. + * Copyright (C) 2009 Google Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -17,7 +17,6 @@ * 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 RenderSVGTSpan_h diff --git a/Source/WebCore/rendering/svg/RenderSVGText.cpp b/Source/WebCore/rendering/svg/RenderSVGText.cpp index 01a92b0..dad0b70 100644 --- a/Source/WebCore/rendering/svg/RenderSVGText.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGText.cpp @@ -21,7 +21,6 @@ * 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. - * */ #include "config.h" diff --git a/Source/WebCore/rendering/svg/RenderSVGText.h b/Source/WebCore/rendering/svg/RenderSVGText.h index deae78c..188d5fc 100644 --- a/Source/WebCore/rendering/svg/RenderSVGText.h +++ b/Source/WebCore/rendering/svg/RenderSVGText.h @@ -17,7 +17,6 @@ * 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 RenderSVGText_h diff --git a/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp b/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp index 4ba2eeb..4712ddc 100644 --- a/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp @@ -1,6 +1,4 @@ /* - * This file is part of the WebKit project. - * * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * * This library is free software; you can redistribute it and/or @@ -17,7 +15,6 @@ * 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. - * */ #include "config.h" diff --git a/Source/WebCore/rendering/svg/RenderSVGTextPath.h b/Source/WebCore/rendering/svg/RenderSVGTextPath.h index a71edf5..f1871b0 100644 --- a/Source/WebCore/rendering/svg/RenderSVGTextPath.h +++ b/Source/WebCore/rendering/svg/RenderSVGTextPath.h @@ -1,6 +1,4 @@ /* - * This file is part of the WebKit project. - * * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * Copyright (C) 2009 Apple Inc. All rights reserved. * @@ -18,7 +16,6 @@ * 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 RenderSVGTextPath_h diff --git a/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp new file mode 100644 index 0000000..23aaa89 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org> + * Copyright (C) 2009 Google, Inc. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGTransformableContainer.h" + +#include "SVGNames.h" +#include "SVGShadowTreeElements.h" +#include "SVGStyledTransformableElement.h" + +namespace WebCore { + +RenderSVGTransformableContainer::RenderSVGTransformableContainer(SVGStyledTransformableElement* node) + : RenderSVGContainer(node) + , m_needsTransformUpdate(true) +{ +} + +bool RenderSVGTransformableContainer::calculateLocalTransform() +{ + SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(node()); + + bool needsUpdate = m_needsTransformUpdate; + if (needsUpdate) { + m_localTransform = element->animatedLocalTransform(); + m_needsTransformUpdate = false; + } + + if (!element->hasTagName(SVGNames::gTag) || !static_cast<SVGGElement*>(element)->isShadowTreeContainerElement()) + return needsUpdate; + + FloatSize translation = static_cast<SVGShadowTreeContainerElement*>(element)->containerTranslation(); + if (!translation.width() && !translation.height()) + return needsUpdate; + + // FIXME: Could optimize this case for use to avoid refetching the animatedLocalTransform() here, if only the containerTranslation() changed. + if (!needsUpdate) + m_localTransform = element->animatedLocalTransform(); + + m_localTransform.translate(translation.width(), translation.height()); + return true; +} + +} + +#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.h b/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.h new file mode 100644 index 0000000..401bfa8 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Google, Inc. + * + * 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 RenderSVGTransformableContainer_h +#define RenderSVGTransformableContainer_h + +#if ENABLE(SVG) +#include "RenderSVGContainer.h" + +namespace WebCore { + +class SVGStyledTransformableElement; +class RenderSVGTransformableContainer : public RenderSVGContainer { +public: + explicit RenderSVGTransformableContainer(SVGStyledTransformableElement*); + + virtual const AffineTransform& localToParentTransform() const { return m_localTransform; } + virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } + +private: + virtual bool calculateLocalTransform(); + virtual AffineTransform localTransform() const { return m_localTransform; } + + bool m_needsTransformUpdate : 1; + AffineTransform m_localTransform; +}; +} + +#endif // ENABLE(SVG) +#endif // RenderSVGTransformableContainer_h diff --git a/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp new file mode 100644 index 0000000..7f4b6f7 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005, 2007 Rob Buis <buis@kde.org> + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Google, Inc. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGViewportContainer.h" + +#include "GraphicsContext.h" +#include "RenderView.h" +#include "SVGNames.h" +#include "SVGSVGElement.h" + +namespace WebCore { + +RenderSVGViewportContainer::RenderSVGViewportContainer(SVGStyledElement* node) + : RenderSVGContainer(node) +{ +} + +void RenderSVGViewportContainer::applyViewportClip(PaintInfo& paintInfo) +{ + if (SVGRenderSupport::isOverflowHidden(this)) + paintInfo.context->clip(m_viewport); +} + +void RenderSVGViewportContainer::calcViewport() +{ + SVGElement* element = static_cast<SVGElement*>(node()); + if (element->hasTagName(SVGNames::svgTag)) { + SVGSVGElement* svg = static_cast<SVGSVGElement*>(element); + + FloatRect oldViewport = m_viewport; + m_viewport = FloatRect(svg->x().value(svg) + , svg->y().value(svg) + , svg->width().value(svg) + , svg->height().value(svg)); + + if (oldViewport != m_viewport) + setNeedsBoundariesUpdate(); + } +} + +AffineTransform RenderSVGViewportContainer::viewportTransform() const +{ + if (node()->hasTagName(SVGNames::svgTag)) { + SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); + return svg->viewBoxToViewTransform(m_viewport.width(), m_viewport.height()); + } + + return AffineTransform(); +} + +const AffineTransform& RenderSVGViewportContainer::localToParentTransform() const +{ + AffineTransform viewportTranslation(viewportTransform()); + m_localToParentTransform = viewportTranslation.translateRight(m_viewport.x(), m_viewport.y()); + return m_localToParentTransform; + // If this class were ever given a localTransform(), then the above would read: + // return viewportTransform() * localTransform() * viewportTranslation; +} + +bool RenderSVGViewportContainer::pointIsInsideViewportClip(const FloatPoint& pointInParent) +{ + // Respect the viewport clip (which is in parent coords) + if (!SVGRenderSupport::isOverflowHidden(this)) + return true; + + return m_viewport.contains(pointInParent); +} + +} + +#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGViewportContainer.h b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.h new file mode 100644 index 0000000..66037e6 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005, 2007 Rob Buis <buis@kde.org> + * Copyright (C) 2009 Google, Inc. + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * 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 RenderSVGViewportContainer_h +#define RenderSVGViewportContainer_h + +#if ENABLE(SVG) +#include "RenderSVGContainer.h" + +namespace WebCore { + +// This is used for non-root <svg> elements and <marker> elements, neither of which are SVGTransformable +// thus we inherit from RenderSVGContainer instead of RenderSVGTransformableContainer +class RenderSVGViewportContainer : public RenderSVGContainer { +public: + explicit RenderSVGViewportContainer(SVGStyledElement*); + +private: + virtual bool isSVGContainer() const { return true; } + virtual bool isSVGViewportContainer() const { return true; } + virtual const char* renderName() const { return "RenderSVGViewportContainer"; } + + AffineTransform viewportTransform() const; + virtual const AffineTransform& localToParentTransform() const; + + virtual void calcViewport(); + + virtual void applyViewportClip(PaintInfo&); + virtual bool pointIsInsideViewportClip(const FloatPoint& pointInParent); + + FloatRect m_viewport; + mutable AffineTransform m_localToParentTransform; +}; + +inline RenderSVGViewportContainer* toRenderSVGViewportContainer(RenderObject* object) +{ + ASSERT(!object || !strcmp(object->renderName(), "RenderSVGViewportContainer")); + return static_cast<RenderSVGViewportContainer*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderSVGViewportContainer(const RenderSVGViewportContainer*); + +} // namespace WebCore + +#endif // ENABLE(SVG) +#endif // RenderSVGViewportContainer_h diff --git a/Source/WebCore/rendering/svg/SVGImageBufferTools.cpp b/Source/WebCore/rendering/svg/SVGImageBufferTools.cpp new file mode 100644 index 0000000..f0657af --- /dev/null +++ b/Source/WebCore/rendering/svg/SVGImageBufferTools.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "SVGImageBufferTools.h" + +#include "FrameView.h" +#include "GraphicsContext.h" +#include "RenderObject.h" +#include "RenderSVGContainer.h" +#include "RenderSVGRoot.h" + +namespace WebCore { + +static AffineTransform& currentContentTransformation() +{ + DEFINE_STATIC_LOCAL(AffineTransform, s_currentContentTransformation, ()); + return s_currentContentTransformation; +} + +void SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(const RenderObject* renderer, AffineTransform& absoluteTransform) +{ + const RenderObject* current = renderer; + ASSERT(current); + + absoluteTransform = currentContentTransformation(); + while (current) { + absoluteTransform.multiply(current->localToParentTransform()); + if (current->isSVGRoot()) + break; + current = current->parent(); + } +} + +bool SVGImageBufferTools::createImageBuffer(const FloatRect& absoluteTargetRect, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>& imageBuffer, ColorSpace colorSpace) +{ + IntSize imageSize(roundedImageBufferSize(clampedAbsoluteTargetRect.size())); + IntSize unclampedImageSize(SVGImageBufferTools::roundedImageBufferSize(absoluteTargetRect.size())); + + // Don't create empty ImageBuffers. + if (imageSize.isEmpty()) + return false; + + OwnPtr<ImageBuffer> image = ImageBuffer::create(imageSize, colorSpace); + if (!image) + return false; + + GraphicsContext* imageContext = image->context(); + ASSERT(imageContext); + + // Compensate rounding effects, as the absolute target rect is using floating-point numbers and the image buffer size is integer. + imageContext->scale(FloatSize(unclampedImageSize.width() / absoluteTargetRect.width(), unclampedImageSize.height() / absoluteTargetRect.height())); + + imageBuffer = image.release(); + return true; +} + +void SVGImageBufferTools::renderSubtreeToImageBuffer(ImageBuffer* image, RenderObject* item, const AffineTransform& subtreeContentTransformation) +{ + ASSERT(item); + ASSERT(image); + ASSERT(image->context()); + + PaintInfo info(image->context(), PaintInfo::infiniteRect(), PaintPhaseForeground, 0, 0, 0); + + AffineTransform& contentTransformation = currentContentTransformation(); + AffineTransform savedContentTransformation = contentTransformation; + contentTransformation.multiply(subtreeContentTransformation); + + item->layoutIfNeeded(); + item->paint(info, 0, 0); + + contentTransformation = savedContentTransformation; +} + +void SVGImageBufferTools::clipToImageBuffer(GraphicsContext* context, const AffineTransform& absoluteTransform, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>& imageBuffer) +{ + ASSERT(context); + ASSERT(imageBuffer); + + // The mask image has been created in the absolute coordinate space, as the image should not be scaled. + // So the actual masking process has to be done in the absolute coordinate space as well. + context->concatCTM(absoluteTransform.inverse()); + context->clipToImageBuffer(imageBuffer.get(), clampedAbsoluteTargetRect); + context->concatCTM(absoluteTransform); + + // When nesting resources, with objectBoundingBox as content unit types, there's no use in caching the + // resulting image buffer as the parent resource already caches the result. + if (!currentContentTransformation().isIdentity()) + imageBuffer.clear(); +} + +IntSize SVGImageBufferTools::roundedImageBufferSize(const FloatSize& size) +{ + return IntSize(static_cast<int>(lroundf(size.width())), static_cast<int>(lroundf(size.height()))); +} + +FloatRect SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(const RenderObject* renderer, const FloatRect& absoluteTargetRect) +{ + ASSERT(renderer); + + const RenderSVGRoot* svgRoot = SVGRenderSupport::findTreeRootObject(renderer); + FloatRect clampedAbsoluteTargetRect = absoluteTargetRect; + clampedAbsoluteTargetRect.intersect(svgRoot->contentBoxRect()); + return clampedAbsoluteTargetRect; +} + +} + +#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/SVGImageBufferTools.h b/Source/WebCore/rendering/svg/SVGImageBufferTools.h new file mode 100644 index 0000000..cfb15b2 --- /dev/null +++ b/Source/WebCore/rendering/svg/SVGImageBufferTools.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 SVGImageBufferTools_h +#define SVGImageBufferTools_h + +#if ENABLE(SVG) +#include "ImageBuffer.h" +#include <wtf/Noncopyable.h> + +namespace WebCore { + +class AffineTransform; +class FloatRect; +class FloatSize; +class GraphicsContext; +class RenderObject; + +class SVGImageBufferTools : public Noncopyable { +public: + static bool createImageBuffer(const FloatRect& absoluteTargetRect, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>&, ColorSpace); + static void renderSubtreeToImageBuffer(ImageBuffer*, RenderObject*, const AffineTransform&); + static void clipToImageBuffer(GraphicsContext*, const AffineTransform& absoluteTransform, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>&); + + static void calculateTransformationToOutermostSVGCoordinateSystem(const RenderObject*, AffineTransform& absoluteTransform); + static FloatRect clampedAbsoluteTargetRectForRenderer(const RenderObject*, const FloatRect& absoluteTargetRect); + static IntSize roundedImageBufferSize(const FloatSize&); + +private: + SVGImageBufferTools() { } + ~SVGImageBufferTools() { } +}; + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp b/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp index ea806c7..10735f6 100644 --- a/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp +++ b/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp @@ -1,7 +1,7 @@ /* * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> - * (C) 2006 Apple Computer Inc. - * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2006 Apple Computer Inc. + * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * Copyright (C) Research In Motion Limited 2010. All rights reserved. * * This library is free software; you can redistribute it and/or @@ -18,7 +18,6 @@ * 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. - * */ #include "config.h" diff --git a/Source/WebCore/rendering/svg/SVGInlineFlowBox.h b/Source/WebCore/rendering/svg/SVGInlineFlowBox.h index 2358f2d..0e56c9f 100644 --- a/Source/WebCore/rendering/svg/SVGInlineFlowBox.h +++ b/Source/WebCore/rendering/svg/SVGInlineFlowBox.h @@ -1,8 +1,6 @@ /* - * This file is part of the WebKit project. - * * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> - * (C) 2006 Apple Computer Inc. + * Copyright (C) 2006 Apple Computer Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -18,7 +16,6 @@ * 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 SVGInlineFlowBox_h diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp index 5d0278b..f370310 100644 --- a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp +++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp @@ -1,6 +1,6 @@ /** * Copyright (C) 2007 Rob Buis <buis@kde.org> - * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * Copyright (C) Research In Motion Limited 2010. All rights reserved. * * This library is free software; you can redistribute it and/or @@ -17,7 +17,6 @@ * 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. - * */ #include "config.h" diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.h b/Source/WebCore/rendering/svg/SVGInlineTextBox.h index acc5e9f..0458de0 100644 --- a/Source/WebCore/rendering/svg/SVGInlineTextBox.h +++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2007 Rob Buis <buis@kde.org> - * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * Copyright (C) Research In Motion Limited 2010. All rights reserved. * * This library is free software; you can redistribute it and/or @@ -17,7 +17,6 @@ * 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 SVGInlineTextBox_h diff --git a/Source/WebCore/rendering/svg/SVGMarkerData.h b/Source/WebCore/rendering/svg/SVGMarkerData.h new file mode 100644 index 0000000..57c35cd --- /dev/null +++ b/Source/WebCore/rendering/svg/SVGMarkerData.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 SVGMarkerData_h +#define SVGMarkerData_h + +#if ENABLE(SVG) +#include "FloatConversion.h" +#include "Path.h" +#include <wtf/MathExtras.h> + +namespace WebCore { + +class RenderSVGResourceMarker; + +class SVGMarkerData { +public: + enum Type { + Unknown = 0, + Start, + Mid, + End + }; + + SVGMarkerData(const Type& type = Unknown, RenderSVGResourceMarker* marker = 0) + : m_type(type) + , m_marker(marker) + { + } + + FloatPoint origin() const { return m_origin; } + RenderSVGResourceMarker* marker() const { return m_marker; } + + float currentAngle() const + { + FloatSize inslopeChange = m_inslopePoints[1] - m_inslopePoints[0]; + FloatSize outslopeChange = m_outslopePoints[1] - m_outslopePoints[0]; + + double inslope = rad2deg(atan2(inslopeChange.height(), inslopeChange.width())); + double outslope = rad2deg(atan2(outslopeChange.height(), outslopeChange.width())); + + double angle = 0; + switch (m_type) { + case Start: + angle = outslope; + break; + case Mid: + angle = (inslope + outslope) / 2; + break; + case End: + angle = inslope; + break; + default: + ASSERT_NOT_REACHED(); + break; + } + + return narrowPrecisionToFloat(angle); + } + + void updateTypeAndMarker(const Type& type, RenderSVGResourceMarker* marker) + { + m_type = type; + m_marker = marker; + } + + void updateOutslope(const FloatPoint& point) + { + m_outslopePoints[0] = m_origin; + m_outslopePoints[1] = point; + } + + void updateMarkerDataForPathElement(const PathElement* element) + { + FloatPoint* points = element->points; + + switch (element->type) { + case PathElementAddQuadCurveToPoint: + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=33115 (PathElementAddQuadCurveToPoint not handled for <marker>) + m_origin = points[1]; + break; + case PathElementAddCurveToPoint: + m_inslopePoints[0] = points[1]; + m_inslopePoints[1] = points[2]; + m_origin = points[2]; + break; + case PathElementMoveToPoint: + m_subpathStart = points[0]; + case PathElementAddLineToPoint: + updateInslope(points[0]); + m_origin = points[0]; + break; + case PathElementCloseSubpath: + updateInslope(points[0]); + m_origin = m_subpathStart; + m_subpathStart = FloatPoint(); + } + } + +private: + void updateInslope(const FloatPoint& point) + { + m_inslopePoints[0] = m_origin; + m_inslopePoints[1] = point; + } + + Type m_type; + RenderSVGResourceMarker* m_marker; + FloatPoint m_origin; + FloatPoint m_subpathStart; + FloatPoint m_inslopePoints[2]; + FloatPoint m_outslopePoints[2]; +}; + +} + +#endif // ENABLE(SVG) +#endif // SVGMarkerData_h diff --git a/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.cpp b/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.cpp new file mode 100644 index 0000000..dea5a0c --- /dev/null +++ b/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005, 2008 Rob Buis <buis@kde.org> + * Copyright (C) 2005, 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Google, Inc. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "SVGMarkerLayoutInfo.h" + +#include "RenderSVGResourceMarker.h" + +namespace WebCore { + +SVGMarkerLayoutInfo::SVGMarkerLayoutInfo() + : m_midMarker(0) + , m_elementIndex(0) + , m_strokeWidth(0) +{ +} + +SVGMarkerLayoutInfo::~SVGMarkerLayoutInfo() +{ +} + +static inline void processStartAndMidMarkers(void* infoPtr, const PathElement* element) +{ + SVGMarkerLayoutInfo& info = *reinterpret_cast<SVGMarkerLayoutInfo*>(infoPtr); + SVGMarkerData& markerData = info.markerData(); + int& elementIndex = info.elementIndex(); + + // First update the outslope for the previous element + markerData.updateOutslope(element->points[0]); + + // Draw the marker for the previous element + RenderSVGResourceMarker* marker = markerData.marker(); + if (elementIndex > 0 && marker) + info.addLayoutedMarker(marker, markerData.origin(), markerData.currentAngle()); + + // Update our marker data for this element + markerData.updateMarkerDataForPathElement(element); + + // After drawing the start marker, switch to drawing mid markers + if (elementIndex == 1) + markerData.updateTypeAndMarker(SVGMarkerData::Mid, info.midMarker()); + + ++elementIndex; +} + +FloatRect SVGMarkerLayoutInfo::calculateBoundaries(RenderSVGResourceMarker* startMarker, RenderSVGResourceMarker* midMarker, RenderSVGResourceMarker* endMarker, float strokeWidth, const Path& path) +{ + m_layout.clear(); + m_midMarker = midMarker; + m_strokeWidth = strokeWidth; + m_elementIndex = 0; + m_markerData = SVGMarkerData(SVGMarkerData::Start, startMarker); + path.apply(this, processStartAndMidMarkers); + + if (endMarker) { + m_markerData.updateTypeAndMarker(SVGMarkerData::End, endMarker); + addLayoutedMarker(endMarker, m_markerData.origin(), m_markerData.currentAngle()); + } + + if (m_layout.isEmpty()) + return FloatRect(); + + Vector<MarkerLayout>::iterator it = m_layout.begin(); + Vector<MarkerLayout>::iterator end = m_layout.end(); + + FloatRect bounds; + for (; it != end; ++it) { + MarkerLayout& layout = *it; + + RenderSVGResourceMarker* markerContent = layout.marker; + ASSERT(markerContent); + + bounds.unite(markerContent->markerBoundaries(layout.matrix)); + } + + return bounds; +} + +void SVGMarkerLayoutInfo::drawMarkers(PaintInfo& paintInfo) +{ + if (m_layout.isEmpty()) + return; + + Vector<MarkerLayout>::iterator it = m_layout.begin(); + Vector<MarkerLayout>::iterator end = m_layout.end(); + + for (; it != end; ++it) { + MarkerLayout& layout = *it; + layout.marker->draw(paintInfo, layout.matrix); + } +} + +void SVGMarkerLayoutInfo::addLayoutedMarker(RenderSVGResourceMarker* marker, const FloatPoint& origin, float angle) +{ + ASSERT(marker); + m_layout.append(MarkerLayout(marker, marker->markerTransformation(origin, angle, m_strokeWidth))); +} + +} + +#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.h b/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.h new file mode 100644 index 0000000..0eb3689 --- /dev/null +++ b/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 SVGMarkerLayoutInfo_h +#define SVGMarkerLayoutInfo_h + +#if ENABLE(SVG) +#include "RenderObject.h" +#include "SVGMarkerData.h" +#include <wtf/Noncopyable.h> + +namespace WebCore { + +class Path; +class RenderSVGResourceMarker; + +struct MarkerLayout { + MarkerLayout(RenderSVGResourceMarker* markerObj = 0, AffineTransform matrixObj = AffineTransform()) + : marker(markerObj) + , matrix(matrixObj) + { + ASSERT(marker); + } + + RenderSVGResourceMarker* marker; + AffineTransform matrix; +}; + +class SVGMarkerLayoutInfo : public Noncopyable { +public: + SVGMarkerLayoutInfo(); + ~SVGMarkerLayoutInfo(); + + FloatRect calculateBoundaries(RenderSVGResourceMarker* startMarker, RenderSVGResourceMarker* midMarker, RenderSVGResourceMarker* endMarker, float strokeWidth, const Path&); + void drawMarkers(PaintInfo&); + + // Used by static inline helper functions in SVGMarkerLayoutInfo.cpp + SVGMarkerData& markerData() { return m_markerData; } + RenderSVGResourceMarker* midMarker() const { return m_midMarker; } + int& elementIndex() { return m_elementIndex; } + void addLayoutedMarker(RenderSVGResourceMarker*, const FloatPoint& origin, float angle); + +private: + RenderSVGResourceMarker* m_midMarker; + + // Used while layouting markers + int m_elementIndex; + SVGMarkerData m_markerData; + float m_strokeWidth; + + // Holds the final computed result + Vector<MarkerLayout> m_layout; +}; + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/SVGRenderSupport.cpp b/Source/WebCore/rendering/svg/SVGRenderSupport.cpp new file mode 100644 index 0000000..bfc74f0 --- /dev/null +++ b/Source/WebCore/rendering/svg/SVGRenderSupport.cpp @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2007, 2008 Rob Buis <buis@kde.org> + * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Google, Inc. All rights reserved. + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "SVGRenderSupport.h" + +#include "FrameView.h" +#include "ImageBuffer.h" +#include "NodeRenderStyle.h" +#include "RenderLayer.h" +#include "RenderSVGPath.h" +#include "RenderSVGResource.h" +#include "RenderSVGResourceClipper.h" +#include "RenderSVGResourceFilter.h" +#include "RenderSVGResourceMarker.h" +#include "RenderSVGResourceMasker.h" +#include "RenderSVGRoot.h" +#include "SVGResources.h" +#include "SVGStyledElement.h" +#include "TransformState.h" +#include <wtf/UnusedParam.h> + +namespace WebCore { + +IntRect SVGRenderSupport::clippedOverflowRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer) +{ + // Return early for any cases where we don't actually paint + if (object->style()->visibility() != VISIBLE && !object->enclosingLayer()->hasVisibleContent()) + return IntRect(); + + // Pass our local paint rect to computeRectForRepaint() which will + // map to parent coords and recurse up the parent chain. + IntRect repaintRect = enclosingIntRect(object->repaintRectInLocalCoordinates()); + object->computeRectForRepaint(repaintContainer, repaintRect); + return repaintRect; +} + +void SVGRenderSupport::computeRectForRepaint(RenderObject* object, RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed) +{ + const SVGRenderStyle* svgStyle = object->style()->svgStyle(); + if (const ShadowData* shadow = svgStyle->shadow()) + shadow->adjustRectForShadow(repaintRect); + + // Translate to coords in our parent renderer, and then call computeRectForRepaint on our parent + repaintRect = object->localToParentTransform().mapRect(repaintRect); + object->parent()->computeRectForRepaint(repaintContainer, repaintRect, fixed); +} + +void SVGRenderSupport::mapLocalToContainer(const RenderObject* object, RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) +{ + ASSERT(!fixed); // We should have no fixed content in the SVG rendering tree. + ASSERT(useTransforms); // Mapping a point through SVG w/o respecting transforms is useless. + transformState.applyTransform(object->localToParentTransform()); + object->parent()->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState); +} + +bool SVGRenderSupport::prepareToRenderSVGContent(RenderObject* object, PaintInfo& paintInfo) +{ + ASSERT(object); + + RenderStyle* style = object->style(); + ASSERT(style); + + const SVGRenderStyle* svgStyle = style->svgStyle(); + ASSERT(svgStyle); + + // Setup transparency layers before setting up SVG resources! + float opacity = style->opacity(); + const ShadowData* shadow = svgStyle->shadow(); + if (opacity < 1 || shadow) { + FloatRect repaintRect = object->repaintRectInLocalCoordinates(); + + if (opacity < 1) { + paintInfo.context->clip(repaintRect); + paintInfo.context->beginTransparencyLayer(opacity); + } + + if (shadow) { + paintInfo.context->clip(repaintRect); + paintInfo.context->setShadow(IntSize(shadow->x(), shadow->y()), shadow->blur(), shadow->color(), style->colorSpace()); + paintInfo.context->beginTransparencyLayer(1); + } + } + + SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object); + if (!resources) + return true; + + if (RenderSVGResourceMasker* masker = resources->masker()) { + if (!masker->applyResource(object, style, paintInfo.context, ApplyToDefaultMode)) + return false; + } + + if (RenderSVGResourceClipper* clipper = resources->clipper()) { + if (!clipper->applyResource(object, style, paintInfo.context, ApplyToDefaultMode)) + return false; + } + +#if ENABLE(FILTERS) + if (RenderSVGResourceFilter* filter = resources->filter()) { + if (!filter->applyResource(object, style, paintInfo.context, ApplyToDefaultMode)) + return false; + } +#endif + + return true; +} + +void SVGRenderSupport::finishRenderSVGContent(RenderObject* object, PaintInfo& paintInfo, GraphicsContext* savedContext) +{ +#if !ENABLE(FILTERS) + UNUSED_PARAM(savedContext); +#endif + + ASSERT(object); + + const RenderStyle* style = object->style(); + ASSERT(style); + + const SVGRenderStyle* svgStyle = style->svgStyle(); + ASSERT(svgStyle); + +#if ENABLE(FILTERS) + SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object); + if (resources) { + if (RenderSVGResourceFilter* filter = resources->filter()) { + filter->postApplyResource(object, paintInfo.context, ApplyToDefaultMode, /* path */0); + paintInfo.context = savedContext; + } + } +#endif + + if (style->opacity() < 1) + paintInfo.context->endTransparencyLayer(); + + if (svgStyle->shadow()) + paintInfo.context->endTransparencyLayer(); +} + +void SVGRenderSupport::computeContainerBoundingBoxes(const RenderObject* container, FloatRect& objectBoundingBox, FloatRect& strokeBoundingBox, FloatRect& repaintBoundingBox) +{ + for (RenderObject* current = container->firstChild(); current; current = current->nextSibling()) { + if (current->isSVGHiddenContainer()) + continue; + + const AffineTransform& transform = current->localToParentTransform(); + if (transform.isIdentity()) { + objectBoundingBox.unite(current->objectBoundingBox()); + strokeBoundingBox.unite(current->strokeBoundingBox()); + repaintBoundingBox.unite(current->repaintRectInLocalCoordinates()); + } else { + objectBoundingBox.unite(transform.mapRect(current->objectBoundingBox())); + strokeBoundingBox.unite(transform.mapRect(current->strokeBoundingBox())); + repaintBoundingBox.unite(transform.mapRect(current->repaintRectInLocalCoordinates())); + } + } +} + +bool SVGRenderSupport::paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo& paintInfo) +{ + if (localTransform.isIdentity()) + return localRepaintRect.intersects(paintInfo.rect); + + return localTransform.mapRect(localRepaintRect).intersects(paintInfo.rect); +} + +const RenderSVGRoot* SVGRenderSupport::findTreeRootObject(const RenderObject* start) +{ + while (start && !start->isSVGRoot()) + start = start->parent(); + + ASSERT(start); + ASSERT(start->isSVGRoot()); + return toRenderSVGRoot(start); +} + +static inline void invalidateResourcesOfChildren(RenderObject* start) +{ + ASSERT(!start->needsLayout()); + if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(start)) + resources->removeClientFromCache(start, false); + + for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) + invalidateResourcesOfChildren(child); +} + +void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout) +{ + bool layoutSizeChanged = findTreeRootObject(start)->isLayoutSizeChanged(); + HashSet<RenderObject*> notlayoutedObjects; + + for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { + bool needsLayout = selfNeedsLayout; + + if (layoutSizeChanged) { + // When selfNeedsLayout is false and the layout size changed, we have to check whether this child uses relative lengths + if (SVGElement* element = child->node()->isSVGElement() ? static_cast<SVGElement*>(child->node()) : 0) { + if (element->isStyled() && static_cast<SVGStyledElement*>(element)->hasRelativeLengths()) { + // When the layout size changed and when using relative values tell the RenderSVGPath to update its Path object + if (child->isSVGPath()) + toRenderSVGPath(child)->setNeedsPathUpdate(); + + needsLayout = true; + } + } + } + + if (needsLayout) { + child->setNeedsLayout(true, false); + child->layout(); + } else { + if (child->needsLayout()) + child->layout(); + else if (layoutSizeChanged) + notlayoutedObjects.add(child); + } + + ASSERT(!child->needsLayout()); + } + + if (!layoutSizeChanged) { + ASSERT(notlayoutedObjects.isEmpty()); + return; + } + + // If the layout size changed, invalidate all resources of all children that didn't go through the layout() code path. + HashSet<RenderObject*>::iterator end = notlayoutedObjects.end(); + for (HashSet<RenderObject*>::iterator it = notlayoutedObjects.begin(); it != end; ++it) + invalidateResourcesOfChildren(*it); +} + +bool SVGRenderSupport::isOverflowHidden(const RenderObject* object) +{ + // SVG doesn't support independent x/y overflow + ASSERT(object->style()->overflowX() == object->style()->overflowY()); + + // OSCROLL is never set for SVG - see CSSStyleSelector::adjustRenderStyle + ASSERT(object->style()->overflowX() != OSCROLL); + + // RenderSVGRoot should never query for overflow state - it should always clip itself to the initial viewport size. + ASSERT(!object->isRoot()); + + return object->style()->overflowX() == OHIDDEN; +} + +void SVGRenderSupport::intersectRepaintRectWithResources(const RenderObject* object, FloatRect& repaintRect) +{ + ASSERT(object); + + RenderStyle* style = object->style(); + ASSERT(style); + + const SVGRenderStyle* svgStyle = style->svgStyle(); + ASSERT(svgStyle); + + RenderObject* renderer = const_cast<RenderObject*>(object); + SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer); + if (!resources) { + if (const ShadowData* shadow = svgStyle->shadow()) + shadow->adjustRectForShadow(repaintRect); + return; + } + +#if ENABLE(FILTERS) + if (RenderSVGResourceFilter* filter = resources->filter()) + repaintRect = filter->resourceBoundingBox(renderer); +#endif + + if (RenderSVGResourceClipper* clipper = resources->clipper()) + repaintRect.intersect(clipper->resourceBoundingBox(renderer)); + + if (RenderSVGResourceMasker* masker = resources->masker()) + repaintRect.intersect(masker->resourceBoundingBox(renderer)); + + if (const ShadowData* shadow = svgStyle->shadow()) + shadow->adjustRectForShadow(repaintRect); +} + +bool SVGRenderSupport::pointInClippingArea(RenderObject* object, const FloatPoint& point) +{ + ASSERT(object); + + // We just take clippers into account to determine if a point is on the node. The Specification may + // change later and we also need to check maskers. + SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object); + if (!resources) + return true; + + if (RenderSVGResourceClipper* clipper = resources->clipper()) + return clipper->hitTestClipContent(object->objectBoundingBox(), point); + + return true; +} + +void SVGRenderSupport::applyStrokeStyleToContext(GraphicsContext* context, const RenderStyle* style, const RenderObject* object) +{ + ASSERT(context); + ASSERT(style); + ASSERT(object); + ASSERT(object->node()); + ASSERT(object->node()->isSVGElement()); + + const SVGRenderStyle* svgStyle = style->svgStyle(); + ASSERT(svgStyle); + + SVGElement* lengthContext = static_cast<SVGElement*>(object->node()); + context->setStrokeThickness(svgStyle->strokeWidth().value(lengthContext)); + context->setLineCap(svgStyle->capStyle()); + context->setLineJoin(svgStyle->joinStyle()); + if (svgStyle->joinStyle() == MiterJoin) + context->setMiterLimit(svgStyle->strokeMiterLimit()); + + const Vector<SVGLength>& dashes = svgStyle->strokeDashArray(); + if (dashes.isEmpty()) + context->setStrokeStyle(SolidStroke); + else { + DashArray dashArray; + const Vector<SVGLength>::const_iterator end = dashes.end(); + for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it) + dashArray.append((*it).value(lengthContext)); + + context->setLineDash(dashArray, svgStyle->strokeDashOffset().value(lengthContext)); + } +} + +} + +#endif diff --git a/Source/WebCore/rendering/svg/SVGRenderSupport.h b/Source/WebCore/rendering/svg/SVGRenderSupport.h new file mode 100644 index 0000000..9e6aa5c --- /dev/null +++ b/Source/WebCore/rendering/svg/SVGRenderSupport.h @@ -0,0 +1,83 @@ +/** + * Copyright (C) 2007 Rob Buis <buis@kde.org> + * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Google, Inc. All rights reserved. + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 SVGRenderSupport_h +#define SVGRenderSupport_h + +#if ENABLE(SVG) +#include "PaintInfo.h" + +namespace WebCore { + +class FloatPoint; +class FloatRect; +class ImageBuffer; +class RenderBoxModelObject; +class RenderObject; +class RenderStyle; +class RenderSVGRoot; +class TransformState; + +// SVGRendererSupport is a helper class sharing code between all SVG renderers. +class SVGRenderSupport { +public: + // Used by all SVG renderers who apply clip/filter/etc. resources to the renderer content + static bool prepareToRenderSVGContent(RenderObject*, PaintInfo&); + static void finishRenderSVGContent(RenderObject*, PaintInfo&, GraphicsContext* savedContext); + + // Shares child layouting code between RenderSVGRoot/RenderSVG(Hidden)Container + static void layoutChildren(RenderObject*, bool selfNeedsLayout); + + // Helper function determining wheter overflow is hidden + static bool isOverflowHidden(const RenderObject*); + + // Calculates the repaintRect in combination with filter, clipper and masker in local coordinates. + static void intersectRepaintRectWithResources(const RenderObject*, FloatRect&); + + // Determines whether the passed point lies in a clipping area + static bool pointInClippingArea(RenderObject*, const FloatPoint&); + + static void computeContainerBoundingBoxes(const RenderObject* container, FloatRect& objectBoundingBox, FloatRect& strokeBoundingBox, FloatRect& repaintBoundingBox); + static bool paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo&); + + // Important functions used by nearly all SVG renderers centralizing coordinate transformations / repaint rect calculations + static IntRect clippedOverflowRectForRepaint(RenderObject*, RenderBoxModelObject* repaintContainer); + static void computeRectForRepaint(RenderObject*, RenderBoxModelObject* repaintContainer, IntRect&, bool fixed); + static void mapLocalToContainer(const RenderObject*, RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&); + + // Shared between SVG renderers and resources. + static void applyStrokeStyleToContext(GraphicsContext*, const RenderStyle*, const RenderObject*); + + // FIXME: These methods do not belong here. + static const RenderSVGRoot* findTreeRootObject(const RenderObject*); + +private: + // This class is not constructable. + SVGRenderSupport(); + ~SVGRenderSupport(); +}; + +} // namespace WebCore + +#endif // ENABLE(SVG) +#endif // SVGRenderSupport_h diff --git a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp new file mode 100644 index 0000000..97e15af --- /dev/null +++ b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp @@ -0,0 +1,748 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2009 Apple Inc. All rights reserved. + * (C) 2005 Rob Buis <buis@kde.org> + * (C) 2006 Alexander Kellett <lypanov@kde.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 "InlineTextBox.h" +#include "LinearGradientAttributes.h" +#include "NodeRenderStyle.h" +#include "Path.h" +#include "PatternAttributes.h" +#include "RadialGradientAttributes.h" +#include "RenderImage.h" +#include "RenderSVGContainer.h" +#include "RenderSVGGradientStop.h" +#include "RenderSVGImage.h" +#include "RenderSVGInlineText.h" +#include "RenderSVGPath.h" +#include "RenderSVGResourceClipper.h" +#include "RenderSVGResourceFilter.h" +#include "RenderSVGResourceGradient.h" +#include "RenderSVGResourceLinearGradient.h" +#include "RenderSVGResourceMarker.h" +#include "RenderSVGResourceMasker.h" +#include "RenderSVGResourcePattern.h" +#include "RenderSVGResourceRadialGradient.h" +#include "RenderSVGResourceSolidColor.h" +#include "RenderSVGRoot.h" +#include "RenderSVGText.h" +#include "RenderTreeAsText.h" +#include "SVGCircleElement.h" +#include "SVGEllipseElement.h" +#include "SVGInlineTextBox.h" +#include "SVGLineElement.h" +#include "SVGLinearGradientElement.h" +#include "SVGNames.h" +#include "SVGPathElement.h" +#include "SVGPathParserFactory.h" +#include "SVGPatternElement.h" +#include "SVGPointList.h" +#include "SVGPolyElement.h" +#include "SVGRadialGradientElement.h" +#include "SVGRectElement.h" +#include "SVGRootInlineBox.h" +#include "SVGStopElement.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; +} + +template<typename ValueType> +static void writeNameValuePair(TextStream& ts, const char* name, ValueType value) +{ + ts << " [" << name << "=" << value << "]"; +} + +template<typename ValueType> +static void writeNameAndQuotedValue(TextStream& ts, const char* name, ValueType value) +{ + ts << " [" << name << "=\"" << value << "\"]"; +} + +static void writeIfNotEmpty(TextStream& ts, const char* name, const String& value) +{ + if (!value.isEmpty()) + writeNameValuePair(ts, name, value); +} + +template<typename ValueType> +static void writeIfNotDefault(TextStream& ts, const char* name, ValueType value, ValueType defaultValue) +{ + if (value != defaultValue) + writeNameValuePair(ts, name, value); +} + +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 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; +} + +static TextStream& operator<<(TextStream& ts, const WindRule rule) +{ + switch (rule) { + case RULE_NONZERO: + ts << "NON-ZERO"; + break; + case RULE_EVENODD: + ts << "EVEN-ODD"; + break; + } + + return ts; +} + +static TextStream& operator<<(TextStream& ts, const SVGUnitTypes::SVGUnitType& unitType) +{ + switch (unitType) { + case SVGUnitTypes::SVG_UNIT_TYPE_UNKNOWN: + ts << "unknown"; + break; + case SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE: + ts << "userSpaceOnUse"; + break; + case SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX: + ts << "objectBoundingBox"; + break; + } + + return ts; +} + +static TextStream& operator<<(TextStream& ts, const SVGMarkerElement::SVGMarkerUnitsType& markerUnit) +{ + switch (markerUnit) { + case SVGMarkerElement::SVG_MARKERUNITS_UNKNOWN: + ts << "unknown"; + break; + case SVGMarkerElement::SVG_MARKERUNITS_USERSPACEONUSE: + ts << "userSpaceOnUse"; + break; + case SVGMarkerElement::SVG_MARKERUNITS_STROKEWIDTH: + ts << "strokeWidth"; + break; + } + + return ts; +} + +TextStream& operator<<(TextStream& ts, const Color& c) +{ + return ts << c.name(); +} + +// FIXME: Maybe this should be in KCanvasRenderingStyle.cpp +static TextStream& operator<<(TextStream& ts, const DashArray& a) +{ + ts << "{"; + DashArray::const_iterator end = a.end(); + for (DashArray::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; +} + +// FIXME: Maybe this should be in Gradient.cpp +static TextStream& operator<<(TextStream& ts, GradientSpreadMethod mode) +{ + switch (mode) { + case SpreadMethodPad: + ts << "PAD"; + break; + case SpreadMethodRepeat: + ts << "REPEAT"; + break; + case SpreadMethodReflect: + ts << "REFLECT"; + break; + } + + return ts; +} + +static void writeSVGPaintingResource(TextStream& ts, RenderSVGResource* resource) +{ + if (resource->resourceType() == SolidColorResourceType) { + ts << "[type=SOLID] [color=" << static_cast<RenderSVGResourceSolidColor*>(resource)->color() << "]"; + return; + } + + // All other resources derive from RenderSVGResourceContainer + RenderSVGResourceContainer* container = static_cast<RenderSVGResourceContainer*>(resource); + Node* node = container->node(); + ASSERT(node); + ASSERT(node->isSVGElement()); + + if (resource->resourceType() == PatternResourceType) + ts << "[type=PATTERN]"; + else if (resource->resourceType() == LinearGradientResourceType) + ts << "[type=LINEAR-GRADIENT]"; + else if (resource->resourceType() == RadialGradientResourceType) + ts << "[type=RADIAL-GRADIENT]"; + + ts << " [id=\"" << static_cast<SVGElement*>(node)->getIdAttribute() << "\"]"; +} + +static void writeStyle(TextStream& ts, const RenderObject& object) +{ + const RenderStyle* style = object.style(); + const SVGRenderStyle* svgStyle = style->svgStyle(); + + if (!object.localTransform().isIdentity()) + writeNameValuePair(ts, "transform", object.localTransform()); + writeIfNotDefault(ts, "image rendering", svgStyle->imageRendering(), SVGRenderStyle::initialImageRendering()); + writeIfNotDefault(ts, "opacity", style->opacity(), RenderStyle::initialOpacity()); + if (object.isSVGPath()) { + const RenderSVGPath& path = static_cast<const RenderSVGPath&>(object); + ASSERT(path.node()); + ASSERT(path.node()->isSVGElement()); + + Color fallbackColor; + if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(const_cast<RenderSVGPath*>(&path), path.style(), fallbackColor)) { + TextStreamSeparator s(" "); + ts << " [stroke={" << s; + writeSVGPaintingResource(ts, strokePaintingResource); + + SVGElement* element = static_cast<SVGElement*>(path.node()); + double dashOffset = svgStyle->strokeDashOffset().value(element); + double strokeWidth = svgStyle->strokeWidth().value(element); + const Vector<SVGLength>& dashes = svgStyle->strokeDashArray(); + + DashArray dashArray; + const Vector<SVGLength>::const_iterator end = dashes.end(); + for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it) + dashArray.append((*it).value(element)); + + writeIfNotDefault(ts, "opacity", svgStyle->strokeOpacity(), 1.0f); + writeIfNotDefault(ts, "stroke width", strokeWidth, 1.0); + writeIfNotDefault(ts, "miter limit", svgStyle->strokeMiterLimit(), 4.0f); + writeIfNotDefault(ts, "line cap", svgStyle->capStyle(), ButtCap); + writeIfNotDefault(ts, "line join", svgStyle->joinStyle(), MiterJoin); + writeIfNotDefault(ts, "dash offset", dashOffset, 0.0); + if (!dashArray.isEmpty()) + writeNameValuePair(ts, "dash array", dashArray); + + ts << "}]"; + } + + if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(const_cast<RenderSVGPath*>(&path), path.style(), fallbackColor)) { + TextStreamSeparator s(" "); + ts << " [fill={" << s; + writeSVGPaintingResource(ts, fillPaintingResource); + + writeIfNotDefault(ts, "opacity", svgStyle->fillOpacity(), 1.0f); + writeIfNotDefault(ts, "fill rule", svgStyle->fillRule(), RULE_NONZERO); + ts << "}]"; + } + writeIfNotDefault(ts, "clip rule", svgStyle->clipRule(), RULE_NONZERO); + } + + writeIfNotEmpty(ts, "start marker", svgStyle->markerStartResource()); + writeIfNotEmpty(ts, "middle marker", svgStyle->markerMidResource()); + writeIfNotEmpty(ts, "end marker", svgStyle->markerEndResource()); +} + +static TextStream& writePositionAndStyle(TextStream& ts, const RenderObject& object) +{ + ts << " " << const_cast<RenderObject&>(object).absoluteClippedOverflowRect(); + writeStyle(ts, object); + return ts; +} + +static TextStream& operator<<(TextStream& ts, const RenderSVGPath& path) +{ + writePositionAndStyle(ts, path); + + ASSERT(path.node()->isSVGElement()); + SVGElement* svgElement = static_cast<SVGElement*>(path.node()); + + if (svgElement->hasTagName(SVGNames::rectTag)) { + SVGRectElement* element = static_cast<SVGRectElement*>(svgElement); + writeNameValuePair(ts, "x", element->x().value(element)); + writeNameValuePair(ts, "y", element->y().value(element)); + writeNameValuePair(ts, "width", element->width().value(element)); + writeNameValuePair(ts, "height", element->height().value(element)); + } else if (svgElement->hasTagName(SVGNames::lineTag)) { + SVGLineElement* element = static_cast<SVGLineElement*>(svgElement); + writeNameValuePair(ts, "x1", element->x1().value(element)); + writeNameValuePair(ts, "y1", element->y1().value(element)); + writeNameValuePair(ts, "x2", element->x2().value(element)); + writeNameValuePair(ts, "y2", element->y2().value(element)); + } else if (svgElement->hasTagName(SVGNames::ellipseTag)) { + SVGEllipseElement* element = static_cast<SVGEllipseElement*>(svgElement); + writeNameValuePair(ts, "cx", element->cx().value(element)); + writeNameValuePair(ts, "cy", element->cy().value(element)); + writeNameValuePair(ts, "rx", element->rx().value(element)); + writeNameValuePair(ts, "ry", element->ry().value(element)); + } else if (svgElement->hasTagName(SVGNames::circleTag)) { + SVGCircleElement* element = static_cast<SVGCircleElement*>(svgElement); + writeNameValuePair(ts, "cx", element->cx().value(element)); + writeNameValuePair(ts, "cy", element->cy().value(element)); + writeNameValuePair(ts, "r", element->r().value(element)); + } else if (svgElement->hasTagName(SVGNames::polygonTag) || svgElement->hasTagName(SVGNames::polylineTag)) { + SVGPolyElement* element = static_cast<SVGPolyElement*>(svgElement); + writeNameAndQuotedValue(ts, "points", element->pointList().valueAsString()); + } else if (svgElement->hasTagName(SVGNames::pathTag)) { + SVGPathElement* element = static_cast<SVGPathElement*>(svgElement); + String pathString; + // FIXME: We should switch to UnalteredParsing here - this will affect the path dumping output of dozens of tests. + SVGPathParserFactory::self()->buildStringFromByteStream(element->pathByteStream(), pathString, NormalizedParsing); + writeNameAndQuotedValue(ts, "data", pathString); + } else + ASSERT_NOT_REACHED(); + return ts; +} + +static TextStream& operator<<(TextStream& ts, const RenderSVGRoot& root) +{ + return writePositionAndStyle(ts, root); +} + +static void writeRenderSVGTextBox(TextStream& ts, const RenderBlock& text) +{ + SVGRootInlineBox* box = static_cast<SVGRootInlineBox*>(text.firstRootBox()); + if (!box) + return; + + ts << " at (" << text.x() << "," << text.y() << ") size " << box->logicalWidth() << "x" << box->logicalHeight(); + + // FIXME: Remove this hack, once the new text layout engine is completly landed. We want to preserve the old layout test results for now. + ts << " contains 1 chunk(s)"; + + if (text.parent() && (text.parent()->style()->visitedDependentColor(CSSPropertyColor) != text.style()->visitedDependentColor(CSSPropertyColor))) + writeNameValuePair(ts, "color", text.style()->visitedDependentColor(CSSPropertyColor).name()); +} + +static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textBox, int indent) +{ + Vector<SVGTextFragment>& fragments = textBox->textFragments(); + if (fragments.isEmpty()) + return; + + RenderSVGInlineText* textRenderer = toRenderSVGInlineText(textBox->textRenderer()); + ASSERT(textRenderer); + + const SVGRenderStyle* svgStyle = textRenderer->style()->svgStyle(); + String text = textBox->textRenderer()->text(); + + unsigned fragmentsSize = fragments.size(); + for (unsigned i = 0; i < fragmentsSize; ++i) { + SVGTextFragment& fragment = fragments.at(i); + writeIndent(ts, indent + 1); + + unsigned startOffset = fragment.positionListOffset; + unsigned endOffset = fragment.positionListOffset + fragment.length; + + // FIXME: Remove this hack, once the new text layout engine is completly landed. We want to preserve the old layout test results for now. + ts << "chunk 1 "; + ETextAnchor anchor = svgStyle->textAnchor(); + bool isVerticalText = svgStyle->isVerticalWritingMode(); + if (anchor == TA_MIDDLE) { + ts << "(middle anchor"; + if (isVerticalText) + ts << ", vertical"; + ts << ") "; + } else if (anchor == TA_END) { + ts << "(end anchor"; + if (isVerticalText) + ts << ", vertical"; + ts << ") "; + } else if (isVerticalText) + ts << "(vertical) "; + startOffset -= textBox->start(); + endOffset -= textBox->start(); + // </hack> + + ts << "text run " << i + 1 << " at (" << fragment.x << "," << fragment.y << ")"; + ts << " startOffset " << startOffset << " endOffset " << endOffset; + if (isVerticalText) + ts << " height " << fragment.height; + else + ts << " width " << fragment.width; + + if (!textBox->isLeftToRightDirection() || textBox->m_dirOverride) { + ts << (textBox->isLeftToRightDirection() ? " LTR" : " RTL"); + if (textBox->m_dirOverride) + ts << " override"; + } + + ts << ": " << quoteAndEscapeNonPrintables(text.substring(fragment.positionListOffset, fragment.length)) << "\n"; + } +} + +static inline void writeSVGInlineTextBoxes(TextStream& ts, const RenderText& text, int indent) +{ + for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox()) + writeSVGInlineTextBox(ts, static_cast<SVGInlineTextBox*>(box), indent); +} + +static void writeStandardPrefix(TextStream& ts, const RenderObject& object, int indent) +{ + writeIndent(ts, indent); + ts << object.renderName(); + + if (object.node()) + ts << " {" << object.node()->nodeName() << "}"; +} + +static void writeChildren(TextStream& ts, const RenderObject& object, int indent) +{ + for (RenderObject* child = object.firstChild(); child; child = child->nextSibling()) + write(ts, *child, indent + 1); +} + +static inline String boundingBoxModeString(bool boundingBoxMode) +{ + return boundingBoxMode ? "objectBoundingBox" : "userSpaceOnUse"; +} + +static inline void writeCommonGradientProperties(TextStream& ts, GradientSpreadMethod spreadMethod, const AffineTransform& gradientTransform, bool boundingBoxMode) +{ + writeNameValuePair(ts, "gradientUnits", boundingBoxModeString(boundingBoxMode)); + + if (spreadMethod != SpreadMethodPad) + ts << " [spreadMethod=" << spreadMethod << "]"; + + if (!gradientTransform.isIdentity()) + ts << " [gradientTransform=" << gradientTransform << "]"; +} + +void writeSVGResourceContainer(TextStream& ts, const RenderObject& object, int indent) +{ + writeStandardPrefix(ts, object, indent); + + Element* element = static_cast<Element*>(object.node()); + const AtomicString& id = element->getIdAttribute(); + writeNameAndQuotedValue(ts, "id", id); + + RenderSVGResourceContainer* resource = const_cast<RenderObject&>(object).toRenderSVGResourceContainer(); + ASSERT(resource); + + if (resource->resourceType() == MaskerResourceType) { + RenderSVGResourceMasker* masker = static_cast<RenderSVGResourceMasker*>(resource); + writeNameValuePair(ts, "maskUnits", masker->maskUnits()); + writeNameValuePair(ts, "maskContentUnits", masker->maskContentUnits()); + ts << "\n"; +#if ENABLE(FILTERS) + } else if (resource->resourceType() == FilterResourceType) { + RenderSVGResourceFilter* filter = static_cast<RenderSVGResourceFilter*>(resource); + writeNameValuePair(ts, "filterUnits", filter->filterUnits()); + writeNameValuePair(ts, "primitiveUnits", filter->primitiveUnits()); + ts << "\n"; + // Creating a placeholder filter which is passed to the builder. + FloatRect dummyRect; + RefPtr<SVGFilter> dummyFilter = SVGFilter::create(AffineTransform(), dummyRect, dummyRect, dummyRect, true); + if (RefPtr<SVGFilterBuilder> builder = filter->buildPrimitives(dummyFilter.get())) { + if (FilterEffect* lastEffect = builder->lastEffect()) + lastEffect->externalRepresentation(ts, indent + 1); + } +#endif + } else if (resource->resourceType() == ClipperResourceType) { + RenderSVGResourceClipper* clipper = static_cast<RenderSVGResourceClipper*>(resource); + writeNameValuePair(ts, "clipPathUnits", clipper->clipPathUnits()); + ts << "\n"; + } else if (resource->resourceType() == MarkerResourceType) { + RenderSVGResourceMarker* marker = static_cast<RenderSVGResourceMarker*>(resource); + writeNameValuePair(ts, "markerUnits", marker->markerUnits()); + ts << " [ref at " << marker->referencePoint() << "]"; + ts << " [angle="; + if (marker->angle() == -1) + ts << "auto" << "]\n"; + else + ts << marker->angle() << "]\n"; + } else if (resource->resourceType() == PatternResourceType) { + RenderSVGResourcePattern* pattern = static_cast<RenderSVGResourcePattern*>(resource); + + // Dump final results that are used for rendering. No use in asking SVGPatternElement for its patternUnits(), as it may + // link to other patterns using xlink:href, we need to build the full inheritance chain, aka. collectPatternProperties() + PatternAttributes attributes; + static_cast<SVGPatternElement*>(pattern->node())->collectPatternAttributes(attributes); + + writeNameValuePair(ts, "patternUnits", boundingBoxModeString(attributes.boundingBoxMode())); + writeNameValuePair(ts, "patternContentUnits", boundingBoxModeString(attributes.boundingBoxModeContent())); + + AffineTransform transform = attributes.patternTransform(); + if (!transform.isIdentity()) + ts << " [patternTransform=" << transform << "]"; + ts << "\n"; + } else if (resource->resourceType() == LinearGradientResourceType) { + RenderSVGResourceLinearGradient* gradient = static_cast<RenderSVGResourceLinearGradient*>(resource); + + // Dump final results that are used for rendering. No use in asking SVGGradientElement for its gradientUnits(), as it may + // link to other gradients using xlink:href, we need to build the full inheritance chain, aka. collectGradientProperties() + SVGLinearGradientElement* linearGradientElement = static_cast<SVGLinearGradientElement*>(gradient->node()); + + LinearGradientAttributes attributes; + linearGradientElement->collectGradientAttributes(attributes); + writeCommonGradientProperties(ts, attributes.spreadMethod(), attributes.gradientTransform(), attributes.boundingBoxMode()); + + FloatPoint startPoint; + FloatPoint endPoint; + linearGradientElement->calculateStartEndPoints(attributes, startPoint, endPoint); + + ts << " [start=" << startPoint << "] [end=" << endPoint << "]\n"; + } else if (resource->resourceType() == RadialGradientResourceType) { + RenderSVGResourceRadialGradient* gradient = static_cast<RenderSVGResourceRadialGradient*>(resource); + + // Dump final results that are used for rendering. No use in asking SVGGradientElement for its gradientUnits(), as it may + // link to other gradients using xlink:href, we need to build the full inheritance chain, aka. collectGradientProperties() + SVGRadialGradientElement* radialGradientElement = static_cast<SVGRadialGradientElement*>(gradient->node()); + + RadialGradientAttributes attributes; + radialGradientElement->collectGradientAttributes(attributes); + writeCommonGradientProperties(ts, attributes.spreadMethod(), attributes.gradientTransform(), attributes.boundingBoxMode()); + + FloatPoint focalPoint; + FloatPoint centerPoint; + float radius; + radialGradientElement->calculateFocalCenterPointsAndRadius(attributes, focalPoint, centerPoint, radius); + + ts << " [center=" << centerPoint << "] [focal=" << focalPoint << "] [radius=" << radius << "]\n"; + } else + ts << "\n"; + writeChildren(ts, object, indent); +} + +void writeSVGContainer(TextStream& ts, const RenderObject& container, int indent) +{ + // Currently RenderSVGResourceFilterPrimitive has no meaningful output. + if (container.isSVGResourceFilterPrimitive()) + return; + writeStandardPrefix(ts, container, indent); + writePositionAndStyle(ts, container); + ts << "\n"; + writeResources(ts, container, indent); + writeChildren(ts, container, indent); +} + +void write(TextStream& ts, const RenderSVGRoot& root, int indent) +{ + writeStandardPrefix(ts, root, indent); + ts << root << "\n"; + writeChildren(ts, root, indent); +} + +void writeSVGText(TextStream& ts, const RenderBlock& text, int indent) +{ + writeStandardPrefix(ts, text, indent); + writeRenderSVGTextBox(ts, text); + ts << "\n"; + writeResources(ts, text, indent); + writeChildren(ts, text, indent); +} + +void writeSVGInlineText(TextStream& ts, const RenderText& text, int indent) +{ + writeStandardPrefix(ts, text, indent); + + // Why not just linesBoundingBox()? + ts << " " << FloatRect(text.firstRunOrigin(), text.linesBoundingBox().size()) << "\n"; + writeResources(ts, text, indent); + writeSVGInlineTextBoxes(ts, text, indent); +} + +void writeSVGImage(TextStream& ts, const RenderSVGImage& image, int indent) +{ + writeStandardPrefix(ts, image, indent); + writePositionAndStyle(ts, image); + ts << "\n"; + writeResources(ts, image, indent); +} + +void write(TextStream& ts, const RenderSVGPath& path, int indent) +{ + writeStandardPrefix(ts, path, indent); + ts << path << "\n"; + writeResources(ts, path, indent); +} + +void writeSVGGradientStop(TextStream& ts, const RenderSVGGradientStop& stop, int indent) +{ + writeStandardPrefix(ts, stop, indent); + + SVGStopElement* stopElement = static_cast<SVGStopElement*>(stop.node()); + ASSERT(stopElement); + + RenderStyle* style = stop.style(); + if (!style) + return; + + ts << " [offset=" << stopElement->offset() << "] [color=" << stopElement->stopColorIncludingOpacity() << "]\n"; +} + +void writeResources(TextStream& ts, const RenderObject& object, int indent) +{ + const RenderStyle* style = object.style(); + const SVGRenderStyle* svgStyle = style->svgStyle(); + + // FIXME: We want to use SVGResourcesCache to determine which resources are present, instead of quering the resource <-> id cache. + // For now leave the DRT output as is, but later on we should change this so cycles are properly ignored in the DRT output. + RenderObject& renderer = const_cast<RenderObject&>(object); + if (!svgStyle->maskerResource().isEmpty()) { + if (RenderSVGResourceMasker* masker = getRenderSVGResourceById<RenderSVGResourceMasker>(object.document(), svgStyle->maskerResource())) { + writeIndent(ts, indent); + ts << " "; + writeNameAndQuotedValue(ts, "masker", svgStyle->maskerResource()); + ts << " "; + writeStandardPrefix(ts, *masker, 0); + ts << " " << masker->resourceBoundingBox(&renderer) << "\n"; + } + } + if (!svgStyle->clipperResource().isEmpty()) { + if (RenderSVGResourceClipper* clipper = getRenderSVGResourceById<RenderSVGResourceClipper>(object.document(), svgStyle->clipperResource())) { + writeIndent(ts, indent); + ts << " "; + writeNameAndQuotedValue(ts, "clipPath", svgStyle->clipperResource()); + ts << " "; + writeStandardPrefix(ts, *clipper, 0); + ts << " " << clipper->resourceBoundingBox(&renderer) << "\n"; + } + } +#if ENABLE(FILTERS) + if (!svgStyle->filterResource().isEmpty()) { + if (RenderSVGResourceFilter* filter = getRenderSVGResourceById<RenderSVGResourceFilter>(object.document(), svgStyle->filterResource())) { + writeIndent(ts, indent); + ts << " "; + writeNameAndQuotedValue(ts, "filter", svgStyle->filterResource()); + ts << " "; + writeStandardPrefix(ts, *filter, 0); + ts << " " << filter->resourceBoundingBox(&renderer) << "\n"; + } + } +#endif +} + +} // namespace WebCore + +#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.h b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.h new file mode 100644 index 0000000..ce07a5c --- /dev/null +++ b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2004, 2005, 2009 Apple Inc. All rights reserved. + * + * 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. + */ + +#ifndef SVGRenderTreeAsText_h +#define SVGRenderTreeAsText_h + +#if ENABLE(SVG) + +#include "TextStream.h" + +namespace WebCore { + +class Color; +class FloatRect; +class FloatSize; +class Node; +class RenderBlock; +class RenderImage; +class RenderObject; +class RenderSVGGradientStop; +class RenderSVGImage; +class RenderSVGPath; +class RenderSVGRoot; +class RenderText; +class AffineTransform; +class SVGUnitTypes; + +// functions used by the main RenderTreeAsText code +void write(TextStream&, const RenderSVGPath&, int indent); +void write(TextStream&, const RenderSVGRoot&, int indent); +void writeSVGGradientStop(TextStream&, const RenderSVGGradientStop&, int indent); +void writeSVGResourceContainer(TextStream&, const RenderObject&, int indent); +void writeSVGContainer(TextStream&, const RenderObject&, int indent); +void writeSVGImage(TextStream&, const RenderSVGImage&, int indent); +void writeSVGInlineText(TextStream&, const RenderText&, int indent); +void writeSVGText(TextStream&, const RenderBlock&, int indent); +void writeResources(TextStream&, const RenderObject&, int indent); + +// helper operators defined used in various classes to dump the render tree. +TextStream& operator<<(TextStream&, const AffineTransform&); +TextStream& operator<<(TextStream&, const Color&); +TextStream& operator<<(TextStream&, const FloatRect&); + +// helper operators specific to dumping the render tree. these are used in various classes to dump the render tree +// these could be defined in separate namespace to avoid matching these generic signatures unintentionally. + +template<typename Item> +TextStream& operator<<(TextStream& ts, const Vector<Item*>& v) +{ + ts << "["; + + for (unsigned i = 0; i < v.size(); i++) { + ts << *v[i]; + if (i < v.size() - 1) + ts << ", "; + } + + ts << "]"; + return ts; +} + +template<typename Pointer> +TextStream& operator<<(TextStream& ts, Pointer* t) +{ + ts << reinterpret_cast<intptr_t>(t); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(SVG) + +#endif // SVGRenderTreeAsText_h diff --git a/Source/WebCore/rendering/svg/SVGResources.cpp b/Source/WebCore/rendering/svg/SVGResources.cpp new file mode 100644 index 0000000..9a2c999 --- /dev/null +++ b/Source/WebCore/rendering/svg/SVGResources.cpp @@ -0,0 +1,684 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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. + */ + +#include "config.h" +#include "SVGResources.h" + +#if ENABLE(SVG) +#include "RenderSVGResourceClipper.h" +#include "RenderSVGResourceFilter.h" +#include "RenderSVGResourceMarker.h" +#include "RenderSVGResourceMasker.h" +#include "SVGFilterElement.h" +#include "SVGGradientElement.h" +#include "SVGNames.h" +#include "SVGPaint.h" +#include "SVGPatternElement.h" +#include "SVGRenderStyle.h" +#include "SVGURIReference.h" + +namespace WebCore { + +SVGResources::SVGResources() + : m_clipperFilterMaskerData(0) + , m_markerData(0) + , m_fillStrokeData(0) + , m_linkedResource(0) +{ +} + +static HashSet<AtomicStringImpl*>& clipperFilterMaskerTags() +{ + DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, s_tagList, ()); + if (s_tagList.isEmpty()) { + // "container elements": http://www.w3.org/TR/SVG11/intro.html#TermContainerElement + // "graphics elements" : http://www.w3.org/TR/SVG11/intro.html#TermGraphicsElement + s_tagList.add(SVGNames::aTag.localName().impl()); + s_tagList.add(SVGNames::circleTag.localName().impl()); + s_tagList.add(SVGNames::ellipseTag.localName().impl()); + s_tagList.add(SVGNames::glyphTag.localName().impl()); + s_tagList.add(SVGNames::gTag.localName().impl()); + s_tagList.add(SVGNames::imageTag.localName().impl()); + s_tagList.add(SVGNames::lineTag.localName().impl()); + s_tagList.add(SVGNames::markerTag.localName().impl()); + s_tagList.add(SVGNames::maskTag.localName().impl()); + s_tagList.add(SVGNames::missing_glyphTag.localName().impl()); + s_tagList.add(SVGNames::pathTag.localName().impl()); + s_tagList.add(SVGNames::polygonTag.localName().impl()); + s_tagList.add(SVGNames::polylineTag.localName().impl()); + s_tagList.add(SVGNames::rectTag.localName().impl()); + s_tagList.add(SVGNames::svgTag.localName().impl()); + s_tagList.add(SVGNames::textTag.localName().impl()); + s_tagList.add(SVGNames::useTag.localName().impl()); + + // Not listed in the definitions is the clipPath element, the SVG spec says though: + // The "clipPath" element or any of its children can specify property "clip-path". + // So we have to add clipPathTag here, otherwhise clip-path on clipPath will fail. + // (Already mailed SVG WG, waiting for a solution) + s_tagList.add(SVGNames::clipPathTag.localName().impl()); + + // Not listed in the definitions are the text content elements, though filter/clipper/masker on tspan/text/.. is allowed. + // (Already mailed SVG WG, waiting for a solution) + s_tagList.add(SVGNames::altGlyphTag.localName().impl()); + s_tagList.add(SVGNames::textPathTag.localName().impl()); + s_tagList.add(SVGNames::trefTag.localName().impl()); + s_tagList.add(SVGNames::tspanTag.localName().impl()); + + // Elements that we ignore, as it doesn't make any sense. + // defs, pattern, switch (FIXME: Mail SVG WG about these) + // symbol (is converted to a svg element, when referenced by use, we can safely ignore it.) + } + + return s_tagList; +} + +static HashSet<AtomicStringImpl*>& markerTags() +{ + DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, s_tagList, ()); + if (s_tagList.isEmpty()) { + s_tagList.add(SVGNames::lineTag.localName().impl()); + s_tagList.add(SVGNames::pathTag.localName().impl()); + s_tagList.add(SVGNames::polygonTag.localName().impl()); + s_tagList.add(SVGNames::polylineTag.localName().impl()); + } + + return s_tagList; +} + +static HashSet<AtomicStringImpl*>& fillAndStrokeTags() +{ + DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, s_tagList, ()); + if (s_tagList.isEmpty()) { + s_tagList.add(SVGNames::altGlyphTag.localName().impl()); + s_tagList.add(SVGNames::circleTag.localName().impl()); + s_tagList.add(SVGNames::ellipseTag.localName().impl()); + s_tagList.add(SVGNames::lineTag.localName().impl()); + s_tagList.add(SVGNames::pathTag.localName().impl()); + s_tagList.add(SVGNames::polygonTag.localName().impl()); + s_tagList.add(SVGNames::polylineTag.localName().impl()); + s_tagList.add(SVGNames::rectTag.localName().impl()); + s_tagList.add(SVGNames::textTag.localName().impl()); + s_tagList.add(SVGNames::textPathTag.localName().impl()); + s_tagList.add(SVGNames::trefTag.localName().impl()); + s_tagList.add(SVGNames::tspanTag.localName().impl()); + } + + return s_tagList; +} + +static HashSet<AtomicStringImpl*>& chainableResourceTags() +{ + DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, s_tagList, ()); + if (s_tagList.isEmpty()) { + s_tagList.add(SVGNames::linearGradientTag.localName().impl()); + s_tagList.add(SVGNames::filterTag.localName().impl()); + s_tagList.add(SVGNames::patternTag.localName().impl()); + s_tagList.add(SVGNames::radialGradientTag.localName().impl()); + } + + return s_tagList; +} + +static inline String targetReferenceFromResource(SVGElement* element) +{ + String target; + if (element->hasTagName(SVGNames::patternTag)) + target = static_cast<SVGPatternElement*>(element)->href(); + else if (element->hasTagName(SVGNames::linearGradientTag) || element->hasTagName(SVGNames::radialGradientTag)) + target = static_cast<SVGGradientElement*>(element)->href(); +#if ENABLE(FILTERS) + else if (element->hasTagName(SVGNames::filterTag)) + target = static_cast<SVGFilterElement*>(element)->href(); +#endif + else + ASSERT_NOT_REACHED(); + + return SVGURIReference::getTarget(target); +} + +static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document* document, SVGPaint* paint, AtomicString& id, bool& hasPendingResource) +{ + ASSERT(paint); + + SVGPaint::SVGPaintType paintType = paint->paintType(); + if (paintType != SVGPaint::SVG_PAINTTYPE_URI && paintType != SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR) + return 0; + + id = SVGURIReference::getTarget(paint->uri()); + RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id); + if (!container) { + hasPendingResource = true; + return 0; + } + + RenderSVGResourceType resourceType = container->resourceType(); + if (resourceType != PatternResourceType && resourceType != LinearGradientResourceType && resourceType != RadialGradientResourceType) + return 0; + + return container; +} + +static inline void registerPendingResource(SVGDocumentExtensions* extensions, const AtomicString& id, SVGElement* element) +{ + ASSERT(element); + if (!element->isStyled()) + return; + + extensions->addPendingResource(id, static_cast<SVGStyledElement*>(element)); +} + +bool SVGResources::buildCachedResources(const RenderObject* object, const SVGRenderStyle* style) +{ + ASSERT(object); + ASSERT(style); + + Node* node = object->node(); + ASSERT(node); + ASSERT(node->isSVGElement()); + + SVGElement* element = static_cast<SVGElement*>(node); + if (!element) + return false; + + Document* document = object->document(); + ASSERT(document); + + SVGDocumentExtensions* extensions = document->accessSVGExtensions(); + ASSERT(extensions); + + AtomicStringImpl* tagNameImpl = element->tagQName().localName().impl(); + if (!tagNameImpl) + return false; + + bool foundResources = false; + if (clipperFilterMaskerTags().contains(tagNameImpl)) { + if (style->hasClipper()) { + AtomicString id(style->clipperResource()); + if (setClipper(getRenderSVGResourceById<RenderSVGResourceClipper>(document, id))) + foundResources = true; + else + registerPendingResource(extensions, id, element); + } + +#if ENABLE(FILTERS) + if (style->hasFilter()) { + AtomicString id(style->filterResource()); + if (setFilter(getRenderSVGResourceById<RenderSVGResourceFilter>(document, id))) + foundResources = true; + else + registerPendingResource(extensions, id, element); + } +#endif + + if (style->hasMasker()) { + AtomicString id(style->maskerResource()); + if (setMasker(getRenderSVGResourceById<RenderSVGResourceMasker>(document, id))) + foundResources = true; + else + registerPendingResource(extensions, id, element); + } + } + + if (markerTags().contains(tagNameImpl) && style->hasMarkers()) { + AtomicString markerStartId(style->markerStartResource()); + if (setMarkerStart(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerStartId))) + foundResources = true; + else + registerPendingResource(extensions, markerStartId, element); + + AtomicString markerMidId(style->markerMidResource()); + if (setMarkerMid(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerMidId))) + foundResources = true; + else + registerPendingResource(extensions, markerMidId, element); + + AtomicString markerEndId(style->markerEndResource()); + if (setMarkerEnd(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerEndId))) + foundResources = true; + else + registerPendingResource(extensions, markerEndId, element); + } + + if (fillAndStrokeTags().contains(tagNameImpl)) { + if (style->hasFill()) { + bool hasPendingResource = false; + AtomicString id; + if (setFill(paintingResourceFromSVGPaint(document, style->fillPaint(), id, hasPendingResource))) + foundResources = true; + else if (hasPendingResource) + registerPendingResource(extensions, id, element); + } + + if (style->hasStroke()) { + bool hasPendingResource = false; + AtomicString id; + if (setStroke(paintingResourceFromSVGPaint(document, style->strokePaint(), id, hasPendingResource))) + foundResources = true; + else if (hasPendingResource) + registerPendingResource(extensions, id, element); + } + } + + if (chainableResourceTags().contains(tagNameImpl)) { + AtomicString id(targetReferenceFromResource(element)); + if (setLinkedResource(getRenderSVGResourceContainerById(document, id))) + foundResources = true; + else + registerPendingResource(extensions, id, element); + } + + return foundResources; +} + +void SVGResources::removeClientFromCache(RenderObject* object, bool markForInvalidation) const +{ + if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource) + return; + + if (m_linkedResource) { + ASSERT(!m_clipperFilterMaskerData); + ASSERT(!m_markerData); + ASSERT(!m_fillStrokeData); + m_linkedResource->removeClientFromCache(object, markForInvalidation); + return; + } + + if (m_clipperFilterMaskerData) { + if (m_clipperFilterMaskerData->clipper) + m_clipperFilterMaskerData->clipper->removeClientFromCache(object, markForInvalidation); +#if ENABLE(FILTERS) + if (m_clipperFilterMaskerData->filter) + m_clipperFilterMaskerData->filter->removeClientFromCache(object, markForInvalidation); +#endif + if (m_clipperFilterMaskerData->masker) + m_clipperFilterMaskerData->masker->removeClientFromCache(object, markForInvalidation); + } + + if (m_markerData) { + if (m_markerData->markerStart) + m_markerData->markerStart->removeClientFromCache(object, markForInvalidation); + if (m_markerData->markerMid) + m_markerData->markerMid->removeClientFromCache(object, markForInvalidation); + if (m_markerData->markerEnd) + m_markerData->markerEnd->removeClientFromCache(object, markForInvalidation); + } + + if (m_fillStrokeData) { + if (m_fillStrokeData->fill) + m_fillStrokeData->fill->removeClientFromCache(object, markForInvalidation); + if (m_fillStrokeData->stroke) + m_fillStrokeData->stroke->removeClientFromCache(object, markForInvalidation); + } +} + +void SVGResources::resourceDestroyed(RenderSVGResourceContainer* resource) +{ + ASSERT(resource); + if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource) + return; + + if (m_linkedResource == resource) { + ASSERT(!m_clipperFilterMaskerData); + ASSERT(!m_markerData); + ASSERT(!m_fillStrokeData); + m_linkedResource->removeAllClientsFromCache(); + m_linkedResource = 0; + return; + } + + switch (resource->resourceType()) { + case MaskerResourceType: + if (!m_clipperFilterMaskerData) + break; + if (m_clipperFilterMaskerData->masker == resource) { + m_clipperFilterMaskerData->masker->removeAllClientsFromCache(); + m_clipperFilterMaskerData->masker = 0; + } + break; + case MarkerResourceType: + if (!m_markerData) + break; + if (m_markerData->markerStart == resource) { + m_markerData->markerStart->removeAllClientsFromCache(); + m_markerData->markerStart = 0; + } + if (m_markerData->markerMid == resource) { + m_markerData->markerMid->removeAllClientsFromCache(); + m_markerData->markerMid = 0; + } + if (m_markerData->markerEnd == resource) { + m_markerData->markerEnd->removeAllClientsFromCache(); + m_markerData->markerEnd = 0; + } + break; + case PatternResourceType: + case LinearGradientResourceType: + case RadialGradientResourceType: + if (!m_fillStrokeData) + break; + if (m_fillStrokeData->fill == resource) { + m_fillStrokeData->fill->removeAllClientsFromCache(); + m_fillStrokeData->fill = 0; + } + if (m_fillStrokeData->stroke == resource) { + m_fillStrokeData->stroke->removeAllClientsFromCache(); + m_fillStrokeData->stroke = 0; + } + break; + case FilterResourceType: +#if ENABLE(FILTERS) + if (!m_clipperFilterMaskerData) + break; + if (m_clipperFilterMaskerData->filter == resource) { + m_clipperFilterMaskerData->filter->removeAllClientsFromCache(); + m_clipperFilterMaskerData->filter = 0; + } +#else + ASSERT_NOT_REACHED(); +#endif + break; + case ClipperResourceType: + if (!m_clipperFilterMaskerData) + break; + if (m_clipperFilterMaskerData->clipper == resource) { + m_clipperFilterMaskerData->clipper->removeAllClientsFromCache(); + m_clipperFilterMaskerData->clipper = 0; + } + break; + case SolidColorResourceType: + ASSERT_NOT_REACHED(); + } +} + +void SVGResources::buildSetOfResources(HashSet<RenderSVGResourceContainer*>& set) +{ + if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource) + return; + + if (m_linkedResource) { + ASSERT(!m_clipperFilterMaskerData); + ASSERT(!m_markerData); + ASSERT(!m_fillStrokeData); + set.add(m_linkedResource); + return; + } + + if (m_clipperFilterMaskerData) { + if (m_clipperFilterMaskerData->clipper) + set.add(m_clipperFilterMaskerData->clipper); +#if ENABLE(FILTERS) + if (m_clipperFilterMaskerData->filter) + set.add(m_clipperFilterMaskerData->filter); +#endif + if (m_clipperFilterMaskerData->masker) + set.add(m_clipperFilterMaskerData->masker); + } + + if (m_markerData) { + if (m_markerData->markerStart) + set.add(m_markerData->markerStart); + if (m_markerData->markerMid) + set.add(m_markerData->markerMid); + if (m_markerData->markerEnd) + set.add(m_markerData->markerEnd); + } + + if (m_fillStrokeData) { + if (m_fillStrokeData->fill) + set.add(m_fillStrokeData->fill); + if (m_fillStrokeData->stroke) + set.add(m_fillStrokeData->stroke); + } +} + +bool SVGResources::setClipper(RenderSVGResourceClipper* clipper) +{ + if (!clipper) + return false; + + ASSERT(clipper->resourceType() == ClipperResourceType); + + if (!m_clipperFilterMaskerData) + m_clipperFilterMaskerData = ClipperFilterMaskerData::create(); + + m_clipperFilterMaskerData->clipper = clipper; + return true; +} + +void SVGResources::resetClipper() +{ + ASSERT(m_clipperFilterMaskerData); + ASSERT(m_clipperFilterMaskerData->clipper); + m_clipperFilterMaskerData->clipper = 0; +} + +#if ENABLE(FILTERS) +bool SVGResources::setFilter(RenderSVGResourceFilter* filter) +{ + if (!filter) + return false; + + ASSERT(filter->resourceType() == FilterResourceType); + + if (!m_clipperFilterMaskerData) + m_clipperFilterMaskerData = ClipperFilterMaskerData::create(); + + m_clipperFilterMaskerData->filter = filter; + return true; +} + +void SVGResources::resetFilter() +{ + ASSERT(m_clipperFilterMaskerData); + ASSERT(m_clipperFilterMaskerData->filter); + m_clipperFilterMaskerData->filter = 0; +} +#endif + +bool SVGResources::setMarkerStart(RenderSVGResourceMarker* markerStart) +{ + if (!markerStart) + return false; + + ASSERT(markerStart->resourceType() == MarkerResourceType); + + if (!m_markerData) + m_markerData = MarkerData::create(); + + m_markerData->markerStart = markerStart; + return true; +} + +void SVGResources::resetMarkerStart() +{ + ASSERT(m_markerData); + ASSERT(m_markerData->markerStart); + m_markerData->markerStart = 0; +} + +bool SVGResources::setMarkerMid(RenderSVGResourceMarker* markerMid) +{ + if (!markerMid) + return false; + + ASSERT(markerMid->resourceType() == MarkerResourceType); + + if (!m_markerData) + m_markerData = MarkerData::create(); + + m_markerData->markerMid = markerMid; + return true; +} + +void SVGResources::resetMarkerMid() +{ + ASSERT(m_markerData); + ASSERT(m_markerData->markerMid); + m_markerData->markerMid = 0; +} + +bool SVGResources::setMarkerEnd(RenderSVGResourceMarker* markerEnd) +{ + if (!markerEnd) + return false; + + ASSERT(markerEnd->resourceType() == MarkerResourceType); + + if (!m_markerData) + m_markerData = MarkerData::create(); + + m_markerData->markerEnd = markerEnd; + return true; +} + +void SVGResources::resetMarkerEnd() +{ + ASSERT(m_markerData); + ASSERT(m_markerData->markerEnd); + m_markerData->markerEnd = 0; +} + +bool SVGResources::setMasker(RenderSVGResourceMasker* masker) +{ + if (!masker) + return false; + + ASSERT(masker->resourceType() == MaskerResourceType); + + if (!m_clipperFilterMaskerData) + m_clipperFilterMaskerData = ClipperFilterMaskerData::create(); + + m_clipperFilterMaskerData->masker = masker; + return true; +} + +void SVGResources::resetMasker() +{ + ASSERT(m_clipperFilterMaskerData); + ASSERT(m_clipperFilterMaskerData->masker); + m_clipperFilterMaskerData->masker = 0; +} + +bool SVGResources::setFill(RenderSVGResourceContainer* fill) +{ + if (!fill) + return false; + + ASSERT(fill->resourceType() == PatternResourceType + || fill->resourceType() == LinearGradientResourceType + || fill->resourceType() == RadialGradientResourceType); + + if (!m_fillStrokeData) + m_fillStrokeData = FillStrokeData::create(); + + m_fillStrokeData->fill = fill; + return true; +} + +void SVGResources::resetFill() +{ + ASSERT(m_fillStrokeData); + ASSERT(m_fillStrokeData->fill); + m_fillStrokeData->fill = 0; +} + +bool SVGResources::setStroke(RenderSVGResourceContainer* stroke) +{ + if (!stroke) + return false; + + ASSERT(stroke->resourceType() == PatternResourceType + || stroke->resourceType() == LinearGradientResourceType + || stroke->resourceType() == RadialGradientResourceType); + + if (!m_fillStrokeData) + m_fillStrokeData = FillStrokeData::create(); + + m_fillStrokeData->stroke = stroke; + return true; +} + +void SVGResources::resetStroke() +{ + ASSERT(m_fillStrokeData); + ASSERT(m_fillStrokeData->stroke); + m_fillStrokeData->stroke = 0; +} + +bool SVGResources::setLinkedResource(RenderSVGResourceContainer* linkedResource) +{ + if (!linkedResource) + return false; + + m_linkedResource = linkedResource; + return true; +} + +void SVGResources::resetLinkedResource() +{ + ASSERT(m_linkedResource); + m_linkedResource = 0; +} + +#ifndef NDEBUG +void SVGResources::dump(const RenderObject* object) +{ + ASSERT(object); + ASSERT(object->node()); + + fprintf(stderr, "-> this=%p, SVGResources(renderer=%p, node=%p)\n", this, object, object->node()); + fprintf(stderr, " | DOM Tree:\n"); + object->node()->showTreeForThis(); + + fprintf(stderr, "\n | List of resources:\n"); + if (m_clipperFilterMaskerData) { + if (RenderSVGResourceClipper* clipper = m_clipperFilterMaskerData->clipper) + fprintf(stderr, " |-> Clipper : %p (node=%p)\n", clipper, clipper->node()); +#if ENABLE(FILTERS) + if (RenderSVGResourceFilter* filter = m_clipperFilterMaskerData->filter) + fprintf(stderr, " |-> Filter : %p (node=%p)\n", filter, filter->node()); +#endif + if (RenderSVGResourceMasker* masker = m_clipperFilterMaskerData->masker) + fprintf(stderr, " |-> Masker : %p (node=%p)\n", masker, masker->node()); + } + + if (m_markerData) { + if (RenderSVGResourceMarker* markerStart = m_markerData->markerStart) + fprintf(stderr, " |-> MarkerStart: %p (node=%p)\n", markerStart, markerStart->node()); + if (RenderSVGResourceMarker* markerMid = m_markerData->markerMid) + fprintf(stderr, " |-> MarkerMid : %p (node=%p)\n", markerMid, markerMid->node()); + if (RenderSVGResourceMarker* markerEnd = m_markerData->markerEnd) + fprintf(stderr, " |-> MarkerEnd : %p (node=%p)\n", markerEnd, markerEnd->node()); + } + + if (m_fillStrokeData) { + if (RenderSVGResourceContainer* fill = m_fillStrokeData->fill) + fprintf(stderr, " |-> Fill : %p (node=%p)\n", fill, fill->node()); + if (RenderSVGResourceContainer* stroke = m_fillStrokeData->stroke) + fprintf(stderr, " |-> Stroke : %p (node=%p)\n", stroke, stroke->node()); + } + + if (m_linkedResource) + fprintf(stderr, " |-> xlink:href : %p (node=%p)\n", m_linkedResource, m_linkedResource->node()); +} +#endif + +} + +#endif diff --git a/Source/WebCore/rendering/svg/SVGResources.h b/Source/WebCore/rendering/svg/SVGResources.h new file mode 100644 index 0000000..dd328b8 --- /dev/null +++ b/Source/WebCore/rendering/svg/SVGResources.h @@ -0,0 +1,179 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 SVGResources_h +#define SVGResources_h + +#if ENABLE(SVG) +#include <wtf/HashSet.h> +#include <wtf/Noncopyable.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> + +namespace WebCore { + +class Document; +class RenderObject; +class RenderSVGResourceClipper; +class RenderSVGResourceContainer; +class RenderSVGResourceFilter; +class RenderSVGResourceMarker; +class RenderSVGResourceMasker; +class SVGRenderStyle; + +// Holds a set of resources associated with a RenderObject +class SVGResources : public Noncopyable { +public: + SVGResources(); + + bool buildCachedResources(const RenderObject*, const SVGRenderStyle*); + + // Ordinary resources + RenderSVGResourceClipper* clipper() const { return m_clipperFilterMaskerData ? m_clipperFilterMaskerData->clipper : 0; } +#if ENABLE(FILTERS) + RenderSVGResourceFilter* filter() const { return m_clipperFilterMaskerData ? m_clipperFilterMaskerData->filter : 0; } +#endif + RenderSVGResourceMarker* markerStart() const { return m_markerData ? m_markerData->markerStart : 0; } + RenderSVGResourceMarker* markerMid() const { return m_markerData ? m_markerData->markerMid : 0; } + RenderSVGResourceMarker* markerEnd() const { return m_markerData ? m_markerData->markerEnd : 0; } + RenderSVGResourceMasker* masker() const { return m_clipperFilterMaskerData ? m_clipperFilterMaskerData->masker : 0; } + + // Paint servers + RenderSVGResourceContainer* fill() const { return m_fillStrokeData ? m_fillStrokeData->fill : 0; } + RenderSVGResourceContainer* stroke() const { return m_fillStrokeData ? m_fillStrokeData->stroke : 0; } + + // Chainable resources - linked through xlink:href + RenderSVGResourceContainer* linkedResource() const { return m_linkedResource; } + + void buildSetOfResources(HashSet<RenderSVGResourceContainer*>&); + + // Methods operating on all cached resources + void removeClientFromCache(RenderObject*, bool markForInvalidation = true) const; + void resourceDestroyed(RenderSVGResourceContainer*); + +#ifndef NDEBUG + void dump(const RenderObject*); +#endif + +private: + friend class SVGResourcesCycleSolver; + + // Only used by SVGResourcesCache cycle detection logic + void resetClipper(); +#if ENABLE(FILTERS) + void resetFilter(); +#endif + void resetMarkerStart(); + void resetMarkerMid(); + void resetMarkerEnd(); + void resetMasker(); + void resetFill(); + void resetStroke(); + void resetLinkedResource(); + +private: + bool setClipper(RenderSVGResourceClipper*); +#if ENABLE(FILTERS) + bool setFilter(RenderSVGResourceFilter*); +#endif + bool setMarkerStart(RenderSVGResourceMarker*); + bool setMarkerMid(RenderSVGResourceMarker*); + bool setMarkerEnd(RenderSVGResourceMarker*); + bool setMasker(RenderSVGResourceMasker*); + bool setFill(RenderSVGResourceContainer*); + bool setStroke(RenderSVGResourceContainer*); + bool setLinkedResource(RenderSVGResourceContainer*); + + // From SVG 1.1 2nd Edition + // clipper: 'container elements' and 'graphics elements' + // filter: 'container elements' and 'graphics elements' + // masker: 'container elements' and 'graphics elements' + // -> a, circle, defs, ellipse, glyph, g, image, line, marker, mask, missing-glyph, path, pattern, polygon, polyline, rect, svg, switch, symbol, text, use + struct ClipperFilterMaskerData { + ClipperFilterMaskerData() + : clipper(0) +#if ENABLE(FILTERS) + , filter(0) +#endif + , masker(0) + { + } + + static PassOwnPtr<ClipperFilterMaskerData> create() + { + return new ClipperFilterMaskerData; + } + + RenderSVGResourceClipper* clipper; +#if ENABLE(FILTERS) + RenderSVGResourceFilter* filter; +#endif + RenderSVGResourceMasker* masker; + }; + + // From SVG 1.1 2nd Edition + // marker: line, path, polygon, polyline + struct MarkerData { + MarkerData() + : markerStart(0) + , markerMid(0) + , markerEnd(0) + { + } + + static PassOwnPtr<MarkerData> create() + { + return new MarkerData; + } + + RenderSVGResourceMarker* markerStart; + RenderSVGResourceMarker* markerMid; + RenderSVGResourceMarker* markerEnd; + }; + + // From SVG 1.1 2nd Edition + // fill: 'shapes' and 'text content elements' + // stroke: 'shapes' and 'text content elements' + // -> altGlyph, circle, ellipse, line, path, polygon, polyline, rect, text, textPath, tref, tspan + struct FillStrokeData { + FillStrokeData() + : fill(0) + , stroke(0) + { + } + + static PassOwnPtr<FillStrokeData> create() + { + return new FillStrokeData; + } + + RenderSVGResourceContainer* fill; + RenderSVGResourceContainer* stroke; + }; + + OwnPtr<ClipperFilterMaskerData> m_clipperFilterMaskerData; + OwnPtr<MarkerData> m_markerData; + OwnPtr<FillStrokeData> m_fillStrokeData; + RenderSVGResourceContainer* m_linkedResource; +}; + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/SVGResourcesCache.cpp b/Source/WebCore/rendering/svg/SVGResourcesCache.cpp new file mode 100644 index 0000000..886f76a --- /dev/null +++ b/Source/WebCore/rendering/svg/SVGResourcesCache.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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. + */ + +#include "config.h" +#include "SVGResourcesCache.h" + +#if ENABLE(SVG) +#include "RenderSVGResourceContainer.h" +#include "SVGDocumentExtensions.h" +#include "SVGResources.h" +#include "SVGResourcesCycleSolver.h" + +namespace WebCore { + +SVGResourcesCache::SVGResourcesCache() +{ +} + +SVGResourcesCache::~SVGResourcesCache() +{ + deleteAllValues(m_cache); +} + +void SVGResourcesCache::addResourcesFromRenderObject(RenderObject* object, const RenderStyle* style) +{ + ASSERT(object); + ASSERT(style); + ASSERT(!m_cache.contains(object)); + + const SVGRenderStyle* svgStyle = style->svgStyle(); + ASSERT(svgStyle); + + // Build a list of all resources associated with the passed RenderObject + SVGResources* resources = new SVGResources; + if (!resources->buildCachedResources(object, svgStyle)) { + delete resources; + return; + } + + // Put object in cache. + m_cache.set(object, resources); + + // Run cycle-detection _afterwards_, so self-references can be caught as well. + SVGResourcesCycleSolver solver(object, resources); + solver.resolveCycles(); + + // Walk resources and register the render object at each resources. + HashSet<RenderSVGResourceContainer*> resourceSet; + resources->buildSetOfResources(resourceSet); + + HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end(); + for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it) + (*it)->addClient(object); +} + +void SVGResourcesCache::removeResourcesFromRenderObject(RenderObject* object) +{ + if (!m_cache.contains(object)) + return; + + SVGResources* resources = m_cache.get(object); + + // Walk resources and register the render object at each resources. + HashSet<RenderSVGResourceContainer*> resourceSet; + resources->buildSetOfResources(resourceSet); + + HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end(); + for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it) + (*it)->removeClient(object); + + delete m_cache.take(object); +} + +static inline SVGResourcesCache* resourcesCacheFromRenderObject(RenderObject* renderer) +{ + Document* document = renderer->document(); + ASSERT(document); + + SVGDocumentExtensions* extensions = document->accessSVGExtensions(); + ASSERT(extensions); + + SVGResourcesCache* cache = extensions->resourcesCache(); + ASSERT(cache); + + return cache; +} + +SVGResources* SVGResourcesCache::cachedResourcesForRenderObject(RenderObject* renderer) +{ + ASSERT(renderer); + SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer); + if (!cache->m_cache.contains(renderer)) + return 0; + + return cache->m_cache.get(renderer); +} + +void SVGResourcesCache::clientLayoutChanged(RenderObject* object) +{ + SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object); + if (!resources) + return; + + resources->removeClientFromCache(object); +} + +void SVGResourcesCache::clientStyleChanged(RenderObject* renderer, StyleDifference diff, const RenderStyle* newStyle) +{ + ASSERT(renderer); + if (diff == StyleDifferenceEqual) + return; + + clientUpdatedFromElement(renderer, newStyle); + RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false); +} + +void SVGResourcesCache::clientUpdatedFromElement(RenderObject* renderer, const RenderStyle* newStyle) +{ + ASSERT(renderer); + ASSERT(renderer->parent()); + + SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer); + cache->removeResourcesFromRenderObject(renderer); + cache->addResourcesFromRenderObject(renderer, newStyle); +} + +void SVGResourcesCache::clientDestroyed(RenderObject* renderer) +{ + ASSERT(renderer); + SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer); + cache->removeResourcesFromRenderObject(renderer); +} + +void SVGResourcesCache::resourceDestroyed(RenderSVGResourceContainer* resource) +{ + ASSERT(resource); + SVGResourcesCache* cache = resourcesCacheFromRenderObject(resource); + + // The resource itself may have clients, that need to be notified. + cache->removeResourcesFromRenderObject(resource); + + HashMap<RenderObject*, SVGResources*>::iterator end = cache->m_cache.end(); + for (HashMap<RenderObject*, SVGResources*>::iterator it = cache->m_cache.begin(); it != end; ++it) + it->second->resourceDestroyed(resource); +} + +} + +#endif diff --git a/Source/WebCore/rendering/svg/SVGResourcesCache.h b/Source/WebCore/rendering/svg/SVGResourcesCache.h new file mode 100644 index 0000000..30eaeca --- /dev/null +++ b/Source/WebCore/rendering/svg/SVGResourcesCache.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 SVGResourcesCache_h +#define SVGResourcesCache_h + +#if ENABLE(SVG) +#include "RenderStyleConstants.h" +#include <wtf/HashMap.h> + +namespace WebCore { + +class RenderObject; +class RenderStyle; +class RenderSVGResourceContainer; +class SVGResources; + +class SVGResourcesCache : public Noncopyable { +public: + SVGResourcesCache(); + ~SVGResourcesCache(); + + void addResourcesFromRenderObject(RenderObject*, const RenderStyle*); + void removeResourcesFromRenderObject(RenderObject*); + static SVGResources* cachedResourcesForRenderObject(RenderObject*); + + // Called from all SVG renderers destroy() methods - except for RenderSVGResourceContainer. + static void clientDestroyed(RenderObject*); + + // Called from all SVG renderers layout() methods. + static void clientLayoutChanged(RenderObject*); + + // Called from all SVG renderers styleDidChange() methods. + static void clientStyleChanged(RenderObject*, StyleDifference, const RenderStyle* newStyle); + + // Called from all SVG renderers updateFromElement() methods. + static void clientUpdatedFromElement(RenderObject*, const RenderStyle* newStyle); + + // Called from RenderSVGResourceContainer::destroy(). + static void resourceDestroyed(RenderSVGResourceContainer*); + +private: + HashMap<RenderObject*, SVGResources*> m_cache; +}; + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.cpp b/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.cpp new file mode 100644 index 0000000..fa91e80 --- /dev/null +++ b/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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. + */ + +#include "config.h" +#include "SVGResourcesCycleSolver.h" + +// Set to a value > 0, to debug the resource cache. +#define DEBUG_CYCLE_DETECTION 0 + +#if ENABLE(SVG) +#include "RenderSVGResourceClipper.h" +#include "RenderSVGResourceFilter.h" +#include "RenderSVGResourceMarker.h" +#include "RenderSVGResourceMasker.h" +#include "SVGFilterElement.h" +#include "SVGGradientElement.h" +#include "SVGPatternElement.h" +#include "SVGResources.h" +#include "SVGResourcesCache.h" + +namespace WebCore { + +SVGResourcesCycleSolver::SVGResourcesCycleSolver(RenderObject* renderer, SVGResources* resources) + : m_renderer(renderer) + , m_resources(resources) +{ + ASSERT(m_renderer); + ASSERT(m_resources); +} + +SVGResourcesCycleSolver::~SVGResourcesCycleSolver() +{ +} + +bool SVGResourcesCycleSolver::resourceContainsCycles(RenderObject* renderer) const +{ + ASSERT(renderer); + + // First operate on the resources of the given renderer. + // <marker id="a"> <path marker-start="url(#b)"/> ... + // <marker id="b" marker-start="url(#a)"/> + if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer)) { + HashSet<RenderSVGResourceContainer*> resourceSet; + resources->buildSetOfResources(resourceSet); + + // Walk all resources and check wheter they reference any resource contained in the resources set. + HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end(); + for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it) { + if (m_allResources.contains(*it)) + return true; + } + } + + // Then operate on the child resources of the given renderer. + // <marker id="a"> <path marker-start="url(#b)"/> ... + // <marker id="b"> <path marker-start="url(#a)"/> ... + for (RenderObject* child = renderer->firstChild(); child; child = child->nextSibling()) { + SVGResources* childResources = SVGResourcesCache::cachedResourcesForRenderObject(child); + if (!childResources) + continue; + + // A child of the given 'resource' contains resources. + HashSet<RenderSVGResourceContainer*> childSet; + childResources->buildSetOfResources(childSet); + + // Walk all child resources and check wheter they reference any resource contained in the resources set. + HashSet<RenderSVGResourceContainer*>::iterator end = childSet.end(); + for (HashSet<RenderSVGResourceContainer*>::iterator it = childSet.begin(); it != end; ++it) { + if (m_allResources.contains(*it)) + return true; + } + + // Walk children recursively, stop immediately if we found a cycle + if (resourceContainsCycles(child)) + return true; + } + + return false; +} + +void SVGResourcesCycleSolver::resolveCycles() +{ + ASSERT(m_allResources.isEmpty()); + +#if DEBUG_CYCLE_DETECTION > 0 + fprintf(stderr, "\nBefore cycle detection:\n"); + m_resources->dump(m_renderer); +#endif + + // Stash all resources into a HashSet for the ease of traversing. + HashSet<RenderSVGResourceContainer*> localResources; + m_resources->buildSetOfResources(localResources); + ASSERT(!localResources.isEmpty()); + + // Add all parent resource containers to the HashSet. + HashSet<RenderSVGResourceContainer*> parentResources; + RenderObject* parent = m_renderer->parent(); + while (parent) { + if (parent->isSVGResourceContainer()) + parentResources.add(parent->toRenderSVGResourceContainer()); + parent = parent->parent(); + } + +#if DEBUG_CYCLE_DETECTION > 0 + fprintf(stderr, "\nDetecting wheter any resources references any of following objects:\n"); + { + fprintf(stderr, "Local resources:\n"); + HashSet<RenderSVGResourceContainer*>::iterator end = localResources.end(); + for (HashSet<RenderSVGResourceContainer*>::iterator it = localResources.begin(); it != end; ++it) + fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node()); + + fprintf(stderr, "Parent resources:\n"); + end = parentResources.end(); + for (HashSet<RenderSVGResourceContainer*>::iterator it = parentResources.begin(); it != end; ++it) + fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node()); + } +#endif + + // Build combined set of local and parent resources. + m_allResources = localResources; + HashSet<RenderSVGResourceContainer*>::iterator end = parentResources.end(); + for (HashSet<RenderSVGResourceContainer*>::iterator it = parentResources.begin(); it != end; ++it) + m_allResources.add(*it); + + // If we're a resource, add ourselves to the HashSet. + if (m_renderer->isSVGResourceContainer()) + m_allResources.add(m_renderer->toRenderSVGResourceContainer()); + + ASSERT(!m_allResources.isEmpty()); + + // The job of this function is to determine wheter any of the 'resources' associated with the given 'renderer' + // references us (or wheter any of its kids references us) -> that's a cycle, we need to find and break it. + end = localResources.end(); + for (HashSet<RenderSVGResourceContainer*>::iterator it = localResources.begin(); it != end; ++it) { + RenderSVGResourceContainer* resource = *it; + if (parentResources.contains(resource) || resourceContainsCycles(resource)) + breakCycle(resource); + } + +#if DEBUG_CYCLE_DETECTION > 0 + fprintf(stderr, "\nAfter cycle detection:\n"); + m_resources->dump(m_renderer); +#endif + + m_allResources.clear(); +} + +void SVGResourcesCycleSolver::breakCycle(RenderSVGResourceContainer* resourceLeadingToCycle) +{ + ASSERT(resourceLeadingToCycle); + if (resourceLeadingToCycle == m_resources->linkedResource()) { + m_resources->resetLinkedResource(); + return; + } + + switch (resourceLeadingToCycle->resourceType()) { + case MaskerResourceType: + ASSERT(resourceLeadingToCycle == m_resources->masker()); + m_resources->resetMasker(); + break; + case MarkerResourceType: + ASSERT(resourceLeadingToCycle == m_resources->markerStart() || resourceLeadingToCycle == m_resources->markerMid() || resourceLeadingToCycle == m_resources->markerEnd()); + if (m_resources->markerStart() == resourceLeadingToCycle) + m_resources->resetMarkerStart(); + if (m_resources->markerMid() == resourceLeadingToCycle) + m_resources->resetMarkerMid(); + if (m_resources->markerEnd() == resourceLeadingToCycle) + m_resources->resetMarkerEnd(); + break; + case PatternResourceType: + case LinearGradientResourceType: + case RadialGradientResourceType: + ASSERT(resourceLeadingToCycle == m_resources->fill() || resourceLeadingToCycle == m_resources->stroke()); + if (m_resources->fill() == resourceLeadingToCycle) + m_resources->resetFill(); + if (m_resources->stroke() == resourceLeadingToCycle) + m_resources->resetStroke(); + break; + case FilterResourceType: +#if ENABLE(FILTERS) + ASSERT(resourceLeadingToCycle == m_resources->filter()); + m_resources->resetFilter(); +#endif + break; + case ClipperResourceType: + ASSERT(resourceLeadingToCycle == m_resources->clipper()); + m_resources->resetClipper(); + break; + case SolidColorResourceType: + ASSERT_NOT_REACHED(); + break; + } +} + +} + +#endif diff --git a/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.h b/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.h new file mode 100644 index 0000000..0653304 --- /dev/null +++ b/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 SVGResourcesCycleSolver_h +#define SVGResourcesCycleSolver_h + +#if ENABLE(SVG) +#include <wtf/HashSet.h> + +namespace WebCore { + +class RenderObject; +class RenderSVGResourceContainer; +class SVGResources; + +class SVGResourcesCycleSolver : public Noncopyable { +public: + SVGResourcesCycleSolver(RenderObject*, SVGResources*); + ~SVGResourcesCycleSolver(); + + void resolveCycles(); + +private: + bool resourceContainsCycles(RenderObject*) const; + void breakCycle(RenderSVGResourceContainer*); + + RenderObject* m_renderer; + SVGResources* m_resources; + HashSet<RenderSVGResourceContainer*> m_allResources; +}; + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp b/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp index 49c76de..c2289d6 100644 --- a/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp +++ b/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp @@ -18,7 +18,6 @@ * 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. - * */ #include "config.h" diff --git a/Source/WebCore/rendering/svg/SVGRootInlineBox.h b/Source/WebCore/rendering/svg/SVGRootInlineBox.h index 418c289..2e073c9 100644 --- a/Source/WebCore/rendering/svg/SVGRootInlineBox.h +++ b/Source/WebCore/rendering/svg/SVGRootInlineBox.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> - * (C) 2006 Apple Computer Inc. - * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2006 Apple Computer Inc. + * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * Copyright (C) Research In Motion Limited 2010. All rights reserved. * * This library is free software; you can redistribute it and/or @@ -18,7 +18,6 @@ * 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 SVGRootInlineBox_h diff --git a/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp b/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp new file mode 100644 index 0000000..2d84c48 --- /dev/null +++ b/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "SVGShadowTreeElements.h" + +#include "Document.h" +#include "FloatSize.h" +#include "RenderObject.h" +#include "SVGNames.h" +#include "SVGUseElement.h" + +namespace WebCore { + +// SVGShadowTreeContainerElement + +SVGShadowTreeContainerElement::SVGShadowTreeContainerElement(Document* document) + : SVGGElement(SVGNames::gTag, document) +{ +} + +PassRefPtr<SVGShadowTreeContainerElement> SVGShadowTreeContainerElement::create(Document* document) +{ + return adoptRef(new SVGShadowTreeContainerElement(document)); +} + +FloatSize SVGShadowTreeContainerElement::containerTranslation() const +{ + return FloatSize(m_xOffset.value(this), m_yOffset.value(this)); +} + +// SVGShadowTreeRootElement + +inline SVGShadowTreeRootElement::SVGShadowTreeRootElement(Document* document, SVGUseElement* shadowParent) + : SVGShadowTreeContainerElement(document) +{ + setShadowHost(shadowParent); + setInDocument(); +} + +PassRefPtr<SVGShadowTreeRootElement> SVGShadowTreeRootElement::create(Document* document, SVGUseElement* shadowParent) +{ + return adoptRef(new SVGShadowTreeRootElement(document, shadowParent)); +} + +void SVGShadowTreeRootElement::attachElement(PassRefPtr<RenderStyle> style, RenderArena* arena) +{ + ASSERT(shadowHost()); + + // Create the renderer with the specified style + RenderObject* renderer = createRenderer(arena, style.get()); + if (renderer) { + setRenderer(renderer); + renderer->setStyle(style); + } + + // Set these explicitly since this normally happens during an attach() + setAttached(); + + // Add the renderer to the render tree + if (renderer) + shadowHost()->renderer()->addChild(renderer); +} + +void SVGShadowTreeRootElement::clearShadowHost() +{ + setShadowHost(0); +} + +} + +#endif diff --git a/Source/WebCore/rendering/svg/SVGShadowTreeElements.h b/Source/WebCore/rendering/svg/SVGShadowTreeElements.h new file mode 100644 index 0000000..3406f95 --- /dev/null +++ b/Source/WebCore/rendering/svg/SVGShadowTreeElements.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 SVGShadowTreeElements_h +#define SVGShadowTreeElements_h + +#if ENABLE(SVG) +#include "SVGGElement.h" +#include "SVGLength.h" + +namespace WebCore { + +class FloatSize; +class SVGUseElement; + +class SVGShadowTreeContainerElement : public SVGGElement { +public: + static PassRefPtr<SVGShadowTreeContainerElement> create(Document*); + + FloatSize containerTranslation() const; + void setContainerOffset(const SVGLength& x, const SVGLength& y) + { + m_xOffset = x; + m_yOffset = y; + } + +protected: + SVGShadowTreeContainerElement(Document*); + +private: + virtual bool isShadowTreeContainerElement() const { return true; } + + SVGLength m_xOffset; + SVGLength m_yOffset; +}; + +class SVGShadowTreeRootElement : public SVGShadowTreeContainerElement { +public: + static PassRefPtr<SVGShadowTreeRootElement> create(Document*, SVGUseElement* shadowParent); + + void attachElement(PassRefPtr<RenderStyle>, RenderArena*); + void clearShadowHost(); + +private: + SVGShadowTreeRootElement(Document*, SVGUseElement* shadowParent); +}; + +} + +#endif +#endif diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp index 7060ac6..3863322 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp +++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp @@ -154,8 +154,7 @@ float SVGTextLayoutEngineBaseline::calculateGlyphOrientationAngle(bool isVertica ASSERT(style); switch (isVerticalText ? style->glyphOrientationVertical() : style->glyphOrientationHorizontal()) { - case GO_AUTO: - { + case GO_AUTO: { // Spec: Fullwidth ideographic and fullwidth Latin text will be set with a glyph-orientation of 0-degrees. // Text which is not fullwidth will be set with a glyph-orientation of 90-degrees. unsigned int unicodeRange = findCharUnicodeRange(character); diff --git a/Source/WebCore/rendering/svg/SVGTextQuery.cpp b/Source/WebCore/rendering/svg/SVGTextQuery.cpp index fcc7924..42d511b 100644 --- a/Source/WebCore/rendering/svg/SVGTextQuery.cpp +++ b/Source/WebCore/rendering/svg/SVGTextQuery.cpp @@ -1,21 +1,21 @@ /* - Copyright (C) Research In Motion Limited 2010. All rights reserved. - - 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. -*/ + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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. + */ #include "config.h" #include "SVGTextQuery.h" diff --git a/Source/WebCore/rendering/svg/SVGTextQuery.h b/Source/WebCore/rendering/svg/SVGTextQuery.h index 9a671f4..331dd94 100644 --- a/Source/WebCore/rendering/svg/SVGTextQuery.h +++ b/Source/WebCore/rendering/svg/SVGTextQuery.h @@ -1,21 +1,21 @@ /* - Copyright (C) Research In Motion Limited 2010. All rights reserved. - - 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. -*/ + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * 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 SVGTextQuery_h #define SVGTextQuery_h |