1/* 2 * Copyright (C) 2011 Apple Inc. All rights reserved. 3 * Copyright (C) 2013 Google Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "config.h" 28 29#if ENABLE(CSS_FILTERS) 30 31#include "FilterEffectRenderer.h" 32 33#include "CachedSVGDocument.h" 34#include "CachedSVGDocumentReference.h" 35#include "ColorSpace.h" 36#include "Document.h" 37#include "ElementIterator.h" 38#include "FEColorMatrix.h" 39#include "FEComponentTransfer.h" 40#include "FEDropShadow.h" 41#include "FEGaussianBlur.h" 42#include "FEMerge.h" 43#include "FloatConversion.h" 44#include "Frame.h" 45#include "RenderLayer.h" 46#include "SVGElement.h" 47#include "SVGFilterPrimitiveStandardAttributes.h" 48#include "Settings.h" 49#include "SourceAlpha.h" 50 51#include <algorithm> 52#include <wtf/MathExtras.h> 53 54namespace WebCore { 55 56static inline void endMatrixRow(Vector<float>& parameters) 57{ 58 parameters.append(0); 59 parameters.append(0); 60} 61 62static inline void lastMatrixRow(Vector<float>& parameters) 63{ 64 parameters.append(0); 65 parameters.append(0); 66 parameters.append(0); 67 parameters.append(1); 68 parameters.append(0); 69} 70 71FilterEffectRenderer::FilterEffectRenderer() 72 : Filter(AffineTransform()) 73 , m_graphicsBufferAttached(false) 74 , m_hasFilterThatMovesPixels(false) 75{ 76 setFilterResolution(FloatSize(1, 1)); 77 m_sourceGraphic = SourceGraphic::create(this); 78} 79 80FilterEffectRenderer::~FilterEffectRenderer() 81{ 82} 83 84GraphicsContext* FilterEffectRenderer::inputContext() 85{ 86 return sourceImage() ? sourceImage()->context() : 0; 87} 88 89PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(RenderElement* renderer, PassRefPtr<FilterEffect> previousEffect, ReferenceFilterOperation* filterOperation) 90{ 91 if (!renderer) 92 return 0; 93 94 Document* document = &renderer->document(); 95 96 CachedSVGDocumentReference* cachedSVGDocumentReference = filterOperation->cachedSVGDocumentReference(); 97 CachedSVGDocument* cachedSVGDocument = cachedSVGDocumentReference ? cachedSVGDocumentReference->document() : 0; 98 99 // If we have an SVG document, this is an external reference. Otherwise 100 // we look up the referenced node in the current document. 101 if (cachedSVGDocument) 102 document = cachedSVGDocument->document(); 103 104 if (!document) 105 return 0; 106 107 Element* filter = document->getElementById(filterOperation->fragment()); 108 if (!filter) { 109 // Although we did not find the referenced filter, it might exist later in the document. 110 // FIXME: This skips anonymous RenderObjects. <https://webkit.org/b/131085> 111 if (Element* element = renderer->element()) 112 document->accessSVGExtensions()->addPendingResource(filterOperation->fragment(), element); 113 return 0; 114 } 115 116 RefPtr<FilterEffect> effect; 117 118 // FIXME: Figure out what to do with SourceAlpha. Right now, we're 119 // using the alpha of the original input layer, which is obviously 120 // wrong. We should probably be extracting the alpha from the 121 // previousEffect, but this requires some more processing. 122 // This may need a spec clarification. 123 auto builder = std::make_unique<SVGFilterBuilder>(previousEffect, SourceAlpha::create(this)); 124 125 for (auto& effectElement : childrenOfType<SVGFilterPrimitiveStandardAttributes>(*filter)) { 126 effect = effectElement.build(builder.get(), this); 127 if (!effect) 128 continue; 129 130 effectElement.setStandardAttributes(effect.get()); 131 builder->add(effectElement.result(), effect); 132 m_effects.append(effect); 133 } 134 return effect; 135} 136 137bool FilterEffectRenderer::build(RenderElement* renderer, const FilterOperations& operations, FilterConsumer consumer) 138{ 139 m_hasFilterThatMovesPixels = operations.hasFilterThatMovesPixels(); 140 if (m_hasFilterThatMovesPixels) 141 m_outsets = operations.outsets(); 142 143 m_effects.clear(); 144 145 RefPtr<FilterEffect> previousEffect = m_sourceGraphic; 146 for (size_t i = 0; i < operations.operations().size(); ++i) { 147 RefPtr<FilterEffect> effect; 148 FilterOperation* filterOperation = operations.operations().at(i).get(); 149 switch (filterOperation->type()) { 150 case FilterOperation::REFERENCE: { 151 ReferenceFilterOperation* referenceOperation = toReferenceFilterOperation(filterOperation); 152 effect = buildReferenceFilter(renderer, previousEffect, referenceOperation); 153 referenceOperation->setFilterEffect(effect); 154 break; 155 } 156 case FilterOperation::GRAYSCALE: { 157 BasicColorMatrixFilterOperation* colorMatrixOperation = toBasicColorMatrixFilterOperation(filterOperation); 158 Vector<float> inputParameters; 159 double oneMinusAmount = clampTo(1 - colorMatrixOperation->amount(), 0.0, 1.0); 160 161 // See https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#grayscaleEquivalent 162 // for information on parameters. 163 164 inputParameters.append(narrowPrecisionToFloat(0.2126 + 0.7874 * oneMinusAmount)); 165 inputParameters.append(narrowPrecisionToFloat(0.7152 - 0.7152 * oneMinusAmount)); 166 inputParameters.append(narrowPrecisionToFloat(0.0722 - 0.0722 * oneMinusAmount)); 167 endMatrixRow(inputParameters); 168 169 inputParameters.append(narrowPrecisionToFloat(0.2126 - 0.2126 * oneMinusAmount)); 170 inputParameters.append(narrowPrecisionToFloat(0.7152 + 0.2848 * oneMinusAmount)); 171 inputParameters.append(narrowPrecisionToFloat(0.0722 - 0.0722 * oneMinusAmount)); 172 endMatrixRow(inputParameters); 173 174 inputParameters.append(narrowPrecisionToFloat(0.2126 - 0.2126 * oneMinusAmount)); 175 inputParameters.append(narrowPrecisionToFloat(0.7152 - 0.7152 * oneMinusAmount)); 176 inputParameters.append(narrowPrecisionToFloat(0.0722 + 0.9278 * oneMinusAmount)); 177 endMatrixRow(inputParameters); 178 179 lastMatrixRow(inputParameters); 180 181 effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_MATRIX, inputParameters); 182 break; 183 } 184 case FilterOperation::SEPIA: { 185 BasicColorMatrixFilterOperation* colorMatrixOperation = toBasicColorMatrixFilterOperation(filterOperation); 186 Vector<float> inputParameters; 187 double oneMinusAmount = clampTo(1 - colorMatrixOperation->amount(), 0.0, 1.0); 188 189 // See https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#sepiaEquivalent 190 // for information on parameters. 191 192 inputParameters.append(narrowPrecisionToFloat(0.393 + 0.607 * oneMinusAmount)); 193 inputParameters.append(narrowPrecisionToFloat(0.769 - 0.769 * oneMinusAmount)); 194 inputParameters.append(narrowPrecisionToFloat(0.189 - 0.189 * oneMinusAmount)); 195 endMatrixRow(inputParameters); 196 197 inputParameters.append(narrowPrecisionToFloat(0.349 - 0.349 * oneMinusAmount)); 198 inputParameters.append(narrowPrecisionToFloat(0.686 + 0.314 * oneMinusAmount)); 199 inputParameters.append(narrowPrecisionToFloat(0.168 - 0.168 * oneMinusAmount)); 200 endMatrixRow(inputParameters); 201 202 inputParameters.append(narrowPrecisionToFloat(0.272 - 0.272 * oneMinusAmount)); 203 inputParameters.append(narrowPrecisionToFloat(0.534 - 0.534 * oneMinusAmount)); 204 inputParameters.append(narrowPrecisionToFloat(0.131 + 0.869 * oneMinusAmount)); 205 endMatrixRow(inputParameters); 206 207 lastMatrixRow(inputParameters); 208 209 effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_MATRIX, inputParameters); 210 break; 211 } 212 case FilterOperation::SATURATE: { 213 BasicColorMatrixFilterOperation* colorMatrixOperation = toBasicColorMatrixFilterOperation(filterOperation); 214 Vector<float> inputParameters; 215 inputParameters.append(narrowPrecisionToFloat(colorMatrixOperation->amount())); 216 effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_SATURATE, inputParameters); 217 break; 218 } 219 case FilterOperation::HUE_ROTATE: { 220 BasicColorMatrixFilterOperation* colorMatrixOperation = toBasicColorMatrixFilterOperation(filterOperation); 221 Vector<float> inputParameters; 222 inputParameters.append(narrowPrecisionToFloat(colorMatrixOperation->amount())); 223 effect = FEColorMatrix::create(this, FECOLORMATRIX_TYPE_HUEROTATE, inputParameters); 224 break; 225 } 226 case FilterOperation::INVERT: { 227 BasicComponentTransferFilterOperation* componentTransferOperation = toBasicComponentTransferFilterOperation(filterOperation); 228 ComponentTransferFunction transferFunction; 229 transferFunction.type = FECOMPONENTTRANSFER_TYPE_TABLE; 230 Vector<float> transferParameters; 231 transferParameters.append(narrowPrecisionToFloat(componentTransferOperation->amount())); 232 transferParameters.append(narrowPrecisionToFloat(1 - componentTransferOperation->amount())); 233 transferFunction.tableValues = transferParameters; 234 235 ComponentTransferFunction nullFunction; 236 effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction); 237 break; 238 } 239 case FilterOperation::OPACITY: { 240 BasicComponentTransferFilterOperation* componentTransferOperation = toBasicComponentTransferFilterOperation(filterOperation); 241 ComponentTransferFunction transferFunction; 242 transferFunction.type = FECOMPONENTTRANSFER_TYPE_TABLE; 243 Vector<float> transferParameters; 244 transferParameters.append(0); 245 transferParameters.append(narrowPrecisionToFloat(componentTransferOperation->amount())); 246 transferFunction.tableValues = transferParameters; 247 248 ComponentTransferFunction nullFunction; 249 effect = FEComponentTransfer::create(this, nullFunction, nullFunction, nullFunction, transferFunction); 250 break; 251 } 252 case FilterOperation::BRIGHTNESS: { 253 BasicComponentTransferFilterOperation* componentTransferOperation = toBasicComponentTransferFilterOperation(filterOperation); 254 ComponentTransferFunction transferFunction; 255 transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR; 256 transferFunction.slope = narrowPrecisionToFloat(componentTransferOperation->amount()); 257 transferFunction.intercept = 0; 258 259 ComponentTransferFunction nullFunction; 260 effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction); 261 break; 262 } 263 case FilterOperation::CONTRAST: { 264 BasicComponentTransferFilterOperation* componentTransferOperation = toBasicComponentTransferFilterOperation(filterOperation); 265 ComponentTransferFunction transferFunction; 266 transferFunction.type = FECOMPONENTTRANSFER_TYPE_LINEAR; 267 float amount = narrowPrecisionToFloat(componentTransferOperation->amount()); 268 transferFunction.slope = amount; 269 transferFunction.intercept = -0.5 * amount + 0.5; 270 271 ComponentTransferFunction nullFunction; 272 effect = FEComponentTransfer::create(this, transferFunction, transferFunction, transferFunction, nullFunction); 273 break; 274 } 275 case FilterOperation::BLUR: { 276 BlurFilterOperation* blurOperation = toBlurFilterOperation(filterOperation); 277 float stdDeviation = floatValueForLength(blurOperation->stdDeviation(), 0); 278 effect = FEGaussianBlur::create(this, stdDeviation, stdDeviation, consumer == FilterProperty ? EDGEMODE_NONE : EDGEMODE_DUPLICATE); 279 break; 280 } 281 case FilterOperation::DROP_SHADOW: { 282 DropShadowFilterOperation* dropShadowOperation = toDropShadowFilterOperation(filterOperation); 283 effect = FEDropShadow::create(this, dropShadowOperation->stdDeviation(), dropShadowOperation->stdDeviation(), 284 dropShadowOperation->x(), dropShadowOperation->y(), dropShadowOperation->color(), 1); 285 break; 286 } 287 default: 288 break; 289 } 290 291 if (effect) { 292 // Unlike SVG Filters and CSSFilterImages, filter functions on the filter 293 // property applied here should not clip to their primitive subregions. 294 effect->setClipsToBounds(consumer == FilterFunction); 295 effect->setOperatingColorSpace(ColorSpaceDeviceRGB); 296 297 if (filterOperation->type() != FilterOperation::REFERENCE) { 298 effect->inputEffects().append(previousEffect); 299 m_effects.append(effect); 300 } 301 previousEffect = effect.release(); 302 } 303 } 304 305 // If we didn't make any effects, tell our caller we are not valid 306 if (!m_effects.size()) 307 return false; 308 309 setMaxEffectRects(m_sourceDrawingRegion); 310 311 return true; 312} 313 314bool FilterEffectRenderer::updateBackingStoreRect(const FloatRect& filterRect) 315{ 316 if (!filterRect.isZero() && FilterEffect::isFilterSizeValid(filterRect)) { 317 FloatRect currentSourceRect = sourceImageRect(); 318 if (filterRect != currentSourceRect) { 319 setSourceImageRect(filterRect); 320 return true; 321 } 322 } 323 return false; 324} 325 326void FilterEffectRenderer::allocateBackingStoreIfNeeded() 327{ 328 // At this point the effect chain has been built, and the 329 // source image sizes set. We just need to attach the graphic 330 // buffer if we have not yet done so. 331 if (!m_graphicsBufferAttached) { 332 IntSize logicalSize(m_sourceDrawingRegion.width(), m_sourceDrawingRegion.height()); 333 if (!sourceImage() || sourceImage()->logicalSize() != logicalSize) 334 setSourceImage(ImageBuffer::create(logicalSize, filterScale(), ColorSpaceDeviceRGB, renderingMode())); 335 m_graphicsBufferAttached = true; 336 } 337} 338 339void FilterEffectRenderer::clearIntermediateResults() 340{ 341 m_sourceGraphic->clearResult(); 342 for (size_t i = 0; i < m_effects.size(); ++i) 343 m_effects[i]->clearResult(); 344} 345 346void FilterEffectRenderer::apply() 347{ 348 RefPtr<FilterEffect> effect = lastEffect(); 349 effect->apply(); 350 effect->transformResultColorSpace(ColorSpaceDeviceRGB); 351} 352 353LayoutRect FilterEffectRenderer::computeSourceImageRectForDirtyRect(const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect) 354{ 355 // The result of this function is the area in the "filterBoxRect" that needs to be repainted, so that we fully cover the "dirtyRect". 356 LayoutRect rectForRepaint = dirtyRect; 357 if (hasFilterThatMovesPixels()) { 358 // Note that the outsets are reversed here because we are going backwards -> we have the dirty rect and 359 // need to find out what is the rectangle that might influence the result inside that dirty rect. 360 rectForRepaint.move(-m_outsets.right(), -m_outsets.bottom()); 361 rectForRepaint.expand(m_outsets.left() + m_outsets.right(), m_outsets.top() + m_outsets.bottom()); 362 } 363 rectForRepaint.intersect(filterBoxRect); 364 return rectForRepaint; 365} 366 367bool FilterEffectRendererHelper::prepareFilterEffect(RenderLayer* renderLayer, const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect, const LayoutRect& layerRepaintRect) 368{ 369 ASSERT(m_haveFilterEffect && renderLayer->filterRenderer()); 370 m_renderLayer = renderLayer; 371 m_repaintRect = dirtyRect; 372 373 FilterEffectRenderer* filter = renderLayer->filterRenderer(); 374 LayoutRect filterSourceRect = filter->computeSourceImageRectForDirtyRect(filterBoxRect, dirtyRect); 375 m_paintOffset = filterSourceRect.location(); 376 377 if (filterSourceRect.isEmpty()) { 378 // The dirty rect is not in view, just bail out. 379 m_haveFilterEffect = false; 380 return false; 381 } 382 383 bool hasUpdatedBackingStore = filter->updateBackingStoreRect(filterSourceRect); 384 if (filter->hasFilterThatMovesPixels()) { 385 if (hasUpdatedBackingStore) 386 m_repaintRect = filterSourceRect; 387 else { 388 m_repaintRect.unite(layerRepaintRect); 389 m_repaintRect.intersect(filterSourceRect); 390 } 391 } 392 return true; 393} 394 395GraphicsContext* FilterEffectRendererHelper::filterContext() const 396{ 397 if (!m_haveFilterEffect) 398 return 0; 399 400 FilterEffectRenderer* filter = m_renderLayer->filterRenderer(); 401 return filter->inputContext(); 402} 403 404bool FilterEffectRendererHelper::beginFilterEffect() 405{ 406 ASSERT(m_renderLayer); 407 408 FilterEffectRenderer* filter = m_renderLayer->filterRenderer(); 409 filter->allocateBackingStoreIfNeeded(); 410 // Paint into the context that represents the SourceGraphic of the filter. 411 GraphicsContext* sourceGraphicsContext = filter->inputContext(); 412 if (!sourceGraphicsContext || !FilterEffect::isFilterSizeValid(filter->filterRegion())) { 413 // Disable the filters and continue. 414 m_haveFilterEffect = false; 415 return false; 416 } 417 418 // Translate the context so that the contents of the layer is captuterd in the offscreen memory buffer. 419 sourceGraphicsContext->save(); 420 sourceGraphicsContext->translate(-m_paintOffset.x(), -m_paintOffset.y()); 421 sourceGraphicsContext->clearRect(m_repaintRect); 422 sourceGraphicsContext->clip(m_repaintRect); 423 424 m_startedFilterEffect = true; 425 return true; 426} 427 428void FilterEffectRendererHelper::applyFilterEffect(GraphicsContext* destinationContext) 429{ 430 ASSERT(m_haveFilterEffect && m_renderLayer->filterRenderer()); 431 FilterEffectRenderer* filter = m_renderLayer->filterRenderer(); 432 filter->inputContext()->restore(); 433 434 filter->apply(); 435 436 // Get the filtered output and draw it in place. 437 LayoutRect destRect = filter->outputRect(); 438 destRect.move(m_paintOffset.x(), m_paintOffset.y()); 439 440 destinationContext->drawImageBuffer(filter->output(), m_renderLayer->renderer().style().colorSpace(), 441 pixelSnappedForPainting(destRect, m_renderLayer->renderer().document().deviceScaleFactor())); 442 443 filter->clearIntermediateResults(); 444} 445 446} // namespace WebCore 447 448#endif // ENABLE(CSS_FILTERS) 449