1 /* 2 * Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann (at) kde.org> 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Rob Buis <buis (at) 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 33 namespace WebCore { 34 35 const RenderSVGResourceType RenderSVGResourceMarker::s_resourceType = MarkerResourceType; 36 37 RenderSVGResourceMarker::RenderSVGResourceMarker(SVGMarkerElement* node) 38 : RenderSVGResourceContainer(node) 39 { 40 } 41 42 RenderSVGResourceMarker::~RenderSVGResourceMarker() 43 { 44 } 45 46 void 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 62 void RenderSVGResourceMarker::removeAllClientsFromCache(bool markForInvalidation) 63 { 64 markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation); 65 } 66 67 void RenderSVGResourceMarker::removeClientFromCache(RenderObject* client, bool markForInvalidation) 68 { 69 ASSERT(client); 70 markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation); 71 } 72 73 void RenderSVGResourceMarker::applyViewportClip(PaintInfo& paintInfo) 74 { 75 if (SVGRenderSupport::isOverflowHidden(this)) 76 paintInfo.context->clip(m_viewport); 77 } 78 79 FloatRect 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 89 const 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 97 FloatPoint 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 106 float 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 118 AffineTransform 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 133 void 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 152 AffineTransform 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 165 AffineTransform 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 173 void 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