diff options
author | Konstantin Tokarev <annulen@yandex.ru> | 2016-08-25 19:20:41 +0300 |
---|---|---|
committer | Konstantin Tokarev <annulen@yandex.ru> | 2017-02-02 12:30:55 +0000 |
commit | 6882a04fb36642862b11efe514251d32070c3d65 (patch) | |
tree | b7959826000b061fd5ccc7512035c7478742f7b0 /Source/WebCore/platform/graphics/filters/FilterEffect.cpp | |
parent | ab6df191029eeeb0b0f16f127d553265659f739e (diff) |
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f
Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/WebCore/platform/graphics/filters/FilterEffect.cpp')
-rw-r--r-- | Source/WebCore/platform/graphics/filters/FilterEffect.cpp | 296 |
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) |