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 #if ENABLE(SVG) 25 #include "RenderSVGResourceMarker.h" 26 27 #include "GraphicsContext.h" 28 #include "RenderSVGContainer.h" 29 #include "SVGElement.h" 30 #include "SVGMarkerElement.h" 31 #include "SVGRenderSupport.h" 32 #include "SVGStyledElement.h" 33 #include "SVGStyledTransformableElement.h" 34 35 namespace WebCore { 36 37 RenderSVGResourceType RenderSVGResourceMarker::s_resourceType = MarkerResourceType; 38 39 RenderSVGResourceMarker::RenderSVGResourceMarker(SVGMarkerElement* node) 40 : RenderSVGResourceContainer(node) 41 { 42 } 43 44 RenderSVGResourceMarker::~RenderSVGResourceMarker() 45 { 46 } 47 48 void RenderSVGResourceMarker::layout() 49 { 50 // Invalidate all resources if our layout changed. 51 if (m_everHadLayout && selfNeedsLayout()) 52 removeAllClientsFromCache(); 53 54 // RenderSVGHiddenContainer overwrites layout(). We need the 55 // layouting of RenderSVGContainer for calculating local 56 // transformations and repaint. 57 RenderSVGContainer::layout(); 58 } 59 60 void RenderSVGResourceMarker::removeAllClientsFromCache(bool markForInvalidation) 61 { 62 markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation); 63 } 64 65 void RenderSVGResourceMarker::removeClientFromCache(RenderObject* client, bool markForInvalidation) 66 { 67 ASSERT(client); 68 markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation); 69 } 70 71 void RenderSVGResourceMarker::applyViewportClip(PaintInfo& paintInfo) 72 { 73 if (SVGRenderSupport::isOverflowHidden(this)) 74 paintInfo.context->clip(m_viewport); 75 } 76 77 FloatRect RenderSVGResourceMarker::markerBoundaries(const AffineTransform& markerTransformation) const 78 { 79 FloatRect coordinates = RenderSVGContainer::repaintRectInLocalCoordinates(); 80 81 // Map repaint rect into parent coordinate space, in which the marker boundaries have to be evaluated 82 coordinates = localToParentTransform().mapRect(coordinates); 83 84 return markerTransformation.mapRect(coordinates); 85 } 86 87 const AffineTransform& RenderSVGResourceMarker::localToParentTransform() const 88 { 89 m_localToParentTransform = AffineTransform::translation(m_viewport.x(), m_viewport.y()) * viewportTransform(); 90 return m_localToParentTransform; 91 // If this class were ever given a localTransform(), then the above would read: 92 // return viewportTranslation * localTransform() * viewportTransform(); 93 } 94 95 FloatPoint RenderSVGResourceMarker::referencePoint() const 96 { 97 SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node()); 98 ASSERT(marker); 99 100 return FloatPoint(marker->refX().value(marker), marker->refY().value(marker)); 101 } 102 103 float RenderSVGResourceMarker::angle() const 104 { 105 SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node()); 106 ASSERT(marker); 107 108 float angle = -1; 109 if (marker->orientType() == SVGMarkerElement::SVG_MARKER_ORIENT_ANGLE) 110 angle = marker->orientAngle().value(); 111 112 return angle; 113 } 114 115 AffineTransform RenderSVGResourceMarker::markerTransformation(const FloatPoint& origin, float autoAngle, float strokeWidth) const 116 { 117 SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node()); 118 ASSERT(marker); 119 120 float markerAngle = angle(); 121 bool useStrokeWidth = (marker->markerUnits() == SVGMarkerElement::SVG_MARKERUNITS_STROKEWIDTH); 122 123 AffineTransform transform; 124 transform.translate(origin.x(), origin.y()); 125 transform.rotate(markerAngle == -1 ? autoAngle : markerAngle); 126 transform = markerContentTransformation(transform, referencePoint(), useStrokeWidth ? strokeWidth : -1); 127 return transform; 128 } 129 130 void RenderSVGResourceMarker::draw(PaintInfo& paintInfo, const AffineTransform& transform) 131 { 132 PaintInfo info(paintInfo); 133 info.context->save(); 134 info.applyTransform(transform); 135 RenderSVGContainer::paint(info, 0, 0); 136 info.context->restore(); 137 } 138 139 AffineTransform RenderSVGResourceMarker::markerContentTransformation(const AffineTransform& contentTransformation, const FloatPoint& origin, float strokeWidth) const 140 { 141 // The 'origin' coordinate maps to SVGs refX/refY, given in coordinates relative to the viewport established by the marker 142 FloatPoint mappedOrigin = viewportTransform().mapPoint(origin); 143 144 AffineTransform transformation = contentTransformation; 145 if (strokeWidth != -1) 146 transformation.scaleNonUniform(strokeWidth, strokeWidth); 147 148 transformation.translate(-mappedOrigin.x(), -mappedOrigin.y()); 149 return transformation; 150 } 151 152 AffineTransform RenderSVGResourceMarker::viewportTransform() const 153 { 154 SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node()); 155 ASSERT(marker); 156 157 return marker->viewBoxToViewTransform(m_viewport.width(), m_viewport.height()); 158 } 159 160 void RenderSVGResourceMarker::calcViewport() 161 { 162 if (!selfNeedsLayout()) 163 return; 164 165 SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node()); 166 ASSERT(marker); 167 168 float w = marker->markerWidth().value(marker); 169 float h = marker->markerHeight().value(marker); 170 m_viewport = FloatRect(0, 0, w, h); 171 } 172 173 } 174 175 #endif // ENABLE(SVG) 176