summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics/filters/FilterEffect.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/platform/graphics/filters/FilterEffect.cpp')
-rw-r--r--Source/WebCore/platform/graphics/filters/FilterEffect.cpp296
1 files changed, 103 insertions, 193 deletions
diff --git a/Source/WebCore/platform/graphics/filters/FilterEffect.cpp b/Source/WebCore/platform/graphics/filters/FilterEffect.cpp
index 5dd065d98..1dcb0cb06 100644
--- a/Source/WebCore/platform/graphics/filters/FilterEffect.cpp
+++ b/Source/WebCore/platform/graphics/filters/FilterEffect.cpp
@@ -3,6 +3,7 @@
* Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
* Copyright (C) Research In Motion Limited 2010. All rights reserved.
* Copyright (C) 2012 University of Szeged
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -21,14 +22,14 @@
*/
#include "config.h"
-
-#if ENABLE(FILTERS)
#include "FilterEffect.h"
#include "Filter.h"
#include "ImageBuffer.h"
#include "TextStream.h"
-#include <wtf/Uint8ClampedArray.h>
+#include <runtime/JSCInlines.h>
+#include <runtime/TypedArrayInlines.h>
+#include <runtime/Uint8ClampedArray.h>
#if HAVE(ARM_NEON_INTRINSICS)
#include <arm_neon.h>
@@ -36,7 +37,7 @@
namespace WebCore {
-FilterEffect::FilterEffect(Filter* filter)
+FilterEffect::FilterEffect(Filter& filter)
: m_alphaImage(false)
, m_filter(filter)
, m_hasX(false)
@@ -45,36 +46,29 @@ FilterEffect::FilterEffect(Filter* filter)
, m_hasHeight(false)
, m_clipsToBounds(true)
, m_operatingColorSpace(ColorSpaceLinearRGB)
- , m_resultColorSpace(ColorSpaceDeviceRGB)
+ , m_resultColorSpace(ColorSpaceSRGB)
{
- ASSERT(m_filter);
}
FilterEffect::~FilterEffect()
{
}
-inline bool isFilterSizeValid(IntRect rect)
+void FilterEffect::determineAbsolutePaintRect()
{
- if (rect.width() < 0 || rect.width() > kMaxFilterSize
- || rect.height() < 0 || rect.height() > kMaxFilterSize)
- return false;
- return true;
+ m_absolutePaintRect = IntRect();
+ for (auto& effect : m_inputEffects)
+ m_absolutePaintRect.unite(effect->absolutePaintRect());
+ clipAbsolutePaintRect();
}
-void FilterEffect::determineAbsolutePaintRect()
+void FilterEffect::clipAbsolutePaintRect()
{
- m_absolutePaintRect = IntRect();
- unsigned size = m_inputEffects.size();
- for (unsigned i = 0; i < size; ++i)
- m_absolutePaintRect.unite(m_inputEffects.at(i)->absolutePaintRect());
-
// 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));
-
}
IntRect FilterEffect::requestedRegionOfInputImageData(const IntRect& effectRect) const
@@ -85,10 +79,16 @@ IntRect FilterEffect::requestedRegionOfInputImageData(const IntRect& effectRect)
return IntRect(location, m_absolutePaintRect.size());
}
-IntRect FilterEffect::drawingRegionOfInputImage(const IntRect& srcRect) const
+FloatRect FilterEffect::drawingRegionOfInputImage(const IntRect& srcRect) const
{
- return IntRect(IntPoint(srcRect.x() - m_absolutePaintRect.x(),
- srcRect.y() - m_absolutePaintRect.y()), srcRect.size());
+ ASSERT(hasResult());
+
+ FloatSize scale;
+ ImageBuffer::clampedSize(m_absolutePaintRect.size(), scale);
+
+ AffineTransform transform;
+ transform.scale(scale).translate(-m_absolutePaintRect.location());
+ return transform.mapRect(srcRect);
}
FilterEffect* FilterEffect::inputEffect(unsigned number) const
@@ -97,23 +97,22 @@ FilterEffect* FilterEffect::inputEffect(unsigned number) const
return m_inputEffects.at(number).get();
}
-#if ENABLE(OPENCL)
-void FilterEffect::applyAll()
+static unsigned collectEffects(const FilterEffect*effect, HashSet<const FilterEffect*>& allEffects)
{
- if (hasResult())
- return;
- FilterContextOpenCL* context = FilterContextOpenCL::context();
- if (context) {
- apply();
- if (!context->inError())
- return;
- clearResultsRecursive();
- context->destroyContext();
+ allEffects.add(effect);
+ unsigned size = effect->numberOfEffectInputs();
+ for (unsigned i = 0; i < size; ++i) {
+ FilterEffect* in = effect->inputEffect(i);
+ collectEffects(in, allEffects);
}
- // Software code path.
- apply();
+ return allEffects.size();
+}
+
+unsigned FilterEffect::totalNumberOfEffectInputs() const
+{
+ HashSet<const FilterEffect*> allEffects;
+ return collectEffects(this, allEffects);
}
-#endif
void FilterEffect::apply()
{
@@ -133,7 +132,7 @@ void FilterEffect::apply()
determineAbsolutePaintRect();
setResultColorSpace(m_operatingColorSpace);
- if (!isFilterSizeValid(m_absolutePaintRect))
+ if (m_absolutePaintRect.isEmpty() || ImageBuffer::sizeNeedsClamping(m_absolutePaintRect.size()))
return;
if (requiresValidPreMultipliedPixels()) {
@@ -142,38 +141,9 @@ void FilterEffect::apply()
}
// Add platform specific apply functions here and return earlier.
-#if ENABLE(OPENCL)
- if (platformApplyOpenCL())
- return;
-#endif
platformApplySoftware();
}
-#if ENABLE(OPENCL)
-// This function will be changed to abstract virtual when all filters are landed.
-bool FilterEffect::platformApplyOpenCL()
-{
- if (!FilterContextOpenCL::context())
- return false;
-
- unsigned size = m_inputEffects.size();
- for (unsigned i = 0; i < size; ++i) {
- FilterEffect* in = m_inputEffects.at(i).get();
- // Software code path expects that at least one of the following fileds is valid.
- if (!in->m_imageBufferResult && !in->m_unmultipliedImageResult && !in->m_premultipliedImageResult)
- in->asImageBuffer();
- }
-
- platformApplySoftware();
- ImageBuffer* sourceImage = asImageBuffer();
- if (sourceImage) {
- RefPtr<Uint8ClampedArray> sourceImageData = sourceImage->getUnmultipliedImageData(IntRect(IntPoint(), sourceImage->internalSize()));
- createOpenCLImageResult(sourceImageData->data());
- }
- return true;
-}
-#endif
-
void FilterEffect::forceValidPreMultipliedPixels()
{
// Must operate on pre-multiplied results; other formats cannot have invalid pixels.
@@ -226,15 +196,11 @@ void FilterEffect::forceValidPreMultipliedPixels()
void FilterEffect::clearResult()
{
if (m_imageBufferResult)
- m_imageBufferResult.clear();
+ m_imageBufferResult.reset();
if (m_unmultipliedImageResult)
- m_unmultipliedImageResult.clear();
+ m_unmultipliedImageResult = nullptr;
if (m_premultipliedImageResult)
- m_premultipliedImageResult.clear();
-#if ENABLE(OPENCL)
- if (m_openCLImageResult)
- m_openCLImageResult.clear();
-#endif
+ m_premultipliedImageResult = nullptr;
}
void FilterEffect::clearResultsRecursive()
@@ -252,14 +218,13 @@ void FilterEffect::clearResultsRecursive()
ImageBuffer* FilterEffect::asImageBuffer()
{
if (!hasResult())
- return 0;
+ return nullptr;
if (m_imageBufferResult)
return m_imageBufferResult.get();
-#if ENABLE(OPENCL)
- if (m_openCLImageResult)
- return openCLImageToImageBuffer();
-#endif
- m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), 1, m_resultColorSpace, m_filter->renderingMode());
+ m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), m_filter.renderingMode(), m_filter.filterScale(), m_resultColorSpace);
+ if (!m_imageBufferResult)
+ return nullptr;
+
IntRect destinationRect(IntPoint(), m_absolutePaintRect.size());
if (m_premultipliedImageResult)
m_imageBufferResult->putByteArray(Premultiplied, m_premultipliedImageResult.get(), destinationRect.size(), destinationRect, IntPoint());
@@ -268,85 +233,66 @@ ImageBuffer* FilterEffect::asImageBuffer()
return m_imageBufferResult.get();
}
-#if ENABLE(OPENCL)
-ImageBuffer* FilterEffect::openCLImageToImageBuffer()
-{
- FilterContextOpenCL* context = FilterContextOpenCL::context();
- ASSERT(context);
-
- if (context->inError())
- return 0;
-
- size_t origin[3] = { 0, 0, 0 };
- size_t region[3] = { m_absolutePaintRect.width(), m_absolutePaintRect.height(), 1 };
-
- RefPtr<Uint8ClampedArray> destinationPixelArray = Uint8ClampedArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
-
- if (context->isFailed(clFinish(context->commandQueue())))
- return 0;
-
- if (context->isFailed(clEnqueueReadImage(context->commandQueue(), m_openCLImageResult, CL_TRUE, origin, region, 0, 0, destinationPixelArray->data(), 0, 0, 0)))
- return 0;
-
- m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size());
- IntRect destinationRect(IntPoint(), m_absolutePaintRect.size());
- m_imageBufferResult->putByteArray(Unmultiplied, destinationPixelArray.get(), destinationRect.size(), destinationRect, IntPoint());
-
- return m_imageBufferResult.get();
-}
-#endif
-
PassRefPtr<Uint8ClampedArray> FilterEffect::asUnmultipliedImage(const IntRect& rect)
{
- ASSERT(isFilterSizeValid(rect));
- RefPtr<Uint8ClampedArray> imageData = Uint8ClampedArray::createUninitialized(rect.width() * rect.height() * 4);
+ IntSize scaledSize(rect.size());
+ ASSERT(!ImageBuffer::sizeNeedsClamping(scaledSize));
+ scaledSize.scale(m_filter.filterScale());
+ RefPtr<Uint8ClampedArray> imageData = Uint8ClampedArray::createUninitialized(scaledSize.width() * scaledSize.height() * 4);
copyUnmultipliedImage(imageData.get(), rect);
return imageData.release();
}
PassRefPtr<Uint8ClampedArray> FilterEffect::asPremultipliedImage(const IntRect& rect)
{
- ASSERT(isFilterSizeValid(rect));
- RefPtr<Uint8ClampedArray> imageData = Uint8ClampedArray::createUninitialized(rect.width() * rect.height() * 4);
+ IntSize scaledSize(rect.size());
+ ASSERT(!ImageBuffer::sizeNeedsClamping(scaledSize));
+ scaledSize.scale(m_filter.filterScale());
+ RefPtr<Uint8ClampedArray> imageData = Uint8ClampedArray::createUninitialized(scaledSize.width() * scaledSize.height() * 4);
copyPremultipliedImage(imageData.get(), rect);
return imageData.release();
}
inline void FilterEffect::copyImageBytes(Uint8ClampedArray* source, Uint8ClampedArray* destination, const IntRect& rect)
{
+ IntRect scaledRect(rect);
+ scaledRect.scale(m_filter.filterScale());
+ IntSize scaledPaintSize(m_absolutePaintRect.size());
+ scaledPaintSize.scale(m_filter.filterScale());
+
// Initialize the destination to transparent black, if not entirely covered by the source.
- if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > m_absolutePaintRect.width() || rect.maxY() > m_absolutePaintRect.height())
+ if (scaledRect.x() < 0 || scaledRect.y() < 0 || scaledRect.maxX() > scaledPaintSize.width() || scaledRect.maxY() > scaledPaintSize.height())
memset(destination->data(), 0, destination->length());
// Early return if the rect does not intersect with the source.
- if (rect.maxX() <= 0 || rect.maxY() <= 0 || rect.x() >= m_absolutePaintRect.width() || rect.y() >= m_absolutePaintRect.height())
+ if (scaledRect.maxX() <= 0 || scaledRect.maxY() <= 0 || scaledRect.x() >= scaledPaintSize.width() || scaledRect.y() >= scaledPaintSize.height())
return;
- int xOrigin = rect.x();
+ int xOrigin = scaledRect.x();
int xDest = 0;
if (xOrigin < 0) {
xDest = -xOrigin;
xOrigin = 0;
}
- int xEnd = rect.maxX();
- if (xEnd > m_absolutePaintRect.width())
- xEnd = m_absolutePaintRect.width();
+ int xEnd = scaledRect.maxX();
+ if (xEnd > scaledPaintSize.width())
+ xEnd = scaledPaintSize.width();
- int yOrigin = rect.y();
+ int yOrigin = scaledRect.y();
int yDest = 0;
if (yOrigin < 0) {
yDest = -yOrigin;
yOrigin = 0;
}
- int yEnd = rect.maxY();
- if (yEnd > m_absolutePaintRect.height())
- yEnd = m_absolutePaintRect.height();
+ int yEnd = scaledRect.maxY();
+ if (yEnd > scaledPaintSize.height())
+ yEnd = scaledPaintSize.height();
int size = (xEnd - xOrigin) * 4;
- int destinationScanline = rect.width() * 4;
- int sourceScanline = m_absolutePaintRect.width() * 4;
- unsigned char *destinationPixel = destination->data() + ((yDest * rect.width()) + xDest) * 4;
- unsigned char *sourcePixel = source->data() + ((yOrigin * m_absolutePaintRect.width()) + xOrigin) * 4;
+ int destinationScanline = scaledRect.width() * 4;
+ int sourceScanline = scaledPaintSize.width() * 4;
+ unsigned char *destinationPixel = destination->data() + ((yDest * scaledRect.width()) + xDest) * 4;
+ unsigned char *sourcePixel = source->data() + ((yOrigin * scaledPaintSize.width()) + xOrigin) * 4;
while (yOrigin < yEnd) {
memcpy(destinationPixel, sourcePixel, size);
@@ -365,11 +311,13 @@ void FilterEffect::copyUnmultipliedImage(Uint8ClampedArray* destination, const I
if (m_imageBufferResult)
m_unmultipliedImageResult = m_imageBufferResult->getUnmultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size()));
else {
- ASSERT(isFilterSizeValid(m_absolutePaintRect));
- m_unmultipliedImageResult = Uint8ClampedArray::createUninitialized(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
+ IntSize inputSize(m_absolutePaintRect.size());
+ ASSERT(!ImageBuffer::sizeNeedsClamping(inputSize));
+ inputSize.scale(m_filter.filterScale());
+ m_unmultipliedImageResult = Uint8ClampedArray::createUninitialized(inputSize.width() * inputSize.height() * 4);
unsigned char* sourceComponent = m_premultipliedImageResult->data();
unsigned char* destinationComponent = m_unmultipliedImageResult->data();
- unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
+ unsigned char* end = sourceComponent + (inputSize.width() * inputSize.height() * 4);
while (sourceComponent < end) {
int alpha = sourceComponent[3];
if (alpha) {
@@ -399,11 +347,13 @@ void FilterEffect::copyPremultipliedImage(Uint8ClampedArray* destination, const
if (m_imageBufferResult)
m_premultipliedImageResult = m_imageBufferResult->getPremultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size()));
else {
- ASSERT(isFilterSizeValid(m_absolutePaintRect));
- m_premultipliedImageResult = Uint8ClampedArray::createUninitialized(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
+ IntSize inputSize(m_absolutePaintRect.size());
+ ASSERT(!ImageBuffer::sizeNeedsClamping(inputSize));
+ inputSize.scale(m_filter.filterScale());
+ m_premultipliedImageResult = Uint8ClampedArray::createUninitialized(inputSize.width() * inputSize.height() * 4);
unsigned char* sourceComponent = m_unmultipliedImageResult->data();
unsigned char* destinationComponent = m_premultipliedImageResult->data();
- unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
+ unsigned char* end = sourceComponent + (inputSize.width() * inputSize.height() * 4);
while (sourceComponent < end) {
int alpha = sourceComponent[3];
destinationComponent[0] = static_cast<int>(sourceComponent[0]) * alpha / 255;
@@ -423,11 +373,13 @@ ImageBuffer* FilterEffect::createImageBufferResult()
// Only one result type is allowed.
ASSERT(!hasResult());
if (m_absolutePaintRect.isEmpty())
- return 0;
- m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), 1, m_resultColorSpace, m_filter->renderingMode());
+ return nullptr;
+
+ FloatSize clampedSize = ImageBuffer::clampedSize(m_absolutePaintRect.size());
+ m_imageBufferResult = ImageBuffer::create(clampedSize, m_filter.renderingMode(), m_filter.filterScale(), m_resultColorSpace);
if (!m_imageBufferResult)
- return 0;
- ASSERT(m_imageBufferResult->context());
+ return nullptr;
+
return m_imageBufferResult.get();
}
@@ -435,11 +387,13 @@ Uint8ClampedArray* FilterEffect::createUnmultipliedImageResult()
{
// Only one result type is allowed.
ASSERT(!hasResult());
- ASSERT(isFilterSizeValid(m_absolutePaintRect));
-
if (m_absolutePaintRect.isEmpty())
- return 0;
- m_unmultipliedImageResult = Uint8ClampedArray::createUninitialized(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
+ return nullptr;
+
+ IntSize resultSize(m_absolutePaintRect.size());
+ ASSERT(!ImageBuffer::sizeNeedsClamping(resultSize));
+ resultSize.scale(m_filter.filterScale());
+ m_unmultipliedImageResult = Uint8ClampedArray::createUninitialized(resultSize.width() * resultSize.height() * 4);
return m_unmultipliedImageResult.get();
}
@@ -447,43 +401,15 @@ Uint8ClampedArray* FilterEffect::createPremultipliedImageResult()
{
// Only one result type is allowed.
ASSERT(!hasResult());
- ASSERT(isFilterSizeValid(m_absolutePaintRect));
-
if (m_absolutePaintRect.isEmpty())
- return 0;
- m_premultipliedImageResult = Uint8ClampedArray::createUninitialized(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
- return m_premultipliedImageResult.get();
-}
-
-#if ENABLE(OPENCL)
-OpenCLHandle FilterEffect::createOpenCLImageResult(uint8_t* source)
-{
- FilterContextOpenCL* context = FilterContextOpenCL::context();
- ASSERT(context);
-
- if (context->inError())
- return 0;
-
- ASSERT(!hasResult());
- cl_image_format clImageFormat;
- clImageFormat.image_channel_order = CL_RGBA;
- clImageFormat.image_channel_data_type = CL_UNORM_INT8;
-
- int errorCode = 0;
-#ifdef CL_API_SUFFIX__VERSION_1_2
- cl_image_desc imageDescriptor = { CL_MEM_OBJECT_IMAGE2D, m_absolutePaintRect.width(), m_absolutePaintRect.height(), 0, 0, 0, 0, 0, 0, 0};
- m_openCLImageResult = clCreateImage(context->deviceContext(), CL_MEM_READ_WRITE | (source ? CL_MEM_COPY_HOST_PTR : 0),
- &clImageFormat, &imageDescriptor, source, &errorCode);
-#else
- m_openCLImageResult = clCreateImage2D(context->deviceContext(), CL_MEM_READ_WRITE | (source ? CL_MEM_COPY_HOST_PTR : 0),
- &clImageFormat, m_absolutePaintRect.width(), m_absolutePaintRect.height(), 0, source, &errorCode);
-#endif
- if (context->isFailed(errorCode))
- return 0;
+ return nullptr;
- return m_openCLImageResult;
+ IntSize resultSize(m_absolutePaintRect.size());
+ ASSERT(!ImageBuffer::sizeNeedsClamping(resultSize));
+ resultSize.scale(m_filter.filterScale());
+ m_premultipliedImageResult = Uint8ClampedArray::createUninitialized(resultSize.width() * resultSize.height() * 4);
+ return m_premultipliedImageResult.get();
}
-#endif
void FilterEffect::transformResultColorSpace(ColorSpace dstColorSpace)
{
@@ -494,30 +420,16 @@ void FilterEffect::transformResultColorSpace(ColorSpace dstColorSpace)
if (!hasResult() || dstColorSpace == m_resultColorSpace)
return;
-#if ENABLE(OPENCL)
- if (openCLImage()) {
- if (m_imageBufferResult)
- m_imageBufferResult.clear();
- FilterContextOpenCL* context = FilterContextOpenCL::context();
- ASSERT(context);
- context->openCLTransformColorSpace(m_openCLImageResult, absolutePaintRect(), m_resultColorSpace, dstColorSpace);
- } else {
-#endif
-
- // FIXME: We can avoid this potentially unnecessary ImageBuffer conversion by adding
- // color space transform support for the {pre,un}multiplied arrays.
- asImageBuffer()->transformColorSpace(m_resultColorSpace, dstColorSpace);
-
-#if ENABLE(OPENCL)
- }
-#endif
+ // FIXME: We can avoid this potentially unnecessary ImageBuffer conversion by adding
+ // color space transform support for the {pre,un}multiplied arrays.
+ asImageBuffer()->transformColorSpace(m_resultColorSpace, dstColorSpace);
m_resultColorSpace = dstColorSpace;
if (m_unmultipliedImageResult)
- m_unmultipliedImageResult.clear();
+ m_unmultipliedImageResult = nullptr;
if (m_premultipliedImageResult)
- m_premultipliedImageResult.clear();
+ m_premultipliedImageResult = nullptr;
#endif
}
@@ -529,5 +441,3 @@ TextStream& FilterEffect::externalRepresentation(TextStream& ts, int) const
}
} // namespace WebCore
-
-#endif // ENABLE(FILTERS)