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 blink { 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 paint invalidation. 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 paint invalidation 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 info.applyTransform(transform, &stateSaver); 146 RenderSVGContainer::paint(info, IntPoint()); 147} 148 149AffineTransform RenderSVGResourceMarker::markerContentTransformation(const AffineTransform& contentTransformation, const FloatPoint& origin, float strokeWidth) const 150{ 151 // The 'origin' coordinate maps to SVGs refX/refY, given in coordinates relative to the viewport established by the marker 152 FloatPoint mappedOrigin = viewportTransform().mapPoint(origin); 153 154 AffineTransform transformation = contentTransformation; 155 if (strokeWidth != -1) 156 transformation.scaleNonUniform(strokeWidth, strokeWidth); 157 158 transformation.translate(-mappedOrigin.x(), -mappedOrigin.y()); 159 return transformation; 160} 161 162AffineTransform RenderSVGResourceMarker::viewportTransform() const 163{ 164 SVGMarkerElement* marker = toSVGMarkerElement(element()); 165 ASSERT(marker); 166 167 return marker->viewBoxToViewTransform(m_viewport.width(), m_viewport.height()); 168} 169 170void RenderSVGResourceMarker::calcViewport() 171{ 172 if (!selfNeedsLayout()) 173 return; 174 175 SVGMarkerElement* marker = toSVGMarkerElement(element()); 176 ASSERT(marker); 177 178 SVGLengthContext lengthContext(marker); 179 float w = marker->markerWidth()->currentValue()->value(lengthContext); 180 float h = marker->markerHeight()->currentValue()->value(lengthContext); 181 m_viewport = FloatRect(0, 0, w, h); 182} 183 184} 185