• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     Copyright (C) 2006 Alexander Kellett <lypanov@kde.org>
3     Copyright (C) 2006 Apple Computer, Inc.
4     Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
5     Copyright (C) 2007, 2008, 2009 Rob Buis <buis@kde.org>
6     Copyright (C) 2009, Google, Inc.
7 
8     This library is free software; you can redistribute it and/or
9     modify it under the terms of the GNU Library General Public
10     License as published by the Free Software Foundation; either
11     version 2 of the License, or (at your option) any later version.
12 
13     This library is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16     Library General Public License for more details.
17 
18     You should have received a copy of the GNU Library General Public License
19     along with this library; see the file COPYING.LIB.  If not, write to
20     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21     Boston, MA 02110-1301, USA.
22 */
23 
24 #include "config.h"
25 
26 #if ENABLE(SVG)
27 #include "RenderSVGImage.h"
28 
29 #include "Attr.h"
30 #include "FloatConversion.h"
31 #include "FloatQuad.h"
32 #include "GraphicsContext.h"
33 #include "PointerEventsHitRules.h"
34 #include "RenderLayer.h"
35 #include "SVGImageElement.h"
36 #include "SVGLength.h"
37 #include "SVGPreserveAspectRatio.h"
38 #include "SVGRenderSupport.h"
39 #include "SVGResourceClipper.h"
40 #include "SVGResourceFilter.h"
41 #include "SVGResourceMasker.h"
42 
43 namespace WebCore {
44 
RenderSVGImage(SVGImageElement * impl)45 RenderSVGImage::RenderSVGImage(SVGImageElement* impl)
46     : RenderImage(impl)
47 {
48 }
49 
adjustRectsForAspectRatio(FloatRect & destRect,FloatRect & srcRect,SVGPreserveAspectRatio * aspectRatio)50 void RenderSVGImage::adjustRectsForAspectRatio(FloatRect& destRect, FloatRect& srcRect, SVGPreserveAspectRatio* aspectRatio)
51 {
52     float origDestWidth = destRect.width();
53     float origDestHeight = destRect.height();
54     if (aspectRatio->meetOrSlice() == SVGPreserveAspectRatio::SVG_MEETORSLICE_MEET) {
55         float widthToHeightMultiplier = srcRect.height() / srcRect.width();
56         if (origDestHeight > (origDestWidth * widthToHeightMultiplier)) {
57             destRect.setHeight(origDestWidth * widthToHeightMultiplier);
58             switch (aspectRatio->align()) {
59                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID:
60                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
61                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
62                     destRect.setY(destRect.y() + origDestHeight / 2.0f - destRect.height() / 2.0f);
63                     break;
64                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX:
65                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
66                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
67                     destRect.setY(destRect.y() + origDestHeight - destRect.height());
68                     break;
69             }
70         }
71         if (origDestWidth > (origDestHeight / widthToHeightMultiplier)) {
72             destRect.setWidth(origDestHeight / widthToHeightMultiplier);
73             switch (aspectRatio->align()) {
74                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN:
75                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
76                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
77                     destRect.setX(destRect.x() + origDestWidth / 2.0f - destRect.width() / 2.0f);
78                     break;
79                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN:
80                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
81                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
82                     destRect.setX(destRect.x() + origDestWidth - destRect.width());
83                     break;
84             }
85         }
86     } else if (aspectRatio->meetOrSlice() == SVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE) {
87         float widthToHeightMultiplier = srcRect.height() / srcRect.width();
88         // if the destination height is less than the height of the image we'll be drawing
89         if (origDestHeight < (origDestWidth * widthToHeightMultiplier)) {
90             float destToSrcMultiplier = srcRect.width() / destRect.width();
91             srcRect.setHeight(destRect.height() * destToSrcMultiplier);
92             switch (aspectRatio->align()) {
93                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID:
94                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
95                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
96                     srcRect.setY(destRect.y() + image()->height() / 2.0f - srcRect.height() / 2.0f);
97                     break;
98                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX:
99                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
100                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
101                     srcRect.setY(destRect.y() + image()->height() - srcRect.height());
102                     break;
103             }
104         }
105         // if the destination width is less than the width of the image we'll be drawing
106         if (origDestWidth < (origDestHeight / widthToHeightMultiplier)) {
107             float destToSrcMultiplier = srcRect.height() / destRect.height();
108             srcRect.setWidth(destRect.width() * destToSrcMultiplier);
109             switch (aspectRatio->align()) {
110                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN:
111                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
112                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
113                     srcRect.setX(destRect.x() + image()->width() / 2.0f - srcRect.width() / 2.0f);
114                     break;
115                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN:
116                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
117                 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
118                     srcRect.setX(destRect.x() + image()->width() - srcRect.width());
119                     break;
120             }
121         }
122     }
123 }
124 
layout()125 void RenderSVGImage::layout()
126 {
127     ASSERT(needsLayout());
128 
129     LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
130 
131     SVGImageElement* image = static_cast<SVGImageElement*>(node());
132     m_localTransform = image->animatedLocalTransform();
133 
134     // minimum height
135     setHeight(errorOccurred() ? intrinsicSize().height() : 0);
136 
137     calcWidth();
138     calcHeight();
139 
140     m_localBounds = FloatRect(image->x().value(image), image->y().value(image), image->width().value(image), image->height().value(image));
141 
142     repainter.repaintAfterLayout();
143 
144     setNeedsLayout(false);
145 }
146 
paint(PaintInfo & paintInfo,int,int)147 void RenderSVGImage::paint(PaintInfo& paintInfo, int, int)
148 {
149     if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN)
150         return;
151 
152     paintInfo.context->save();
153     paintInfo.context->concatCTM(localToParentTransform());
154 
155     if (paintInfo.phase == PaintPhaseForeground) {
156         SVGResourceFilter* filter = 0;
157 
158         PaintInfo savedInfo(paintInfo);
159 
160         prepareToRenderSVGContent(this, paintInfo, m_localBounds, filter);
161 
162         FloatRect destRect = m_localBounds;
163         FloatRect srcRect(0, 0, image()->width(), image()->height());
164 
165         SVGImageElement* imageElt = static_cast<SVGImageElement*>(node());
166         if (imageElt->preserveAspectRatio()->align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE)
167             adjustRectsForAspectRatio(destRect, srcRect, imageElt->preserveAspectRatio());
168 
169         paintInfo.context->drawImage(image(), destRect, srcRect);
170         finishRenderSVGContent(this, paintInfo, filter, savedInfo.context);
171     }
172 
173     if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth())
174         paintOutline(paintInfo.context, 0, 0, width(), height(), style());
175 
176     paintInfo.context->restore();
177 }
178 
nodeAtFloatPoint(const HitTestRequest &,HitTestResult & result,const FloatPoint & pointInParent,HitTestAction hitTestAction)179 bool RenderSVGImage::nodeAtFloatPoint(const HitTestRequest&, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
180 {
181     // We only draw in the forground phase, so we only hit-test then.
182     if (hitTestAction != HitTestForeground)
183         return false;
184 
185     PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_IMAGE_HITTESTING, style()->pointerEvents());
186 
187     bool isVisible = (style()->visibility() == VISIBLE);
188     if (isVisible || !hitRules.requireVisible) {
189         FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent);
190 
191         if (hitRules.canHitFill) {
192             if (m_localBounds.contains(localPoint)) {
193                 updateHitTestResult(result, roundedIntPoint(localPoint));
194                 return true;
195             }
196         }
197     }
198 
199     return false;
200 }
201 
nodeAtPoint(const HitTestRequest &,HitTestResult &,int,int,int,int,HitTestAction)202 bool RenderSVGImage::nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int, HitTestAction)
203 {
204     ASSERT_NOT_REACHED();
205     return false;
206 }
207 
objectBoundingBox() const208 FloatRect RenderSVGImage::objectBoundingBox() const
209 {
210     return m_localBounds;
211 }
212 
repaintRectInLocalCoordinates() const213 FloatRect RenderSVGImage::repaintRectInLocalCoordinates() const
214 {
215     FloatRect repaintRect = m_localBounds;
216 
217     // Filters can paint outside the image content
218     repaintRect.unite(filterBoundingBoxForRenderer(this));
219 
220     return repaintRect;
221 }
222 
imageChanged(WrappedImagePtr image,const IntRect * rect)223 void RenderSVGImage::imageChanged(WrappedImagePtr image, const IntRect* rect)
224 {
225     RenderImage::imageChanged(image, rect);
226     repaint();
227 }
228 
clippedOverflowRectForRepaint(RenderBoxModelObject * repaintContainer)229 IntRect RenderSVGImage::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
230 {
231     return SVGRenderBase::clippedOverflowRectForRepaint(this, repaintContainer);
232 }
233 
computeRectForRepaint(RenderBoxModelObject * repaintContainer,IntRect & repaintRect,bool fixed)234 void RenderSVGImage::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& repaintRect, bool fixed)
235 {
236     SVGRenderBase::computeRectForRepaint(this, repaintContainer, repaintRect, fixed);
237 }
238 
mapLocalToContainer(RenderBoxModelObject * repaintContainer,bool fixed,bool useTransforms,TransformState & transformState) const239 void RenderSVGImage::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed , bool useTransforms, TransformState& transformState) const
240 {
241     SVGRenderBase::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState);
242 }
243 
addFocusRingRects(GraphicsContext * graphicsContext,int,int)244 void RenderSVGImage::addFocusRingRects(GraphicsContext* graphicsContext, int, int)
245 {
246     // this is called from paint() after the localTransform has already been applied
247     IntRect contentRect = enclosingIntRect(repaintRectInLocalCoordinates());
248     graphicsContext->addFocusRingRect(contentRect);
249 }
250 
absoluteRects(Vector<IntRect> & rects,int,int)251 void RenderSVGImage::absoluteRects(Vector<IntRect>& rects, int, int)
252 {
253     rects.append(absoluteClippedOverflowRect());
254 }
255 
absoluteQuads(Vector<FloatQuad> & quads)256 void RenderSVGImage::absoluteQuads(Vector<FloatQuad>& quads)
257 {
258     quads.append(FloatRect(absoluteClippedOverflowRect()));
259 }
260 
261 }
262 
263 #endif // ENABLE(SVG)
264