1/* 2 * Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Rob Buis <buis@kde.org> 4 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 */ 21 22#include "config.h" 23 24#include "core/rendering/svg/RenderSVGResourceMarker.h" 25 26#include "core/rendering/PaintInfo.h" 27#include "core/rendering/svg/RenderSVGContainer.h" 28#include "core/rendering/svg/SVGRenderSupport.h" 29#include "platform/graphics/GraphicsContextStateSaver.h" 30 31#include "wtf/TemporaryChange.h" 32 33namespace WebCore { 34 35const RenderSVGResourceType RenderSVGResourceMarker::s_resourceType = MarkerResourceType; 36 37RenderSVGResourceMarker::RenderSVGResourceMarker(SVGMarkerElement* node) 38 : RenderSVGResourceContainer(node) 39{ 40} 41 42RenderSVGResourceMarker::~RenderSVGResourceMarker() 43{ 44} 45 46void RenderSVGResourceMarker::layout() 47{ 48 ASSERT(needsLayout()); 49 if (m_isInLayout) 50 return; 51 52 TemporaryChange<bool> inLayoutChange(m_isInLayout, true); 53 54 // RenderSVGHiddenContainer overwrites layout(). We need the 55 // layouting of RenderSVGContainer for calculating local 56 // transformations and repaint. 57 RenderSVGContainer::layout(); 58 59 clearInvalidationMask(); 60} 61 62void RenderSVGResourceMarker::removeAllClientsFromCache(bool markForInvalidation) 63{ 64 markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation); 65} 66 67void RenderSVGResourceMarker::removeClientFromCache(RenderObject* client, bool markForInvalidation) 68{ 69 ASSERT(client); 70 markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation); 71} 72 73void RenderSVGResourceMarker::applyViewportClip(PaintInfo& paintInfo) 74{ 75 if (SVGRenderSupport::isOverflowHidden(this)) 76 paintInfo.context->clip(m_viewport); 77} 78 79FloatRect RenderSVGResourceMarker::markerBoundaries(const AffineTransform& markerTransformation) const 80{ 81 FloatRect coordinates = RenderSVGContainer::paintInvalidationRectInLocalCoordinates(); 82 83 // Map repaint rect into parent coordinate space, in which the marker boundaries have to be evaluated 84 coordinates = localToParentTransform().mapRect(coordinates); 85 86 return markerTransformation.mapRect(coordinates); 87} 88 89const AffineTransform& RenderSVGResourceMarker::localToParentTransform() const 90{ 91 m_localToParentTransform = AffineTransform::translation(m_viewport.x(), m_viewport.y()) * viewportTransform(); 92 return m_localToParentTransform; 93 // If this class were ever given a localTransform(), then the above would read: 94 // return viewportTranslation * localTransform() * viewportTransform(); 95} 96 97FloatPoint RenderSVGResourceMarker::referencePoint() const 98{ 99 SVGMarkerElement* marker = toSVGMarkerElement(element()); 100 ASSERT(marker); 101 102 SVGLengthContext lengthContext(marker); 103 return FloatPoint(marker->refX()->currentValue()->value(lengthContext), marker->refY()->currentValue()->value(lengthContext)); 104} 105 106float RenderSVGResourceMarker::angle() const 107{ 108 SVGMarkerElement* marker = toSVGMarkerElement(element()); 109 ASSERT(marker); 110 111 float angle = -1; 112 if (marker->orientType()->currentValue()->enumValue() == SVGMarkerOrientAngle) 113 angle = marker->orientAngle()->currentValue()->value(); 114 115 return angle; 116} 117 118AffineTransform RenderSVGResourceMarker::markerTransformation(const FloatPoint& origin, float autoAngle, float strokeWidth) const 119{ 120 SVGMarkerElement* marker = toSVGMarkerElement(element()); 121 ASSERT(marker); 122 123 float markerAngle = angle(); 124 bool useStrokeWidth = marker->markerUnits()->currentValue()->enumValue() == SVGMarkerUnitsStrokeWidth; 125 126 AffineTransform transform; 127 transform.translate(origin.x(), origin.y()); 128 transform.rotate(markerAngle == -1 ? autoAngle : markerAngle); 129 transform = markerContentTransformation(transform, referencePoint(), useStrokeWidth ? strokeWidth : -1); 130 return transform; 131} 132 133void RenderSVGResourceMarker::draw(PaintInfo& paintInfo, const AffineTransform& transform) 134{ 135 clearInvalidationMask(); 136 137 // An empty viewBox disables rendering. 138 SVGMarkerElement* marker = toSVGMarkerElement(element()); 139 ASSERT(marker); 140 if (marker->hasAttribute(SVGNames::viewBoxAttr) && marker->viewBox()->currentValue()->isValid() && marker->viewBox()->currentValue()->value().isEmpty()) 141 return; 142 143 PaintInfo info(paintInfo); 144 GraphicsContextStateSaver stateSaver(*info.context, false); 145 if (!transform.isIdentity()) { 146 stateSaver.save(); 147 info.applyTransform(transform, false); 148 } 149 RenderSVGContainer::paint(info, IntPoint()); 150} 151 152AffineTransform RenderSVGResourceMarker::markerContentTransformation(const AffineTransform& contentTransformation, const FloatPoint& origin, float strokeWidth) const 153{ 154 // The 'origin' coordinate maps to SVGs refX/refY, given in coordinates relative to the viewport established by the marker 155 FloatPoint mappedOrigin = viewportTransform().mapPoint(origin); 156 157 AffineTransform transformation = contentTransformation; 158 if (strokeWidth != -1) 159 transformation.scaleNonUniform(strokeWidth, strokeWidth); 160 161 transformation.translate(-mappedOrigin.x(), -mappedOrigin.y()); 162 return transformation; 163} 164 165AffineTransform RenderSVGResourceMarker::viewportTransform() const 166{ 167 SVGMarkerElement* marker = toSVGMarkerElement(element()); 168 ASSERT(marker); 169 170 return marker->viewBoxToViewTransform(m_viewport.width(), m_viewport.height()); 171} 172 173void RenderSVGResourceMarker::calcViewport() 174{ 175 if (!selfNeedsLayout()) 176 return; 177 178 SVGMarkerElement* marker = toSVGMarkerElement(element()); 179 ASSERT(marker); 180 181 SVGLengthContext lengthContext(marker); 182 float w = marker->markerWidth()->currentValue()->value(lengthContext); 183 float h = marker->markerHeight()->currentValue()->value(lengthContext); 184 m_viewport = FloatRect(0, 0, w, h); 185} 186 187} 188