1 /* 2 * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann (at) kde.org> 3 * Copyright (C) 2004, 2005 Rob Buis <buis (at) kde.org> 4 * Copyright (C) 2005 Eric Seidel <eric (at) webkit.org> 5 * Copyright (C) 2010 Dirk Schulze <krit (at) webkit.org> 6 * Copyright (C) 2013 Google Inc. All rights reserved. 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 #include "core/svg/graphics/filters/SVGFEImage.h" 27 28 #include "SkBitmapSource.h" 29 #include "SkPictureImageFilter.h" 30 #include "core/rendering/RenderObject.h" 31 #include "core/rendering/svg/SVGRenderingContext.h" 32 #include "core/svg/SVGElement.h" 33 #include "core/svg/SVGURIReference.h" 34 #include "platform/graphics/DisplayList.h" 35 #include "platform/graphics/GraphicsContext.h" 36 #include "platform/graphics/filters/Filter.h" 37 #include "platform/graphics/filters/SkiaImageFilterBuilder.h" 38 #include "platform/text/TextStream.h" 39 #include "platform/transforms/AffineTransform.h" 40 41 namespace WebCore { 42 43 FEImage::FEImage(Filter* filter, PassRefPtr<Image> image, PassRefPtr<SVGPreserveAspectRatio> preserveAspectRatio) 44 : FilterEffect(filter) 45 , m_image(image) 46 , m_treeScope(0) 47 , m_preserveAspectRatio(preserveAspectRatio) 48 { 49 } 50 51 FEImage::FEImage(Filter* filter, TreeScope& treeScope, const String& href, PassRefPtr<SVGPreserveAspectRatio> preserveAspectRatio) 52 : FilterEffect(filter) 53 , m_treeScope(&treeScope) 54 , m_href(href) 55 , m_preserveAspectRatio(preserveAspectRatio) 56 { 57 } 58 59 PassRefPtr<FEImage> FEImage::createWithImage(Filter* filter, PassRefPtr<Image> image, PassRefPtr<SVGPreserveAspectRatio> preserveAspectRatio) 60 { 61 return adoptRef(new FEImage(filter, image, preserveAspectRatio)); 62 } 63 64 PassRefPtr<FEImage> FEImage::createWithIRIReference(Filter* filter, TreeScope& treeScope, const String& href, PassRefPtr<SVGPreserveAspectRatio> preserveAspectRatio) 65 { 66 return adoptRef(new FEImage(filter, treeScope, href, preserveAspectRatio)); 67 } 68 69 static FloatRect getRendererRepaintRect(RenderObject* renderer) 70 { 71 return renderer->localToParentTransform().mapRect( 72 renderer->paintInvalidationRectInLocalCoordinates()); 73 } 74 75 FloatRect FEImage::determineAbsolutePaintRect(const FloatRect& originalRequestedRect) 76 { 77 RenderObject* renderer = referencedRenderer(); 78 if (!m_image && !renderer) 79 return FloatRect(); 80 81 FloatRect requestedRect = originalRequestedRect; 82 if (clipsToBounds()) 83 requestedRect.intersect(maxEffectRect()); 84 85 FloatRect destRect = filter()->mapLocalRectToAbsoluteRect(filterPrimitiveSubregion()); 86 FloatRect srcRect; 87 if (renderer) { 88 srcRect = getRendererRepaintRect(renderer); 89 SVGElement* contextNode = toSVGElement(renderer->node()); 90 91 if (contextNode->hasRelativeLengths()) { 92 // FIXME: This fixes relative lengths but breaks non-relative ones (see crbug/260709). 93 SVGLengthContext lengthContext(contextNode); 94 FloatSize viewportSize; 95 if (lengthContext.determineViewport(viewportSize)) { 96 srcRect = makeMapBetweenRects(FloatRect(FloatPoint(), viewportSize), destRect).mapRect(srcRect); 97 } 98 } else { 99 srcRect = filter()->mapLocalRectToAbsoluteRect(srcRect); 100 srcRect.move(destRect.x(), destRect.y()); 101 } 102 destRect.intersect(srcRect); 103 } else { 104 srcRect = FloatRect(FloatPoint(), m_image->size()); 105 m_preserveAspectRatio->transformRect(destRect, srcRect); 106 } 107 108 destRect.intersect(requestedRect); 109 addAbsolutePaintRect(destRect); 110 return destRect; 111 } 112 113 RenderObject* FEImage::referencedRenderer() const 114 { 115 if (!m_treeScope) 116 return 0; 117 Element* hrefElement = SVGURIReference::targetElementFromIRIString(m_href, *m_treeScope); 118 if (!hrefElement || !hrefElement->isSVGElement()) 119 return 0; 120 return hrefElement->renderer(); 121 } 122 123 void FEImage::applySoftware() 124 { 125 RenderObject* renderer = referencedRenderer(); 126 if (!m_image && !renderer) 127 return; 128 129 ImageBuffer* resultImage = createImageBufferResult(); 130 if (!resultImage) 131 return; 132 IntPoint paintLocation = absolutePaintRect().location(); 133 resultImage->context()->translate(-paintLocation.x(), -paintLocation.y()); 134 135 // FEImage results are always in ColorSpaceDeviceRGB 136 setResultColorSpace(ColorSpaceDeviceRGB); 137 138 FloatRect destRect = filter()->mapLocalRectToAbsoluteRect(filterPrimitiveSubregion()); 139 FloatRect srcRect; 140 141 if (!renderer) { 142 srcRect = FloatRect(FloatPoint(), m_image->size()); 143 m_preserveAspectRatio->transformRect(destRect, srcRect); 144 145 resultImage->context()->drawImage(m_image.get(), destRect, srcRect); 146 return; 147 } 148 149 SVGElement* contextNode = toSVGElement(renderer->node()); 150 if (contextNode->hasRelativeLengths()) { 151 // FIXME: This fixes relative lengths but breaks non-relative ones (see crbug/260709). 152 SVGLengthContext lengthContext(contextNode); 153 FloatSize viewportSize; 154 155 // If we're referencing an element with percentage units, eg. <rect with="30%"> those values were resolved against the viewport. 156 // Build up a transformation that maps from the viewport space to the filter primitive subregion. 157 if (lengthContext.determineViewport(viewportSize)) 158 resultImage->context()->concatCTM(makeMapBetweenRects(FloatRect(FloatPoint(), viewportSize), destRect)); 159 } else { 160 resultImage->context()->translate(destRect.x(), destRect.y()); 161 resultImage->context()->concatCTM(filter()->absoluteTransform()); 162 } 163 164 AffineTransform contentTransformation; 165 SVGRenderingContext::renderSubtree(resultImage->context(), renderer, contentTransformation); 166 } 167 168 TextStream& FEImage::externalRepresentation(TextStream& ts, int indent) const 169 { 170 IntSize imageSize; 171 if (m_image) 172 imageSize = m_image->size(); 173 else if (RenderObject* renderer = referencedRenderer()) 174 imageSize = enclosingIntRect(getRendererRepaintRect(renderer)).size(); 175 writeIndent(ts, indent); 176 ts << "[feImage"; 177 FilterEffect::externalRepresentation(ts); 178 ts << " image-size=\"" << imageSize.width() << "x" << imageSize.height() << "\"]\n"; 179 // FIXME: should this dump also object returned by SVGFEImage::image() ? 180 return ts; 181 } 182 183 PassRefPtr<SkImageFilter> FEImage::createImageFilterForRenderer(RenderObject* renderer, SkiaImageFilterBuilder* builder) 184 { 185 FloatRect dstRect = filterPrimitiveSubregion(); 186 187 AffineTransform transform; 188 SVGElement* contextNode = toSVGElement(renderer->node()); 189 190 if (contextNode->hasRelativeLengths()) { 191 SVGLengthContext lengthContext(contextNode); 192 FloatSize viewportSize; 193 194 // If we're referencing an element with percentage units, eg. <rect with="30%"> those values were resolved against the viewport. 195 // Build up a transformation that maps from the viewport space to the filter primitive subregion. 196 if (lengthContext.determineViewport(viewportSize)) 197 transform = makeMapBetweenRects(FloatRect(FloatPoint(), viewportSize), dstRect); 198 } else { 199 transform.translate(dstRect.x(), dstRect.y()); 200 } 201 202 GraphicsContext* context = builder->context(); 203 if (!context) 204 return adoptRef(SkBitmapSource::Create(SkBitmap())); 205 AffineTransform contentTransformation; 206 context->save(); 207 context->beginRecording(FloatRect(FloatPoint(), dstRect.size())); 208 context->concatCTM(transform); 209 SVGRenderingContext::renderSubtree(context, renderer, contentTransformation); 210 RefPtr<DisplayList> displayList = context->endRecording(); 211 context->restore(); 212 RefPtr<SkImageFilter> result = adoptRef(SkPictureImageFilter::Create(displayList->picture(), dstRect)); 213 return result.release(); 214 } 215 216 PassRefPtr<SkImageFilter> FEImage::createImageFilter(SkiaImageFilterBuilder* builder) 217 { 218 RenderObject* renderer = referencedRenderer(); 219 if (!m_image && !renderer) 220 return adoptRef(SkBitmapSource::Create(SkBitmap())); 221 222 setOperatingColorSpace(ColorSpaceDeviceRGB); 223 224 if (renderer) 225 return createImageFilterForRenderer(renderer, builder); 226 227 FloatRect srcRect = FloatRect(FloatPoint(), m_image->size()); 228 FloatRect dstRect = filterPrimitiveSubregion(); 229 230 // FIXME: CSS image filters currently do not seem to set filter primitive 231 // subregion correctly if unspecified. So default to srcRect size if so. 232 if (dstRect.isEmpty()) 233 dstRect = srcRect; 234 235 m_preserveAspectRatio->transformRect(dstRect, srcRect); 236 237 if (!m_image->nativeImageForCurrentFrame()) 238 return adoptRef(SkBitmapSource::Create(SkBitmap())); 239 240 RefPtr<SkImageFilter> result = adoptRef(SkBitmapSource::Create(m_image->nativeImageForCurrentFrame()->bitmap(), srcRect, dstRect)); 241 return result.release(); 242 } 243 244 } // namespace WebCore 245