1 /* 2 Copyright (C) 2006 Alexander Kellett <lypanov (at) kde.org> 3 Copyright (C) 2006 Apple Computer, Inc. 4 Copyright (C) 2007 Nikolas Zimmermann <zimmermann (at) kde.org> 5 Copyright (C) 2007, 2008, 2009 Rob Buis <buis (at) kde.org> 6 Copyright (C) 2009, Google, Inc. 7 Copyright (C) 2009 Dirk Schulze <krit (at) webkit.org> 8 9 This library is free software; you can redistribute it and/or 10 modify it under the terms of the GNU Library General Public 11 License as published by the Free Software Foundation; either 12 version 2 of the License, or (at your option) any later version. 13 14 This library is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 Library General Public License for more details. 18 19 You should have received a copy of the GNU Library General Public License 20 along with this library; see the file COPYING.LIB. If not, write to 21 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 Boston, MA 02110-1301, USA. 23 */ 24 25 #include "config.h" 26 27 #if ENABLE(SVG) 28 #include "RenderSVGImage.h" 29 30 #include "Attr.h" 31 #include "FloatConversion.h" 32 #include "FloatQuad.h" 33 #include "GraphicsContext.h" 34 #include "PointerEventsHitRules.h" 35 #include "RenderLayer.h" 36 #include "SVGImageElement.h" 37 #include "SVGLength.h" 38 #include "SVGPreserveAspectRatio.h" 39 #include "SVGRenderSupport.h" 40 #include "SVGResourceClipper.h" 41 #include "SVGResourceFilter.h" 42 #include "SVGResourceMasker.h" 43 44 namespace WebCore { 45 46 RenderSVGImage::RenderSVGImage(SVGImageElement* impl) 47 : RenderImage(impl) 48 { 49 } 50 51 void RenderSVGImage::layout() 52 { 53 ASSERT(needsLayout()); 54 55 LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); 56 57 SVGImageElement* image = static_cast<SVGImageElement*>(node()); 58 m_localTransform = image->animatedLocalTransform(); 59 60 // minimum height 61 setHeight(errorOccurred() ? intrinsicSize().height() : 0); 62 63 calcWidth(); 64 calcHeight(); 65 66 m_localBounds = FloatRect(image->x().value(image), image->y().value(image), image->width().value(image), image->height().value(image)); 67 m_cachedLocalRepaintRect = FloatRect(); 68 69 repainter.repaintAfterLayout(); 70 71 setNeedsLayout(false); 72 } 73 74 void RenderSVGImage::paint(PaintInfo& paintInfo, int, int) 75 { 76 if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN) 77 return; 78 79 paintInfo.context->save(); 80 paintInfo.context->concatCTM(localToParentTransform()); 81 82 if (paintInfo.phase == PaintPhaseForeground) { 83 SVGResourceFilter* filter = 0; 84 85 PaintInfo savedInfo(paintInfo); 86 87 if (prepareToRenderSVGContent(this, paintInfo, m_localBounds, filter)) { 88 FloatRect destRect = m_localBounds; 89 FloatRect srcRect(0, 0, image()->width(), image()->height()); 90 91 SVGImageElement* imageElt = static_cast<SVGImageElement*>(node()); 92 if (imageElt->preserveAspectRatio().align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) 93 imageElt->preserveAspectRatio().transformRect(destRect, srcRect); 94 95 paintInfo.context->drawImage(image(), DeviceColorSpace, destRect, srcRect); 96 } 97 finishRenderSVGContent(this, paintInfo, filter, savedInfo.context); 98 } 99 100 if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth()) 101 paintOutline(paintInfo.context, 0, 0, width(), height(), style()); 102 103 paintInfo.context->restore(); 104 } 105 106 bool RenderSVGImage::nodeAtFloatPoint(const HitTestRequest&, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) 107 { 108 // We only draw in the forground phase, so we only hit-test then. 109 if (hitTestAction != HitTestForeground) 110 return false; 111 112 PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_IMAGE_HITTESTING, style()->pointerEvents()); 113 114 bool isVisible = (style()->visibility() == VISIBLE); 115 if (isVisible || !hitRules.requireVisible) { 116 FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); 117 118 if (hitRules.canHitFill) { 119 if (m_localBounds.contains(localPoint)) { 120 updateHitTestResult(result, roundedIntPoint(localPoint)); 121 return true; 122 } 123 } 124 } 125 126 return false; 127 } 128 129 bool RenderSVGImage::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction) 130 { 131 ASSERT_NOT_REACHED(); 132 return false; 133 } 134 135 FloatRect RenderSVGImage::objectBoundingBox() const 136 { 137 return m_localBounds; 138 } 139 140 FloatRect RenderSVGImage::repaintRectInLocalCoordinates() const 141 { 142 // If we already have a cached repaint rect, return that 143 if (!m_cachedLocalRepaintRect.isEmpty()) 144 return m_cachedLocalRepaintRect; 145 146 m_cachedLocalRepaintRect = m_localBounds; 147 148 // FIXME: We need to be careful here. We assume that there is no filter, 149 // clipper or masker if the rects are empty. 150 FloatRect rect = filterBoundingBoxForRenderer(this); 151 if (!rect.isEmpty()) 152 m_cachedLocalRepaintRect = rect; 153 154 rect = clipperBoundingBoxForRenderer(this); 155 if (!rect.isEmpty()) 156 m_cachedLocalRepaintRect.intersect(rect); 157 158 rect = maskerBoundingBoxForRenderer(this); 159 if (!rect.isEmpty()) 160 m_cachedLocalRepaintRect.intersect(rect); 161 162 style()->svgStyle()->inflateForShadow(m_cachedLocalRepaintRect); 163 164 return m_cachedLocalRepaintRect; 165 } 166 167 void RenderSVGImage::imageChanged(WrappedImagePtr image, const IntRect* rect) 168 { 169 RenderImage::imageChanged(image, rect); 170 repaint(); 171 } 172 173 IntRect RenderSVGImage::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) 174 { 175 return SVGRenderBase::clippedOverflowRectForRepaint(this, repaintContainer); 176 } 177 178 void RenderSVGImage::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed) 179 { 180 SVGRenderBase::computeRectForRepaint(this, repaintContainer, repaintRect, fixed); 181 } 182 183 void RenderSVGImage::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) const 184 { 185 SVGRenderBase::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState); 186 } 187 188 void RenderSVGImage::addFocusRingRects(Vector<IntRect>& rects, int, int) 189 { 190 // this is called from paint() after the localTransform has already been applied 191 IntRect contentRect = enclosingIntRect(repaintRectInLocalCoordinates()); 192 if (!contentRect.isEmpty()) 193 rects.append(contentRect); 194 } 195 196 void RenderSVGImage::absoluteRects(Vector<IntRect>& rects, int, int) 197 { 198 rects.append(absoluteClippedOverflowRect()); 199 } 200 201 void RenderSVGImage::absoluteQuads(Vector<FloatQuad>& quads) 202 { 203 quads.append(FloatRect(absoluteClippedOverflowRect())); 204 } 205 206 } 207 208 #endif // ENABLE(SVG) 209