void FEDropShadow::determineAbsolutePaintRect() { Filter* filter = this->filter(); ASSERT(filter); FloatRect absolutePaintRect = inputEffect(0)->absolutePaintRect(); FloatRect absoluteOffsetPaintRect(absolutePaintRect); absoluteOffsetPaintRect.move(filter->applyHorizontalScale(m_dx), filter->applyVerticalScale(m_dy)); absolutePaintRect.unite(absoluteOffsetPaintRect); unsigned kernelSizeX = 0; unsigned kernelSizeY = 0; FEGaussianBlur::calculateKernelSize(filter, kernelSizeX, kernelSizeY, m_stdX, m_stdY); // We take the half kernel size and multiply it with three, because we run box blur three times. absolutePaintRect.inflateX(3 * kernelSizeX * 0.5f); absolutePaintRect.inflateY(3 * kernelSizeY * 0.5f); if (clipsToBounds()) absolutePaintRect.intersect(maxEffectRect()); else absolutePaintRect.unite(maxEffectRect()); setAbsolutePaintRect(enclosingIntRect(absolutePaintRect)); }
void FEOffset::determineAbsolutePaintRect() { FloatRect paintRect = inputEffect(0)->absolutePaintRect(); Filter& filter = this->filter(); paintRect.move(filter.applyHorizontalScale(m_dx), filter.applyVerticalScale(m_dy)); if (clipsToBounds()) paintRect.intersect(maxEffectRect()); else paintRect.unite(maxEffectRect()); setAbsolutePaintRect(enclosingIntRect(paintRect)); }
void FEMorphology::determineAbsolutePaintRect() { FloatRect paintRect = inputEffect(0)->absolutePaintRect(); Filter& filter = this->filter(); paintRect.inflateX(filter.applyHorizontalScale(m_radiusX)); paintRect.inflateY(filter.applyVerticalScale(m_radiusY)); if (clipsToBounds()) paintRect.intersect(maxEffectRect()); else paintRect.unite(maxEffectRect()); setAbsolutePaintRect(enclosingIntRect(paintRect)); }
void FEDropShadow::determineAbsolutePaintRect() { Filter* filter = this->filter(); ASSERT(filter); FloatRect absolutePaintRect = mapRect(inputEffect(0)->absolutePaintRect()); if (clipsToBounds()) absolutePaintRect.intersect(maxEffectRect()); else absolutePaintRect.unite(maxEffectRect()); setAbsolutePaintRect(enclosingIntRect(absolutePaintRect)); }
void FilterEffect::apply() { // Recursively determine paint rects first, so that we don't redraw images // if a smaller section is requested first. determineAbsolutePaintRect(maxEffectRect()); applyRecursive(); }
FloatRect FilterEffect::determineAbsolutePaintRect(const FloatRect& originalRequestedRect) { FloatRect requestedRect = originalRequestedRect; // Filters in SVG clip to primitive subregion, while CSS doesn't. if (m_clipsToBounds) requestedRect.intersect(maxEffectRect()); // We may be called multiple times if result is used more than once. Return // quickly if if nothing new is required. if (absolutePaintRect().contains(enclosingIntRect(requestedRect))) return requestedRect; FloatRect inputRect = mapPaintRect(requestedRect, false); FloatRect inputUnion; unsigned size = m_inputEffects.size(); for (unsigned i = 0; i < size; ++i) inputUnion.unite(m_inputEffects.at(i)->determineAbsolutePaintRect(inputRect)); inputUnion = mapPaintRect(inputUnion, true); if (affectsTransparentPixels() || !size) { inputUnion = requestedRect; } else { // Rect may have inflated. Re-intersect with request. inputUnion.intersect(requestedRect); } addAbsolutePaintRect(inputUnion); return inputUnion; }
void FEImage::determineAbsolutePaintRect() { FloatRect paintRect = filter().absoluteTransform().mapRect(filterPrimitiveSubregion()); FloatRect srcRect; if (m_image) { srcRect.setSize(m_image->size()); m_preserveAspectRatio.transformRect(paintRect, srcRect); } else if (RenderElement* renderer = referencedRenderer()) srcRect = filter().absoluteTransform().mapRect(renderer->repaintRectInLocalCoordinates()); if (clipsToBounds()) paintRect.intersect(maxEffectRect()); else paintRect.unite(maxEffectRect()); setAbsolutePaintRect(enclosingIntRect(paintRect)); }
void FEGaussianBlur::determineAbsolutePaintRect() { FloatRect absolutePaintRect = inputEffect(0)->absolutePaintRect(); if (clipsToBounds()) absolutePaintRect.intersect(maxEffectRect()); else absolutePaintRect.unite(maxEffectRect()); unsigned kernelSizeX = 0; unsigned kernelSizeY = 0; calculateKernelSize(filter(), kernelSizeX, kernelSizeY, m_stdX, m_stdY); // We take the half kernel size and multiply it with three, because we run box blur three times. absolutePaintRect.inflateX(3 * kernelSizeX * 0.5f); absolutePaintRect.inflateY(3 * kernelSizeY * 0.5f); setAbsolutePaintRect(enclosingIntRect(absolutePaintRect)); }
void FEOffset::determineAbsolutePaintRect() { FloatRect paintRect = inputEffect(0)->absolutePaintRect(); Filter* filter = this->filter(); paintRect.move(filter->applyHorizontalScale(m_dx), filter->applyVerticalScale(m_dy)); paintRect.intersect(maxEffectRect()); setAbsolutePaintRect(enclosingIntRect(paintRect)); }
void FEImage::determineAbsolutePaintRect() { ASSERT(m_image); FloatRect srcRect(FloatPoint(), m_image->size()); FloatRect paintRect(m_absoluteSubregion); m_preserveAspectRatio.transformRect(paintRect, srcRect); paintRect.intersect(maxEffectRect()); setAbsolutePaintRect(enclosingIntRect(paintRect)); }
FloatRect FEComposite::determineAbsolutePaintRect(const FloatRect& originalRequestedRect) { FloatRect requestedRect = originalRequestedRect; if (clipsToBounds()) requestedRect.intersect(maxEffectRect()); // We may be called multiple times if result is used more than once. Return // quickly if nothing new is required. if (absolutePaintRect().contains(enclosingIntRect(requestedRect))) return requestedRect; // No mapPaintRect required for FEComposite. FloatRect input1Rect = inputEffect(1)->determineAbsolutePaintRect(requestedRect); FloatRect affectedRect; switch (m_type) { case FECOMPOSITE_OPERATOR_IN: // 'in' has output only in the intersection of both inputs. affectedRect = intersection(input1Rect, inputEffect(0)->determineAbsolutePaintRect(input1Rect)); break; case FECOMPOSITE_OPERATOR_ATOP: // 'atop' has output only in the extents of the second input. // Make sure first input knows where it needs to produce output. inputEffect(0)->determineAbsolutePaintRect(input1Rect); affectedRect = input1Rect; break; case FECOMPOSITE_OPERATOR_ARITHMETIC: if (k4() > 0) { // Make sure first input knows where it needs to produce output. inputEffect(0)->determineAbsolutePaintRect(requestedRect); // Arithmetic with non-zero k4 may influnce the complete filter primitive // region. So we can't optimize the paint region here. affectedRect = requestedRect; break; } if (k2() <= 0) { // Input 0 does not appear where input 1 is not present. FloatRect input0Rect = inputEffect(0)->determineAbsolutePaintRect(input1Rect); if (k3() > 0) { affectedRect = input1Rect; } else { // Just k1 is positive. Use intersection. affectedRect = intersection(input1Rect, input0Rect); } break; } // else fall through to use union default: // Take the union of both input effects. affectedRect = unionRect(input1Rect, inputEffect(0)->determineAbsolutePaintRect(requestedRect)); break; } affectedRect.intersect(requestedRect); addAbsolutePaintRect(affectedRect); return affectedRect; }
FloatRect FEGaussianBlur::determineAbsolutePaintRect(const FloatRect& originalRequestedRect) { FloatRect requestedRect = originalRequestedRect; if (clipsToBounds()) requestedRect.intersect(maxEffectRect()); FilterEffect* input = inputEffect(0); FloatRect inputRect = input->determineAbsolutePaintRect(mapRect(requestedRect, false)); FloatRect outputRect = mapRect(inputRect, true); outputRect.intersect(requestedRect); addAbsolutePaintRect(outputRect); // Blur needs space for both input and output pixels in the paint area. // Input is also clipped to subregion. if (clipsToBounds()) inputRect.intersect(maxEffectRect()); addAbsolutePaintRect(inputRect); return outputRect; }
void FEGaussianBlur::determineAbsolutePaintRect() { IntSize kernelSize = calculateKernelSize(filter(), FloatPoint(m_stdX, m_stdY)); FloatRect absolutePaintRect = inputEffect(0)->absolutePaintRect(); // Edge modes other than 'none' do not inflate the affected paint rect. if (m_edgeMode != EDGEMODE_NONE) { setAbsolutePaintRect(enclosingIntRect(absolutePaintRect)); return; } // We take the half kernel size and multiply it with three, because we run box blur three times. absolutePaintRect.inflateX(3 * kernelSize.width() * 0.5f); absolutePaintRect.inflateY(3 * kernelSize.height() * 0.5f); if (clipsToBounds()) absolutePaintRect.intersect(maxEffectRect()); else absolutePaintRect.unite(maxEffectRect()); setAbsolutePaintRect(enclosingIntRect(absolutePaintRect)); }
void FEDropShadow::determineAbsolutePaintRect() { Filter& filter = this->filter(); FloatRect absolutePaintRect = inputEffect(0)->absolutePaintRect(); FloatRect absoluteOffsetPaintRect(absolutePaintRect); absoluteOffsetPaintRect.move(filter.applyHorizontalScale(m_dx), filter.applyVerticalScale(m_dy)); absolutePaintRect.unite(absoluteOffsetPaintRect); IntSize kernelSize = FEGaussianBlur::calculateKernelSize(filter, FloatPoint(m_stdX, m_stdY)); // We take the half kernel size and multiply it with three, because we run box blur three times. absolutePaintRect.inflateX(3 * kernelSize.width() * 0.5f); absolutePaintRect.inflateY(3 * kernelSize.height() * 0.5f); if (clipsToBounds()) absolutePaintRect.intersect(maxEffectRect()); else absolutePaintRect.unite(maxEffectRect()); setAbsolutePaintRect(enclosingIntRect(absolutePaintRect)); }
FloatRect FEDisplacementMap::determineAbsolutePaintRect(const FloatRect& requestedRect) { FloatRect rect = requestedRect; if (clipsToBounds()) rect.intersect(maxEffectRect()); if (absolutePaintRect().contains(enclosingIntRect(rect))) return rect; rect = mapPaintRect(rect, false); rect = inputEffect(0)->determineAbsolutePaintRect(rect); rect = mapPaintRect(rect, true); rect.intersect(requestedRect); addAbsolutePaintRect(rect); return rect; }
void FETile::platformApplySoftware() { // FIXME: See bug 47315. This is a hack to work around a compile failure, but is incorrect behavior otherwise. FilterEffect* in = inputEffect(0); ImageBuffer* resultImage = createImageBufferResult(); ImageBuffer* inBuffer = in->asImageBuffer(); if (!resultImage || !inBuffer) return; setIsAlphaImage(in->isAlphaImage()); // Source input needs more attention. It has the size of the filterRegion but gives the // size of the cutted sourceImage back. This is part of the specification and optimization. FloatRect tileRect = in->maxEffectRect(); FloatPoint inMaxEffectLocation = tileRect.location(); FloatPoint maxEffectLocation = maxEffectRect().location(); if (in->filterEffectType() == FilterEffectTypeSourceInput) { Filter& filter = this->filter(); tileRect = filter.filterRegion(); tileRect.scale(filter.filterResolution().width(), filter.filterResolution().height()); } auto tileImage = SVGRenderingContext::createImageBuffer(tileRect, tileRect, ColorSpaceSRGB, filter().renderingMode()); if (!tileImage) return; GraphicsContext& tileImageContext = tileImage->context(); tileImageContext.translate(-inMaxEffectLocation.x(), -inMaxEffectLocation.y()); tileImageContext.drawImageBuffer(*inBuffer, in->absolutePaintRect().location()); auto tileImageCopy = ImageBuffer::sinkIntoImage(WTFMove(tileImage)); if (!tileImageCopy) return; auto pattern = Pattern::create(WTFMove(tileImageCopy), true, true); AffineTransform patternTransform; patternTransform.translate(inMaxEffectLocation.x() - maxEffectLocation.x(), inMaxEffectLocation.y() - maxEffectLocation.y()); pattern.get().setPatternSpaceTransform(patternTransform); GraphicsContext& filterContext = resultImage->context(); filterContext.setFillPattern(WTFMove(pattern)); filterContext.fillRect(FloatRect(FloatPoint(), absolutePaintRect().size())); }
void FETile::apply() { // FIXME: See bug 47315. This is a hack to work around a compile failure, but is incorrect behavior otherwise. #if ENABLE(SVG) FilterEffect* in = inputEffect(0); in->apply(); if (!in->resultImage()) return; GraphicsContext* filterContext = effectContext(); if (!filterContext) return; setIsAlphaImage(in->isAlphaImage()); // Source input needs more attention. It has the size of the filterRegion but gives the // size of the cutted sourceImage back. This is part of the specification and optimization. FloatRect tileRect = in->maxEffectRect(); FloatPoint inMaxEffectLocation = tileRect.location(); FloatPoint maxEffectLocation = maxEffectRect().location(); if (in->filterEffectType() == FilterEffectTypeSourceInput) { Filter* filter = this->filter(); tileRect = filter->filterRegion(); tileRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); } OwnPtr<ImageBuffer> tileImage; if (!SVGImageBufferTools::createImageBuffer(tileRect, tileRect, tileImage, ColorSpaceDeviceRGB)) return; GraphicsContext* tileImageContext = tileImage->context(); tileImageContext->translate(-inMaxEffectLocation.x(), -inMaxEffectLocation.y()); tileImageContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, in->absolutePaintRect().location()); RefPtr<Pattern> pattern = Pattern::create(tileImage->copyImage(), true, true); AffineTransform patternTransform; patternTransform.translate(inMaxEffectLocation.x() - maxEffectLocation.x(), inMaxEffectLocation.y() - maxEffectLocation.y()); pattern->setPatternSpaceTransform(patternTransform); filterContext->setFillPattern(pattern); filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size())); #endif }
void FEComposite::determineAbsolutePaintRect() { switch (m_type) { case FECOMPOSITE_OPERATOR_IN: case FECOMPOSITE_OPERATOR_ATOP: // For In and Atop the first effect just influences the result of // the second effect. So just use the absolute paint rect of the second effect here. setAbsolutePaintRect(inputEffect(1)->absolutePaintRect()); return; case FECOMPOSITE_OPERATOR_ARITHMETIC: // Arithmetic may influnce the compele filter primitive region. So we can't // optimize the paint region here. setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); return; default: // Take the union of both input effects. FilterEffect::determineAbsolutePaintRect(); return; } }
void FETile::applySoftware() { FilterEffect* in = inputEffect(0); ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; setIsAlphaImage(in->isAlphaImage()); // Source input needs more attention. It has the size of the filterRegion but gives the // size of the cutted sourceImage back. This is part of the specification and optimization. FloatRect tileRect = in->maxEffectRect(); FloatPoint inMaxEffectLocation = tileRect.location(); FloatPoint maxEffectLocation = maxEffectRect().location(); if (in->filterEffectType() == FilterEffectTypeSourceInput) { Filter* filter = this->filter(); tileRect = filter->absoluteFilterRegion(); } OwnPtr<ImageBufferSurface> surface; IntSize intTileSize = roundedIntSize(tileRect.size()); surface = adoptPtr(new UnacceleratedImageBufferSurface(intTileSize)); OwnPtr<ImageBuffer> tileImage = ImageBuffer::create(surface.release()); if (!tileImage) return; GraphicsContext* tileImageContext = tileImage->context(); tileImageContext->scale(FloatSize(intTileSize.width() / tileRect.width(), intTileSize.height() / tileRect.height())); tileImageContext->translate(-inMaxEffectLocation.x(), -inMaxEffectLocation.y()); tileImageContext->drawImageBuffer(in->asImageBuffer(), in->absolutePaintRect().location()); RefPtr<Pattern> pattern = Pattern::create(tileImage->copyImage(CopyBackingStore), true, true); AffineTransform patternTransform; patternTransform.translate(inMaxEffectLocation.x() - maxEffectLocation.x(), inMaxEffectLocation.y() - maxEffectLocation.y()); pattern->setPatternSpaceTransform(patternTransform); GraphicsContext* filterContext = resultImage->context(); filterContext->setFillPattern(pattern); filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size())); }
void FETile::applySoftware() { FilterEffect* in = inputEffect(0); ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; setIsAlphaImage(in->isAlphaImage()); // Source input needs more attention. It has the size of the filterRegion but gives the // size of the cutted sourceImage back. This is part of the specification and optimization. FloatRect tileRect = in->maxEffectRect(); FloatPoint inMaxEffectLocation = tileRect.location(); FloatPoint maxEffectLocation = maxEffectRect().location(); if (in->filterEffectType() == FilterEffectTypeSourceInput) { Filter* filter = this->filter(); tileRect = filter->absoluteFilterRegion(); tileRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); } OwnPtr<ImageBuffer> tileImage; if (!SVGRenderingContext::createImageBufferForPattern(tileRect, tileRect, tileImage, ColorSpaceDeviceRGB, filter()->renderingMode())) return; GraphicsContext* tileImageContext = tileImage->context(); tileImageContext->translate(-inMaxEffectLocation.x(), -inMaxEffectLocation.y()); tileImageContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, in->absolutePaintRect().location()); RefPtr<Pattern> pattern = Pattern::create(tileImage->copyImage(CopyBackingStore), true, true); AffineTransform patternTransform; patternTransform.translate(inMaxEffectLocation.x() - maxEffectLocation.x(), inMaxEffectLocation.y() - maxEffectLocation.y()); pattern->setPatternSpaceTransform(patternTransform); GraphicsContext* filterContext = resultImage->context(); filterContext->setFillPattern(pattern); filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size())); }
FloatRect FEImage::determineAbsolutePaintRect(const FloatRect& originalRequestedRect) { RenderObject* renderer = referencedRenderer(); if (!m_image && !renderer) return FloatRect(); FloatRect requestedRect = originalRequestedRect; if (clipsToBounds()) requestedRect.intersect(maxEffectRect()); FloatRect destRect = filter()->mapLocalRectToAbsoluteRect(filterPrimitiveSubregion()); FloatRect srcRect; if (renderer) { srcRect = getRendererRepaintRect(renderer); SVGElement* contextNode = toSVGElement(renderer->node()); if (contextNode->hasRelativeLengths()) { // FIXME: This fixes relative lengths but breaks non-relative ones (see crbug/260709). SVGLengthContext lengthContext(contextNode); FloatSize viewportSize; if (lengthContext.determineViewport(viewportSize)) { srcRect = makeMapBetweenRects(FloatRect(FloatPoint(), viewportSize), destRect).mapRect(srcRect); } } else { srcRect = filter()->mapLocalRectToAbsoluteRect(srcRect); srcRect.move(destRect.x(), destRect.y()); } destRect.intersect(srcRect); } else { srcRect = FloatRect(FloatPoint(), m_image->size()); m_preserveAspectRatio->transformRect(destRect, srcRect); } destRect.intersect(requestedRect); addAbsolutePaintRect(destRect); return destRect; }
FloatRect FETile::mapPaintRect(const FloatRect& rect, bool forward) { return forward ? maxEffectRect() : inputEffect(0)->maxEffectRect(); }