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) 2009 Dirk Schulze <krit (at) webkit.org> 6 * Copyright (C) Research In Motion Limited 2010. 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/rendering/svg/RenderSVGResourceFilter.h" 27 28 #include "core/frame/Settings.h" 29 #include "core/rendering/svg/RenderSVGResourceFilterPrimitive.h" 30 #include "core/rendering/svg/SVGRenderingContext.h" 31 #include "core/svg/SVGFilterPrimitiveStandardAttributes.h" 32 #include "platform/graphics/UnacceleratedImageBufferSurface.h" 33 #include "platform/graphics/filters/SourceAlpha.h" 34 #include "platform/graphics/filters/SourceGraphic.h" 35 #include "platform/graphics/gpu/AcceleratedImageBufferSurface.h" 36 37 using namespace std; 38 39 namespace WebCore { 40 41 const RenderSVGResourceType RenderSVGResourceFilter::s_resourceType = FilterResourceType; 42 43 RenderSVGResourceFilter::RenderSVGResourceFilter(SVGFilterElement* node) 44 : RenderSVGResourceContainer(node) 45 { 46 } 47 48 RenderSVGResourceFilter::~RenderSVGResourceFilter() 49 { 50 m_filter.clear(); 51 } 52 53 void RenderSVGResourceFilter::removeAllClientsFromCache(bool markForInvalidation) 54 { 55 m_filter.clear(); 56 markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation); 57 } 58 59 void RenderSVGResourceFilter::removeClientFromCache(RenderObject* client, bool markForInvalidation) 60 { 61 ASSERT(client); 62 63 if (FilterData* filterData = m_filter.get(client)) { 64 if (filterData->savedContext) 65 filterData->state = FilterData::MarkedForRemoval; 66 else 67 m_filter.remove(client); 68 } 69 70 markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation); 71 } 72 73 PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter* filter) 74 { 75 SVGFilterElement* filterElement = toSVGFilterElement(element()); 76 FloatRect targetBoundingBox = filter->targetBoundingBox(); 77 78 // Add effects to the builder 79 RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(SourceGraphic::create(filter), SourceAlpha::create(filter)); 80 for (Node* node = filterElement->firstChild(); node; node = node->nextSibling()) { 81 if (!node->isSVGElement()) 82 continue; 83 84 SVGElement* element = toSVGElement(node); 85 if (!element->isFilterEffect() || !element->renderer()) 86 continue; 87 88 SVGFilterPrimitiveStandardAttributes* effectElement = static_cast<SVGFilterPrimitiveStandardAttributes*>(element); 89 RefPtr<FilterEffect> effect = effectElement->build(builder.get(), filter); 90 if (!effect) { 91 builder->clearEffects(); 92 return 0; 93 } 94 builder->appendEffectToEffectReferences(effect, effectElement->renderer()); 95 effectElement->setStandardAttributes(effect.get()); 96 effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnitsCurrentValue(), targetBoundingBox)); 97 effect->setOperatingColorSpace( 98 effectElement->renderer()->style()->svgStyle()->colorInterpolationFilters() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB); 99 builder->add(effectElement->resultCurrentValue(), effect); 100 } 101 return builder.release(); 102 } 103 104 bool RenderSVGResourceFilter::fitsInMaximumImageSize(const FloatSize& size, FloatSize& scale) 105 { 106 bool matchesFilterSize = true; 107 if (size.width() > kMaxFilterSize) { 108 scale.setWidth(scale.width() * kMaxFilterSize / size.width()); 109 matchesFilterSize = false; 110 } 111 if (size.height() > kMaxFilterSize) { 112 scale.setHeight(scale.height() * kMaxFilterSize / size.height()); 113 matchesFilterSize = false; 114 } 115 116 return matchesFilterSize; 117 } 118 119 static bool createImageBuffer(const FloatRect& targetRect, const AffineTransform& absoluteTransform, 120 OwnPtr<ImageBuffer>& imageBuffer, bool accelerated) 121 { 122 IntRect paintRect = SVGRenderingContext::calculateImageBufferRect(targetRect, absoluteTransform); 123 // Don't create empty ImageBuffers. 124 if (paintRect.isEmpty()) 125 return false; 126 127 OwnPtr<ImageBufferSurface> surface; 128 if (accelerated) 129 surface = adoptPtr(new AcceleratedImageBufferSurface(paintRect.size())); 130 if (!accelerated || !surface->isValid()) 131 surface = adoptPtr(new UnacceleratedImageBufferSurface(paintRect.size())); 132 if (!surface->isValid()) 133 return false; 134 OwnPtr<ImageBuffer> image = ImageBuffer::create(surface.release()); 135 136 GraphicsContext* imageContext = image->context(); 137 ASSERT(imageContext); 138 139 imageContext->translate(-paintRect.x(), -paintRect.y()); 140 imageContext->concatCTM(absoluteTransform); 141 142 imageBuffer = image.release(); 143 return true; 144 } 145 146 bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) 147 { 148 ASSERT(object); 149 ASSERT(context); 150 ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode); 151 152 clearInvalidationMask(); 153 154 if (m_filter.contains(object)) { 155 FilterData* filterData = m_filter.get(object); 156 if (filterData->state == FilterData::PaintingSource || filterData->state == FilterData::Applying) 157 filterData->state = FilterData::CycleDetected; 158 return false; // Already built, or we're in a cycle, or we're marked for removal. Regardless, just do nothing more now. 159 } 160 161 OwnPtr<FilterData> filterData(adoptPtr(new FilterData)); 162 FloatRect targetBoundingBox = object->objectBoundingBox(); 163 164 SVGFilterElement* filterElement = toSVGFilterElement(element()); 165 filterData->boundaries = SVGLengthContext::resolveRectangle<SVGFilterElement>(filterElement, filterElement->filterUnitsCurrentValue(), targetBoundingBox); 166 if (filterData->boundaries.isEmpty()) 167 return false; 168 169 // Determine absolute transformation matrix for filter. 170 AffineTransform absoluteTransform; 171 SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform); 172 if (!absoluteTransform.isInvertible()) 173 return false; 174 175 // Eliminate shear of the absolute transformation matrix, to be able to produce unsheared tile images for feTile. 176 filterData->shearFreeAbsoluteTransform = AffineTransform(absoluteTransform.xScale(), 0, 0, absoluteTransform.yScale(), 0, 0); 177 178 // Determine absolute boundaries of the filter and the drawing region. 179 FloatRect absoluteFilterBoundaries = filterData->shearFreeAbsoluteTransform.mapRect(filterData->boundaries); 180 filterData->drawingRegion = object->strokeBoundingBox(); 181 filterData->drawingRegion.intersect(filterData->boundaries); 182 FloatRect absoluteDrawingRegion = filterData->shearFreeAbsoluteTransform.mapRect(filterData->drawingRegion); 183 184 // Create the SVGFilter object. 185 bool primitiveBoundingBoxMode = filterElement->primitiveUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; 186 filterData->filter = SVGFilter::create(filterData->shearFreeAbsoluteTransform, absoluteDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundingBoxMode); 187 188 // Create all relevant filter primitives. 189 filterData->builder = buildPrimitives(filterData->filter.get()); 190 if (!filterData->builder) 191 return false; 192 193 // Calculate the scale factor for the use of filterRes. 194 // Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion 195 FloatSize scale(1, 1); 196 if (filterElement->hasAttribute(SVGNames::filterResAttr)) { 197 scale.setWidth(filterElement->filterResXCurrentValue() / absoluteFilterBoundaries.width()); 198 scale.setHeight(filterElement->filterResYCurrentValue() / absoluteFilterBoundaries.height()); 199 } 200 201 if (scale.isEmpty()) 202 return false; 203 204 // Determine scale factor for filter. The size of intermediate ImageBuffers shouldn't be bigger than kMaxFilterSize. 205 FloatRect tempSourceRect = absoluteDrawingRegion; 206 tempSourceRect.scale(scale.width(), scale.height()); 207 fitsInMaximumImageSize(tempSourceRect.size(), scale); 208 209 // Set the scale level in SVGFilter. 210 filterData->filter->setFilterResolution(scale); 211 212 FilterEffect* lastEffect = filterData->builder->lastEffect(); 213 if (!lastEffect) 214 return false; 215 216 lastEffect->determineFilterPrimitiveSubregion(ClipToFilterRegion); 217 FloatRect subRegion = lastEffect->maxEffectRect(); 218 // At least one FilterEffect has a too big image size, 219 // recalculate the effect sizes with new scale factors. 220 if (!fitsInMaximumImageSize(subRegion.size(), scale)) { 221 filterData->filter->setFilterResolution(scale); 222 lastEffect->determineFilterPrimitiveSubregion(ClipToFilterRegion); 223 } 224 225 // If the drawingRegion is empty, we have something like <g filter=".."/>. 226 // Even if the target objectBoundingBox() is empty, we still have to draw the last effect result image in postApplyResource. 227 if (filterData->drawingRegion.isEmpty()) { 228 ASSERT(!m_filter.contains(object)); 229 filterData->savedContext = context; 230 m_filter.set(object, filterData.release()); 231 return false; 232 } 233 234 // Change the coordinate transformation applied to the filtered element to reflect the resolution of the filter. 235 AffineTransform effectiveTransform; 236 effectiveTransform.scale(scale.width(), scale.height()); 237 effectiveTransform.multiply(filterData->shearFreeAbsoluteTransform); 238 239 OwnPtr<ImageBuffer> sourceGraphic; 240 bool isAccelerated = object->document().settings()->acceleratedFiltersEnabled(); 241 if (!createImageBuffer(filterData->drawingRegion, effectiveTransform, sourceGraphic, isAccelerated)) { 242 ASSERT(!m_filter.contains(object)); 243 filterData->savedContext = context; 244 m_filter.set(object, filterData.release()); 245 return false; 246 } 247 248 // Set the rendering mode from the page's settings. 249 filterData->filter->setIsAccelerated(isAccelerated); 250 251 GraphicsContext* sourceGraphicContext = sourceGraphic->context(); 252 ASSERT(sourceGraphicContext); 253 254 filterData->sourceGraphicBuffer = sourceGraphic.release(); 255 filterData->savedContext = context; 256 257 context = sourceGraphicContext; 258 259 ASSERT(!m_filter.contains(object)); 260 m_filter.set(object, filterData.release()); 261 262 return true; 263 } 264 265 void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsContext*& context, unsigned short resourceMode, const Path*, const RenderSVGShape*) 266 { 267 ASSERT(object); 268 ASSERT(context); 269 ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode); 270 271 FilterData* filterData = m_filter.get(object); 272 if (!filterData) 273 return; 274 275 switch (filterData->state) { 276 case FilterData::MarkedForRemoval: 277 m_filter.remove(object); 278 return; 279 280 case FilterData::CycleDetected: 281 case FilterData::Applying: 282 // We have a cycle if we are already applying the data. 283 // This can occur due to FeImage referencing a source that makes use of the FEImage itself. 284 // This is the first place we've hit the cycle, so set the state back to PaintingSource so the return stack 285 // will continue correctly. 286 filterData->state = FilterData::PaintingSource; 287 return; 288 289 case FilterData::PaintingSource: 290 if (!filterData->savedContext) { 291 removeClientFromCache(object); 292 return; 293 } 294 295 context = filterData->savedContext; 296 filterData->savedContext = 0; 297 break; 298 299 case FilterData::Built: { } // Empty 300 } 301 302 FilterEffect* lastEffect = filterData->builder->lastEffect(); 303 304 if (lastEffect && !filterData->boundaries.isEmpty() && !lastEffect->filterPrimitiveSubregion().isEmpty()) { 305 // This is the real filtering of the object. It just needs to be called on the 306 // initial filtering process. We just take the stored filter result on a 307 // second drawing. 308 if (filterData->state != FilterData::Built) 309 filterData->filter->setSourceImage(filterData->sourceGraphicBuffer.release()); 310 311 // Always true if filterData is just built (filterData->state == FilterData::Built). 312 if (!lastEffect->hasResult()) { 313 filterData->state = FilterData::Applying; 314 lastEffect->apply(); 315 lastEffect->correctFilterResultIfNeeded(); 316 lastEffect->transformResultColorSpace(ColorSpaceDeviceRGB); 317 } 318 filterData->state = FilterData::Built; 319 320 ImageBuffer* resultImage = lastEffect->asImageBuffer(); 321 if (resultImage) { 322 context->concatCTM(filterData->shearFreeAbsoluteTransform.inverse()); 323 324 context->scale(FloatSize(1 / filterData->filter->filterResolution().width(), 1 / filterData->filter->filterResolution().height())); 325 context->drawImageBuffer(resultImage, lastEffect->absolutePaintRect()); 326 context->scale(filterData->filter->filterResolution()); 327 328 context->concatCTM(filterData->shearFreeAbsoluteTransform); 329 } 330 } 331 filterData->sourceGraphicBuffer.clear(); 332 } 333 334 FloatRect RenderSVGResourceFilter::resourceBoundingBox(RenderObject* object) 335 { 336 if (SVGFilterElement* element = toSVGFilterElement(this->element())) 337 return SVGLengthContext::resolveRectangle<SVGFilterElement>(element, element->filterUnitsCurrentValue(), object->objectBoundingBox()); 338 339 return FloatRect(); 340 } 341 342 void RenderSVGResourceFilter::primitiveAttributeChanged(RenderObject* object, const QualifiedName& attribute) 343 { 344 FilterMap::iterator it = m_filter.begin(); 345 FilterMap::iterator end = m_filter.end(); 346 SVGFilterPrimitiveStandardAttributes* primitve = static_cast<SVGFilterPrimitiveStandardAttributes*>(object->node()); 347 348 for (; it != end; ++it) { 349 FilterData* filterData = it->value.get(); 350 if (filterData->state != FilterData::Built) 351 continue; 352 353 SVGFilterBuilder* builder = filterData->builder.get(); 354 FilterEffect* effect = builder->effectByRenderer(object); 355 if (!effect) 356 continue; 357 // Since all effects shares the same attribute value, all 358 // or none of them will be changed. 359 if (!primitve->setFilterEffectAttribute(effect, attribute)) 360 return; 361 builder->clearResultsRecursive(effect); 362 363 // Repaint the image on the screen. 364 markClientForInvalidation(it->key, RepaintInvalidation); 365 } 366 markAllClientLayersForInvalidation(); 367 } 368 369 FloatRect RenderSVGResourceFilter::drawingRegion(RenderObject* object) const 370 { 371 FilterData* filterData = m_filter.get(object); 372 return filterData ? filterData->drawingRegion : FloatRect(); 373 } 374 375 } 376