summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.cpp')
-rw-r--r--chromium/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.cpp173
1 files changed, 124 insertions, 49 deletions
diff --git a/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.cpp b/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.cpp
index 2b1324298ac..518173bebe3 100644
--- a/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.cpp
+++ b/chromium/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.cpp
@@ -28,7 +28,6 @@
#include "platform/graphics/ImageBuffer.h"
#include "platform/graphics/UnacceleratedImageBufferSurface.h"
#include "platform/graphics/filters/Filter.h"
-#include "platform/graphics/gpu/AcceleratedImageBufferSurface.h"
#if HAVE(ARM_NEON_INTRINSICS)
#include <arm_neon.h>
@@ -36,6 +35,8 @@
namespace WebCore {
+static const float kMaxFilterArea = 4096 * 4096;
+
FilterEffect::FilterEffect(Filter* filter)
: m_alphaImage(false)
, m_filter(filter)
@@ -54,27 +55,49 @@ FilterEffect::~FilterEffect()
{
}
-inline bool isFilterSizeValid(IntRect rect)
+float FilterEffect::maxFilterArea()
+{
+ return kMaxFilterArea;
+}
+
+bool FilterEffect::isFilterSizeValid(const FloatRect& rect)
{
- if (rect.width() < 0 || rect.width() > kMaxFilterSize
- || rect.height() < 0 || rect.height() > kMaxFilterSize)
+ if (rect.width() < 0 || rect.height() < 0
+ || (rect.height() * rect.width() > kMaxFilterArea))
return false;
+
return true;
}
-void FilterEffect::determineAbsolutePaintRect()
+FloatRect FilterEffect::determineAbsolutePaintRect(const FloatRect& originalRequestedRect)
{
- m_absolutePaintRect = IntRect();
+ 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)
- m_absolutePaintRect.unite(m_inputEffects.at(i)->absolutePaintRect());
+ inputUnion.unite(m_inputEffects.at(i)->determineAbsolutePaintRect(inputRect));
+ inputUnion = mapPaintRect(inputUnion, true);
- // Filters in SVG clip to primitive subregion, while CSS doesn't.
- if (m_clipsToBounds)
- m_absolutePaintRect.intersect(enclosingIntRect(m_maxEffectRect));
- else
- m_absolutePaintRect.unite(enclosingIntRect(m_maxEffectRect));
+ if (affectsTransparentPixels() || !size) {
+ inputUnion = requestedRect;
+ } else {
+ // Rect may have inflated. Re-intersect with request.
+ inputUnion.intersect(requestedRect);
+ }
+ addAbsolutePaintRect(inputUnion);
+ return inputUnion;
}
FloatRect FilterEffect::mapRectRecursive(const FloatRect& rect)
@@ -94,7 +117,7 @@ FloatRect FilterEffect::getSourceRect(const FloatRect& destRect, const FloatRect
FloatRect sourceRect = mapRect(destRect, false);
FloatRect sourceClipRect = mapRect(destClipRect, false);
- FloatRect boundaries = effectBoundaries();
+ FloatRect boundaries = filter()->mapLocalRectToAbsoluteRect(effectBoundaries());
if (hasX())
sourceClipRect.setX(boundaries.x());
if (hasY())
@@ -136,14 +159,33 @@ FilterEffect* FilterEffect::inputEffect(unsigned number) const
return m_inputEffects.at(number).get();
}
+void FilterEffect::addAbsolutePaintRect(const FloatRect& paintRect)
+{
+ IntRect intPaintRect(enclosingIntRect(paintRect));
+ if (m_absolutePaintRect.contains(intPaintRect))
+ return;
+ intPaintRect.unite(m_absolutePaintRect);
+ // Make sure we are not holding on to a smaller rendering.
+ clearResult();
+ m_absolutePaintRect = intPaintRect;
+}
+
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();
+}
+
+void FilterEffect::applyRecursive()
+{
if (hasResult())
return;
unsigned size = m_inputEffects.size();
for (unsigned i = 0; i < size; ++i) {
FilterEffect* in = m_inputEffects.at(i).get();
- in->apply();
+ in->applyRecursive();
if (!in->hasResult())
return;
@@ -151,20 +193,16 @@ void FilterEffect::apply()
transformResultColorSpace(in, i);
}
- determineAbsolutePaintRect();
setResultColorSpace(m_operatingColorSpace);
if (!isFilterSizeValid(m_absolutePaintRect))
return;
- if (requiresValidPreMultipliedPixels()) {
+ if (!mayProduceInvalidPreMultipliedPixels()) {
for (unsigned i = 0; i < size; ++i)
inputEffect(i)->correctFilterResultIfNeeded();
}
- if (applySkia())
- return;
-
applySoftware();
}
@@ -225,6 +263,12 @@ void FilterEffect::clearResult()
m_unmultipliedImageResult.clear();
if (m_premultipliedImageResult)
m_premultipliedImageResult.clear();
+
+ m_absolutePaintRect = IntRect();
+ for (int i = 0; i < 4; i++) {
+ filter()->removeFromCache(m_imageFilters[i].get());
+ m_imageFilters[i] = nullptr;
+ }
}
void FilterEffect::clearResultsRecursive()
@@ -246,10 +290,7 @@ ImageBuffer* FilterEffect::asImageBuffer()
if (m_imageBufferResult)
return m_imageBufferResult.get();
OwnPtr<ImageBufferSurface> surface;
- if (m_filter->isAccelerated())
- surface = adoptPtr(new AcceleratedImageBufferSurface(m_absolutePaintRect.size()));
- if (!m_filter->isAccelerated() || !surface->isValid())
- surface = adoptPtr(new UnacceleratedImageBufferSurface(m_absolutePaintRect.size()));
+ surface = adoptPtr(new UnacceleratedImageBufferSurface(m_absolutePaintRect.size()));
m_imageBufferResult = ImageBuffer::create(surface.release());
if (!m_imageBufferResult)
return 0;
@@ -387,13 +428,11 @@ void FilterEffect::copyPremultipliedImage(Uint8ClampedArray* destination, const
ImageBuffer* FilterEffect::createImageBufferResult()
{
// Only one result type is allowed.
- if (m_absolutePaintRect.isEmpty())
- return 0;
+ ASSERT(!hasResult());
+ ASSERT(isFilterSizeValid(m_absolutePaintRect));
+
OwnPtr<ImageBufferSurface> surface;
- if (m_filter->isAccelerated())
- surface = adoptPtr(new AcceleratedImageBufferSurface(m_absolutePaintRect.size()));
- if (!m_filter->isAccelerated() || !surface->isValid())
- surface = adoptPtr(new UnacceleratedImageBufferSurface(m_absolutePaintRect.size()));
+ surface = adoptPtr(new UnacceleratedImageBufferSurface(m_absolutePaintRect.size()));
m_imageBufferResult = ImageBuffer::create(surface.release());
return m_imageBufferResult.get();
}
@@ -422,6 +461,12 @@ Uint8ClampedArray* FilterEffect::createPremultipliedImageResult()
return m_premultipliedImageResult.get();
}
+Color FilterEffect::adaptColorToOperatingColorSpace(const Color& deviceColor)
+{
+ // |deviceColor| is assumed to be DeviceRGB.
+ return ColorSpaceUtilities::convertColor(deviceColor, operatingColorSpace());
+}
+
void FilterEffect::transformResultColorSpace(ColorSpace dstColorSpace)
{
if (!hasResult() || dstColorSpace == m_resultColorSpace)
@@ -448,7 +493,8 @@ TextStream& FilterEffect::externalRepresentation(TextStream& ts, int) const
FloatRect FilterEffect::determineFilterPrimitiveSubregion(DetermineSubregionFlags flags)
{
- ASSERT(filter());
+ Filter* filter = this->filter();
+ ASSERT(filter);
// FETile, FETurbulence, FEFlood don't have input effects, take the filter region as unite rect.
FloatRect subregion;
@@ -456,15 +502,19 @@ FloatRect FilterEffect::determineFilterPrimitiveSubregion(DetermineSubregionFlag
subregion = inputEffect(0)->determineFilterPrimitiveSubregion(flags);
for (unsigned i = 1; i < numberOfInputEffects; ++i)
subregion.unite(inputEffect(i)->determineFilterPrimitiveSubregion(flags));
- } else
- subregion = filter()->filterRegion();
+ } else {
+ subregion = filter->filterRegion();
+ }
// After calling determineFilterPrimitiveSubregion on the target effect, reset the subregion again for <feTile>.
if (filterEffectType() == FilterEffectTypeTile)
- subregion = filter()->filterRegion();
+ subregion = filter->filterRegion();
- if (flags & MapRectForward)
- subregion = mapRect(subregion);
+ if (flags & MapRectForward) {
+ // mapRect works on absolute rectangles.
+ subregion = filter->mapAbsoluteRectToLocalRect(mapRect(
+ filter->mapLocalRectToAbsoluteRect(subregion)));
+ }
FloatRect boundaries = effectBoundaries();
if (hasX())
@@ -478,15 +528,11 @@ FloatRect FilterEffect::determineFilterPrimitiveSubregion(DetermineSubregionFlag
setFilterPrimitiveSubregion(subregion);
- FloatRect absoluteSubregion = filter()->absoluteTransform().mapRect(subregion);
- FloatSize filterResolution = filter()->filterResolution();
- absoluteSubregion.scale(filterResolution.width(), filterResolution.height());
+ FloatRect absoluteSubregion = filter->mapLocalRectToAbsoluteRect(subregion);
// Clip every filter effect to the filter region.
if (flags & ClipToFilterRegion) {
- FloatRect absoluteScaledFilterRegion = filter()->absoluteFilterRegion();
- absoluteScaledFilterRegion.scale(filterResolution.width(), filterResolution.height());
- absoluteSubregion.intersect(absoluteScaledFilterRegion);
+ absoluteSubregion.intersect(filter->absoluteFilterRegion());
}
setMaxEffectRect(absoluteSubregion);
@@ -495,34 +541,63 @@ FloatRect FilterEffect::determineFilterPrimitiveSubregion(DetermineSubregionFlag
PassRefPtr<SkImageFilter> FilterEffect::createImageFilter(SkiaImageFilterBuilder* builder)
{
- return 0;
+ return nullptr;
+}
+
+PassRefPtr<SkImageFilter> FilterEffect::createImageFilterWithoutValidation(SkiaImageFilterBuilder* builder)
+{
+ return createImageFilter(builder);
}
SkImageFilter::CropRect FilterEffect::getCropRect(const FloatSize& cropOffset) const
{
- SkRect rect = SkRect::MakeEmpty();
+ FloatRect rect = filter()->filterRegion();
uint32_t flags = 0;
FloatRect boundaries = effectBoundaries();
- FloatSize resolution = filter()->filterResolution();
- boundaries.scale(resolution.width(), resolution.height());
boundaries.move(cropOffset);
if (hasX()) {
- rect.fLeft = boundaries.x();
+ rect.setX(boundaries.x());
flags |= SkImageFilter::CropRect::kHasLeft_CropEdge;
+ flags |= SkImageFilter::CropRect::kHasRight_CropEdge;
}
if (hasY()) {
- rect.fTop = boundaries.y();
+ rect.setY(boundaries.y());
flags |= SkImageFilter::CropRect::kHasTop_CropEdge;
+ flags |= SkImageFilter::CropRect::kHasBottom_CropEdge;
}
if (hasWidth()) {
- rect.fRight = rect.fLeft + boundaries.width();
+ rect.setWidth(boundaries.width());
flags |= SkImageFilter::CropRect::kHasRight_CropEdge;
}
if (hasHeight()) {
- rect.fBottom = rect.fTop + boundaries.height();
+ rect.setHeight(boundaries.height());
flags |= SkImageFilter::CropRect::kHasBottom_CropEdge;
}
+ rect = filter()->mapLocalRectToAbsoluteRect(rect);
return SkImageFilter::CropRect(rect, flags);
}
+static int getImageFilterIndex(ColorSpace colorSpace, bool requiresPMColorValidation)
+{
+ // Map the (colorspace, bool) tuple to an integer index as follows:
+ // 0 == linear colorspace, no PM validation
+ // 1 == device colorspace, no PM validation
+ // 2 == linear colorspace, PM validation
+ // 3 == device colorspace, PM validation
+ return (colorSpace == ColorSpaceLinearRGB ? 0x1 : 0x0) | (requiresPMColorValidation ? 0x2 : 0x0);
+}
+
+SkImageFilter* FilterEffect::getImageFilter(ColorSpace colorSpace, bool requiresPMColorValidation) const
+{
+ int index = getImageFilterIndex(colorSpace, requiresPMColorValidation);
+ return m_imageFilters[index].get();
+}
+
+void FilterEffect::setImageFilter(ColorSpace colorSpace, bool requiresPMColorValidation, PassRefPtr<SkImageFilter> imageFilter)
+{
+ int index = getImageFilterIndex(colorSpace, requiresPMColorValidation);
+ filter()->removeFromCache(m_imageFilters[index].get());
+ m_imageFilters[index] = imageFilter;
+}
+
} // namespace WebCore