Diff
Modified: trunk/Source/WebCore/ChangeLog (286128 => 286129)
--- trunk/Source/WebCore/ChangeLog 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/ChangeLog 2021-11-23 09:22:16 UTC (rev 286129)
@@ -1,3 +1,152 @@
+2021-11-23 Said Abou-Hallawa <[email protected]>
+
+ [GPU Process] Refactor the FilterEffect result buffers into a new class named 'FilterImage'
+ https://bugs.webkit.org/show_bug.cgi?id=225088
+ rdar://77487760
+
+ Reviewed by Cameron McCormack.
+
+ Move the storage and the logic for managing the result of applying the
+ FilterEffect to its inputs to a new class named 'FilterImage'. This will
+ simplify the implementation of FilterEffect. It will also allow integrating
+ the CoreImage seamlessly and simplifying the geometry calculation.
+
+ Instead of having three ways to create the result of a FilterEffect, there
+ will be one way which is by calling FilterImage::create(). This call will
+ not create a concrete result. But requesting the ImageBuffer or a PixelBuffer
+ from FilterImage will make this creation happen
+
+ The default of the operating ColorSpace is sRGB. But it will be set to
+ linearRGB if the color interpolation of the filter effect element is
+ linearRGB. The only exception is the FEImage whose result has to be in
+ sRGB always.
+
+ The default value of the result ColorSpace is the operating ColorSpace.
+ The only exception is FEDisplacementMap whose result has to be in the
+ ColorSpace of its first input FilterEffect.
+
+ * Sources.txt:
+ * WebCore.xcodeproj/project.pbxproj:
+ * platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:
+ (WebCore::FilterEffectRendererCoreImage::connectCIFilters):
+ * platform/graphics/cpu/arm/filters/FEBlendNEON.h:
+ (WebCore::FEBlend::platformApplySoftware):
+ * platform/graphics/filters/FEBlend.cpp:
+ (WebCore::FEBlend::platformApplySoftware):
+ * platform/graphics/filters/FEColorMatrix.cpp:
+ (WebCore::FEColorMatrix::platformApplySoftware):
+ * platform/graphics/filters/FEComponentTransfer.cpp:
+ (WebCore::FEComponentTransfer::platformApplySoftware):
+ * platform/graphics/filters/FEComposite.cpp:
+ (WebCore::FEComposite::platformApplySoftware):
+ (WebCore::FEComposite::correctFilterResultIfNeeded): Deleted.
+ * platform/graphics/filters/FEComposite.h:
+ requiresValidPreMultipliedPixels() is replaced by the opposite
+ mayProduceInvalidPremultipliedPixels(). Correcting the premultiplied
+ result will be done by FilterEffect.
+
+ * platform/graphics/filters/FEConvolveMatrix.cpp:
+ (WebCore::FEConvolveMatrix::platformApplySoftware):
+ * platform/graphics/filters/FEDisplacementMap.cpp:
+ (WebCore::FEDisplacementMap::resultColorSpace const):
+ (WebCore::FEDisplacementMap::platformApplySoftware):
+ (WebCore::FEDisplacementMap::setResultColorSpace): Deleted.
+ * platform/graphics/filters/FEDisplacementMap.h:
+ (WebCore::FEDisplacementMap::xChannelIndex const):
+ (WebCore::FEDisplacementMap::yChannelIndex const):
+ * platform/graphics/filters/FEDropShadow.cpp:
+ (WebCore::FEDropShadow::platformApplySoftware):
+ * platform/graphics/filters/FEFlood.cpp:
+ (WebCore::FEFlood::platformApplySoftware):
+ * platform/graphics/filters/FEFlood.h:
+ * platform/graphics/filters/FEGaussianBlur.cpp:
+ (WebCore::FEGaussianBlur::platformApplySoftware):
+ * platform/graphics/filters/FELighting.cpp:
+ (WebCore::FELighting::platformApplySoftware):
+ * platform/graphics/filters/FEMerge.cpp:
+ (WebCore::FEMerge::platformApplySoftware):
+ * platform/graphics/filters/FEMorphology.cpp:
+ (WebCore::FEMorphology::platformApplySoftware):
+ * platform/graphics/filters/FEOffset.cpp:
+ (WebCore::FEOffset::platformApplySoftware):
+ * platform/graphics/filters/FETile.cpp:
+ (WebCore::FETile::platformApplySoftware):
+ * platform/graphics/filters/FETurbulence.cpp:
+ (WebCore::FETurbulence::platformApplySoftware):
+ * platform/graphics/filters/FilterEffect.cpp:
+ (WebCore::FilterEffect::apply):
+ (WebCore::FilterEffect::createResult):
+
+ (WebCore::FilterEffect::clearResult):
+ (WebCore::FilterEffect::clearResultsRecursive):
+ Clearing the result can be done by nullifying a single pointer.
+
+ (WebCore::FilterEffect::imageBufferResult):
+ (WebCore::FilterEffect::unpremultipliedResult):
+ (WebCore::FilterEffect::premultipliedResult):
+ (WebCore::FilterEffect::getUnpremultipliedResult):
+ (WebCore::FilterEffect::getPremultipliedResult):
+ (WebCore::FilterEffect::copyUnpremultipliedResult const):
+ (WebCore::FilterEffect::copyPremultipliedResult const):
+ (WebCore::FilterEffect::correctPremultipliedResultIfNeeded):
+ (WebCore::FilterEffect::transformResultColorSpace):
+ (WebCore::FilterEffect::externalRepresentation const):
+ (WebCore::FilterEffect::forceValidPreMultipliedPixels): Deleted.
+ (WebCore::FilterEffect::unmultipliedResult): Deleted.
+ (WebCore::FilterEffect::copyImageBytes const): Deleted.
+ (WebCore::copyPremultiplyingAlpha): Deleted.
+ (WebCore::copyUnpremultiplyingAlpha): Deleted.
+ (WebCore::FilterEffect::convertPixelBufferToColorSpace): Deleted.
+ (WebCore::FilterEffect::convertImageBufferToColorSpace): Deleted.
+ (WebCore::FilterEffect::copyConvertedImageBufferToDestination): Deleted.
+ (WebCore::FilterEffect::copyConvertedPixelBufferToDestination): Deleted.
+ (WebCore::FilterEffect::copyUnmultipliedResult): Deleted.
+ (WebCore::FilterEffect::copyPremultipliedResult): Deleted.
+ (WebCore::FilterEffect::createImageBufferResult): Deleted.
+ (WebCore::FilterEffect::createUnmultipliedImageResult): Deleted.
+ (WebCore::FilterEffect::createPremultipliedImageResult): Deleted.
+ (WebCore::FilterEffect::requiresPixelBufferColorSpaceConversion): Deleted.
+ All the logic of these functions was moved to FilterImage.cpp.
+
+ * platform/graphics/filters/FilterEffect.h:
+ (WebCore::FilterEffect::hasResult const):
+ (WebCore::FilterEffect::resultColorSpace const):
+ (WebCore::FilterEffect::mayProduceInvalidPremultipliedPixels const):
+ (WebCore::FilterEffect::correctFilterResultIfNeeded): Deleted.
+ (WebCore::FilterEffect::setResultColorSpace): Deleted.
+ (WebCore::FilterEffect::requiresValidPreMultipliedPixels): Deleted.
+ * platform/graphics/filters/FilterImage.cpp: Added.
+ (WebCore::FilterImage::create):
+ (WebCore::FilterImage::FilterImage):
+ (WebCore::FilterImage::imageBuffer):
+ (WebCore::copyPremultiplyingAlpha):
+ (WebCore::copyUnpremultiplyingAlpha):
+ (WebCore::FilterImage::pixelBufferIfExists):
+ (WebCore::FilterImage::pixelBuffer):
+ (WebCore::FilterImage::getPixelBuffer):
+ (WebCore::FilterImage::requiresPixelBufferColorSpaceConversion const):
+ (WebCore::FilterImage::copyImageBytes const):
+ (WebCore::FilterImage::getConvertedPixelBuffer const):
+ (WebCore::FilterImage::copyPixelBuffer):
+ (WebCore::FilterImage::correctPremultipliedPixelBuffer):
+ (WebCore::FilterImage::transformToColorSpace):
+ * platform/graphics/filters/FilterImage.h: Added.
+ (WebCore::FilterImage::absoluteImageRect const):
+ (WebCore::FilterImage::renderingMode const):
+ (WebCore::FilterImage::colorSpace const):
+ (WebCore::FilterImage::imageBufferIfExists):
+ * platform/graphics/filters/SourceAlpha.cpp:
+ (WebCore::SourceAlpha::platformApplySoftware):
+ * platform/graphics/filters/SourceGraphic.cpp:
+ (WebCore::SourceGraphic::platformApplySoftware):
+ * platform/graphics/filters/SourceGraphic.h:
+ (WebCore::SourceGraphic::SourceGraphic):
+ * rendering/svg/RenderSVGResourceFilter.cpp:
+ (WebCore::RenderSVGResourceFilter::postApplyResource):
+ * svg/graphics/filters/SVGFEImage.cpp:
+ (WebCore::FEImage::platformApplySoftware):
+ * svg/graphics/filters/SVGFEImage.h:
+
2021-11-22 Simon Fraser <[email protected]>
Have ScrollAnimator::scrollToPositionWithAnimation() take a clamping argument
Modified: trunk/Source/WebCore/Sources.txt (286128 => 286129)
--- trunk/Source/WebCore/Sources.txt 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/Sources.txt 2021-11-23 09:22:16 UTC (rev 286129)
@@ -2103,6 +2103,7 @@
platform/graphics/filters/FilterEffect.cpp
platform/graphics/filters/FilterEffectRenderer.cpp
platform/graphics/filters/FilterFunction.cpp
+platform/graphics/filters/FilterImage.cpp
platform/graphics/filters/FilterOperation.cpp
platform/graphics/filters/FilterOperations.cpp
platform/graphics/filters/PointLightSource.cpp
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (286128 => 286129)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2021-11-23 09:22:16 UTC (rev 286129)
@@ -10867,6 +10867,8 @@
721B496F2512AC0400FE9D3B /* ImageBitmapBacking.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ImageBitmapBacking.cpp; sourceTree = "<group>"; };
721B49702512AC0400FE9D3B /* ImageBitmapBacking.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImageBitmapBacking.h; sourceTree = "<group>"; };
722A815C238FD50500C00583 /* AnimationFrameRate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AnimationFrameRate.h; sourceTree = "<group>"; };
+ 72435EF4273D07670005E7EE /* FilterImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FilterImage.h; sourceTree = "<group>"; };
+ 72435EF5273D07670005E7EE /* FilterImage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FilterImage.cpp; sourceTree = "<group>"; };
724ED3291A3A7E5400F5F13C /* EXTBlendMinMax.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EXTBlendMinMax.cpp; sourceTree = "<group>"; };
724ED32A1A3A7E5400F5F13C /* EXTBlendMinMax.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EXTBlendMinMax.h; sourceTree = "<group>"; };
724ED32B1A3A7E5400F5F13C /* EXTBlendMinMax.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = EXTBlendMinMax.idl; sourceTree = "<group>"; };
@@ -25945,6 +25947,8 @@
7214B9B7274458FA003BE6DF /* FilterEffectVector.h */,
7262D757272A174100C56A09 /* FilterFunction.cpp */,
7262D756272A174100C56A09 /* FilterFunction.h */,
+ 72435EF5273D07670005E7EE /* FilterImage.cpp */,
+ 72435EF4273D07670005E7EE /* FilterImage.h */,
49ECEB631499790D00CDD3A4 /* FilterOperation.cpp */,
49ECEB641499790D00CDD3A4 /* FilterOperation.h */,
49ECEB651499790D00CDD3A4 /* FilterOperations.cpp */,
Modified: trunk/Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm 2021-11-23 09:22:16 UTC (rev 286129)
@@ -116,7 +116,6 @@
inputImages.append(inputImage);
}
effect.determineAbsolutePaintRect(filter);
- effect.setResultColorSpace(effect.operatingColorSpace());
if (effect.absolutePaintRect().isEmpty() || ImageBuffer::sizeNeedsClamping(effect.absolutePaintRect().size()))
return nullptr;
Modified: trunk/Source/WebCore/platform/graphics/cpu/arm/filters/FEBlendNEON.h (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/cpu/arm/filters/FEBlendNEON.h 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/cpu/arm/filters/FEBlendNEON.h 2021-11-23 09:22:16 UTC (rev 286129)
@@ -111,7 +111,7 @@
FilterEffect* in = inputEffect(0);
FilterEffect* in2 = inputEffect(1);
- auto& destinationPixelBuffer = createPremultipliedImageResult();
+ auto& destinationPixelBuffer = pixelBufferResult(AlphaPremultiplication::Premultiplied);
if (!destinationPixelBuffer)
return false;
@@ -118,10 +118,10 @@
auto& destinationPixelArray = destinationPixelBuffer->data();
IntRect effectADrawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect());
- auto sourcePixelArrayA = in->premultipliedResult(effectADrawingRect);
+ auto sourcePixelArrayA = in->getPixelBufferResult(AlphaPremultiplication::Premultiplied, effectADrawingRect);
IntRect effectBDrawingRect = requestedRegionOfInputPixelBuffer(in2->absolutePaintRect());
- auto sourcePixelArrayB = in2->premultipliedResult(effectBDrawingRect);
+ auto sourcePixelArrayB = in2->getPixelBufferResult(AlphaPremultiplication::Premultiplied, effectBDrawingRect);
unsigned sourcePixelArrayLength = sourcePixelArrayA->length();
ASSERT(pixelArrayLength == sourcePixelArrayB->length());
Modified: trunk/Source/WebCore/platform/graphics/filters/FEBlend.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FEBlend.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FEBlend.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -59,16 +59,16 @@
FilterEffect* in = inputEffect(0);
FilterEffect* in2 = inputEffect(1);
- ImageBuffer* resultImage = createImageBufferResult();
+ auto resultImage = imageBufferResult();
if (!resultImage)
return false;
- GraphicsContext& filterContext = resultImage->context();
- ImageBuffer* imageBuffer = in->imageBufferResult();
- ImageBuffer* imageBuffer2 = in2->imageBufferResult();
+ auto imageBuffer = in->imageBufferResult();
+ auto imageBuffer2 = in2->imageBufferResult();
if (!imageBuffer || !imageBuffer2)
return false;
+ GraphicsContext& filterContext = resultImage->context();
filterContext.drawImageBuffer(*imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()));
filterContext.drawImageBuffer(*imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()), { { }, imageBuffer->logicalSize() }, { CompositeOperator::SourceOver, m_mode });
return true;
Modified: trunk/Source/WebCore/platform/graphics/filters/FEColorMatrix.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FEColorMatrix.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FEColorMatrix.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -277,11 +277,11 @@
{
FilterEffect* in = inputEffect(0);
- ImageBuffer* resultImage = createImageBufferResult();
+ auto resultImage = imageBufferResult();
if (!resultImage)
return false;
- ImageBuffer* inBuffer = in->imageBufferResult();
+ auto inBuffer = in->imageBufferResult();
if (inBuffer)
resultImage->context().drawImageBuffer(*inBuffer, drawingRegionOfInputImage(in->absolutePaintRect()));
Modified: trunk/Source/WebCore/platform/graphics/filters/FEComponentTransfer.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FEComponentTransfer.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FEComponentTransfer.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -105,12 +105,10 @@
{
FilterEffect* in = inputEffect(0);
- auto& destinationPixelBuffer = createUnmultipliedImageResult();
+ auto destinationPixelBuffer = pixelBufferResult(AlphaPremultiplication::Unpremultiplied);
if (!destinationPixelBuffer)
return false;
- auto& destinationPixelArray = destinationPixelBuffer->data();
-
LookupTable redTable;
LookupTable greenTable;
LookupTable blueTable;
@@ -118,9 +116,12 @@
computeLookupTables(redTable, greenTable, blueTable, alphaTable);
IntRect drawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect());
- in->copyUnmultipliedResult(destinationPixelArray, drawingRect, operatingColorSpace());
+ in->copyPixelBufferResult(*destinationPixelBuffer, drawingRect);
+
+ auto& destinationPixelArray = destinationPixelBuffer->data();
+ uint8_t* data = ""
unsigned destinationPixelArrayLength = destinationPixelArray.length();
- uint8_t* data = ""
+
for (unsigned pixelOffset = 0; pixelOffset < destinationPixelArrayLength; pixelOffset += 4) {
data[pixelOffset] = redTable[data[pixelOffset]];
data[pixelOffset + 1] = greenTable[data[pixelOffset + 1]];
Modified: trunk/Source/WebCore/platform/graphics/filters/FEComposite.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FEComposite.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FEComposite.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -87,14 +87,6 @@
return true;
}
-void FEComposite::correctFilterResultIfNeeded()
-{
- if (m_type != FECOMPOSITE_OPERATOR_ARITHMETIC)
- return;
-
- forceValidPreMultipliedPixels();
-}
-
static unsigned char clampByte(int c)
{
unsigned char buff[] = { static_cast<unsigned char>(c), 255, 0 };
@@ -229,34 +221,35 @@
FilterEffect* in2 = inputEffect(1);
if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC) {
- auto& destinationPixelBuffer = createPremultipliedImageResult();
+ auto destinationPixelBuffer = pixelBufferResult(AlphaPremultiplication::Premultiplied);
if (!destinationPixelBuffer)
return false;
- auto& destinationPixelArray = destinationPixelBuffer->data();
-
IntRect effectADrawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect());
- auto sourcePixelArray = in->premultipliedResult(effectADrawingRect, operatingColorSpace());
- if (!sourcePixelArray)
+ auto sourcePixelBuffer = in->getPixelBufferResult(AlphaPremultiplication::Premultiplied, effectADrawingRect, operatingColorSpace());
+ if (!sourcePixelBuffer)
return false;
IntRect effectBDrawingRect = requestedRegionOfInputPixelBuffer(in2->absolutePaintRect());
- in2->copyPremultipliedResult(destinationPixelArray, effectBDrawingRect, operatingColorSpace());
+ in2->copyPixelBufferResult(*destinationPixelBuffer, effectBDrawingRect);
- platformArithmeticSoftware(*sourcePixelArray, destinationPixelArray, m_k1, m_k2, m_k3, m_k4);
+ auto& sourcePixelArray = sourcePixelBuffer->data();
+ auto& destinationPixelArray = destinationPixelBuffer->data();
+ platformArithmeticSoftware(sourcePixelArray, destinationPixelArray, m_k1, m_k2, m_k3, m_k4);
return true;
}
- ImageBuffer* resultImage = createImageBufferResult();
+ auto resultImage = imageBufferResult();
if (!resultImage)
return false;
- GraphicsContext& filterContext = resultImage->context();
- ImageBuffer* imageBuffer = in->imageBufferResult();
- ImageBuffer* imageBuffer2 = in2->imageBufferResult();
+ auto imageBuffer = in->imageBufferResult();
+ auto imageBuffer2 = in2->imageBufferResult();
if (!imageBuffer || !imageBuffer2)
return false;
+ GraphicsContext& filterContext = resultImage->context();
+
switch (m_type) {
case FECOMPOSITE_OPERATOR_OVER:
filterContext.drawImageBuffer(*imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()));
Modified: trunk/Source/WebCore/platform/graphics/filters/FEComposite.h (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FEComposite.h 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FEComposite.h 2021-11-23 09:22:16 UTC (rev 286129)
@@ -59,12 +59,10 @@
private:
FEComposite(const CompositeOperationType&, float k1, float k2, float k3, float k4);
- void correctFilterResultIfNeeded() override;
+ void determineAbsolutePaintRect(const Filter&) override;
- bool requiresValidPreMultipliedPixels() override { return m_type != FECOMPOSITE_OPERATOR_ARITHMETIC; }
+ bool mayProduceInvalidPremultipliedPixels() const override { return m_type == FECOMPOSITE_OPERATOR_ARITHMETIC; }
- void determineAbsolutePaintRect(const Filter&) override;
-
bool platformApplySoftware(const Filter&) override;
WTF::TextStream& externalRepresentation(WTF::TextStream&, RepresentationType) const override;
Modified: trunk/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -365,26 +365,23 @@
{
FilterEffect* in = inputEffect(0);
- auto& destinationPixelBuffer = m_preserveAlpha ? createUnmultipliedImageResult() : createPremultipliedImageResult();
+ auto alphaFormat = m_preserveAlpha ? AlphaPremultiplication::Unpremultiplied : AlphaPremultiplication::Premultiplied;
+ auto destinationPixelBuffer = pixelBufferResult(alphaFormat);
if (!destinationPixelBuffer)
return false;
- auto& destinationPixelArray = destinationPixelBuffer->data();
-
IntRect effectDrawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect());
-
- RefPtr<Uint8ClampedArray> sourcePixelArray;
- if (m_preserveAlpha)
- sourcePixelArray = in->unmultipliedResult(effectDrawingRect, operatingColorSpace());
- else
- sourcePixelArray = in->premultipliedResult(effectDrawingRect, operatingColorSpace());
- if (!sourcePixelArray)
+ auto sourcePixelBuffer = in->getPixelBufferResult(alphaFormat, effectDrawingRect, operatingColorSpace());
+ if (!sourcePixelBuffer)
return false;
+ auto& sourcePixelArray = sourcePixelBuffer->data();
+ auto& destinationPixelArray = destinationPixelBuffer->data();
+
IntSize paintSize = absolutePaintRect().size();
PaintingData paintingData = {
- *sourcePixelArray,
+ sourcePixelArray,
destinationPixelArray,
paintSize.width(),
paintSize.height(),
Modified: trunk/Source/WebCore/platform/graphics/filters/FEDisplacementMap.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FEDisplacementMap.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FEDisplacementMap.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -68,13 +68,13 @@
return true;
}
-void FEDisplacementMap::setResultColorSpace(const DestinationColorSpace&)
+const DestinationColorSpace& FEDisplacementMap::resultColorSpace() const
{
// Spec: The 'color-interpolation-filters' property only applies to the 'in2' source image
// and does not apply to the 'in' source image. The 'in' source image must remain in its
// current color space.
- // The result is in that smae color space because it is a displacement of the 'in' image.
- FilterEffect::setResultColorSpace(inputEffect(0)->resultColorSpace());
+ // The result is in that same color space because it is a displacement of the 'in' image.
+ return inputEffect(0)->resultColorSpace();
}
void FEDisplacementMap::transformResultColorSpace(FilterEffect* in, const int index)
@@ -98,7 +98,7 @@
ASSERT(m_xChannelSelector != CHANNEL_UNKNOWN);
ASSERT(m_yChannelSelector != CHANNEL_UNKNOWN);
- auto& destinationPixelBuffer = createPremultipliedImageResult();
+ auto destinationPixelBuffer = pixelBufferResult(AlphaPremultiplication::Premultiplied);
if (!destinationPixelBuffer)
return false;
@@ -105,16 +105,18 @@
auto& destinationPixelArray = destinationPixelBuffer->data();
IntRect effectADrawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect());
- auto inputImage = in->premultipliedResult(effectADrawingRect);
+ auto inputPixelBuffer = in->getPixelBufferResult(AlphaPremultiplication::Premultiplied, effectADrawingRect);
IntRect effectBDrawingRect = requestedRegionOfInputPixelBuffer(in2->absolutePaintRect());
// The calculations using the pixel values from ‘in2’ are performed using non-premultiplied color values.
- auto displacementImage = in2->unmultipliedResult(effectBDrawingRect);
+ auto displacementPixelBuffer = in2->getPixelBufferResult(AlphaPremultiplication::Unpremultiplied, effectBDrawingRect);
- if (!inputImage || !displacementImage)
+ if (!inputPixelBuffer || !displacementPixelBuffer)
return false;
- ASSERT(inputImage->length() == displacementImage->length());
+ auto& inputImage = inputPixelBuffer->data();
+ auto& displacementImage = displacementPixelBuffer->data();
+ ASSERT(inputImage.length() == displacementImage.length());
IntSize paintSize = absolutePaintRect().size();
@@ -135,8 +137,8 @@
for (int x = 0; x < paintSize.width(); ++x) {
int destinationIndex = lineStartOffset + x * 4;
- int srcX = x + static_cast<int>(scaleForColorX * displacementImage->item(destinationIndex + displacementChannelX) + scaledOffsetX);
- int srcY = y + static_cast<int>(scaleForColorY * displacementImage->item(destinationIndex + displacementChannelY) + scaledOffsetY);
+ int srcX = x + static_cast<int>(scaleForColorX * displacementImage.item(destinationIndex + displacementChannelX) + scaledOffsetX);
+ int srcY = y + static_cast<int>(scaleForColorY * displacementImage.item(destinationIndex + displacementChannelY) + scaledOffsetY);
unsigned* destinationPixelPtr = reinterpret_cast<unsigned*>(destinationPixelArray.data() + destinationIndex);
if (srcX < 0 || srcX >= paintSize.width() || srcY < 0 || srcY >= paintSize.height()) {
@@ -144,7 +146,7 @@
continue;
}
- *destinationPixelPtr = *reinterpret_cast<unsigned*>(inputImage->data() + byteOffsetOfPixel(srcX, srcY, rowBytes));
+ *destinationPixelPtr = *reinterpret_cast<unsigned*>(inputImage.data() + byteOffsetOfPixel(srcX, srcY, rowBytes));
}
}
Modified: trunk/Source/WebCore/platform/graphics/filters/FEDisplacementMap.h (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FEDisplacementMap.h 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FEDisplacementMap.h 2021-11-23 09:22:16 UTC (rev 286129)
@@ -47,19 +47,19 @@
float scale() const { return m_scale; }
bool setScale(float);
- void setResultColorSpace(const DestinationColorSpace&) override;
- void transformResultColorSpace(FilterEffect*, const int) override;
-
private:
FEDisplacementMap(ChannelSelectorType xChannelSelector, ChannelSelectorType yChannelSelector, float);
- bool platformApplySoftware(const Filter&) override;
+ int xChannelIndex() const { return m_xChannelSelector - 1; }
+ int yChannelIndex() const { return m_yChannelSelector - 1; }
void determineAbsolutePaintRect(const Filter&) override { setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); }
- int xChannelIndex() const { return m_xChannelSelector - 1; }
- int yChannelIndex() const { return m_yChannelSelector - 1; }
+ const DestinationColorSpace& resultColorSpace() const override;
+ void transformResultColorSpace(FilterEffect*, const int) override;
+ bool platformApplySoftware(const Filter&) override;
+
WTF::TextStream& externalRepresentation(WTF::TextStream&, RepresentationType) const override;
ChannelSelectorType m_xChannelSelector;
Modified: trunk/Source/WebCore/platform/graphics/filters/FEDropShadow.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FEDropShadow.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FEDropShadow.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -73,7 +73,7 @@
{
FilterEffect* in = inputEffect(0);
- ImageBuffer* resultImage = createImageBufferResult();
+ auto resultImage = imageBufferResult();
if (!resultImage)
return false;
@@ -84,7 +84,7 @@
FloatRect drawingRegionWithOffset(drawingRegion);
drawingRegionWithOffset.move(offset);
- ImageBuffer* sourceImage = in->imageBufferResult();
+ auto sourceImage = in->imageBufferResult();
if (!sourceImage)
return false;
Modified: trunk/Source/WebCore/platform/graphics/filters/FEFlood.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FEFlood.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FEFlood.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -60,7 +60,7 @@
bool FEFlood::platformApplySoftware(const Filter&)
{
- ImageBuffer* resultImage = createImageBufferResult();
+ auto resultImage = imageBufferResult();
if (!resultImage)
return false;
Modified: trunk/Source/WebCore/platform/graphics/filters/FEFlood.h (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FEFlood.h 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FEFlood.h 2021-11-23 09:22:16 UTC (rev 286129)
@@ -39,8 +39,7 @@
#if !USE(CG)
// feFlood does not perform color interpolation of any kind, so the result is always in the current
// color space regardless of the value of color-interpolation-filters.
- void setOperatingColorSpace(const DestinationColorSpace&) override { FilterEffect::setResultColorSpace(DestinationColorSpace::SRGB()); }
- void setResultColorSpace(const DestinationColorSpace&) override { FilterEffect::setResultColorSpace(DestinationColorSpace::SRGB()); }
+ void setOperatingColorSpace(const DestinationColorSpace&) override { }
#endif
private:
Modified: trunk/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -523,16 +523,14 @@
{
FilterEffect* in = inputEffect(0);
- auto& destinationPixelBuffer = createPremultipliedImageResult();
+ auto destinationPixelBuffer = pixelBufferResult(AlphaPremultiplication::Premultiplied);
if (!destinationPixelBuffer)
return false;
- auto& destinationPixelArray = destinationPixelBuffer->data();
-
setIsAlphaImage(in->isAlphaImage());
IntRect effectDrawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect());
- in->copyPremultipliedResult(destinationPixelArray, effectDrawingRect, operatingColorSpace());
+ in->copyPixelBufferResult(*destinationPixelBuffer, effectDrawingRect);
if (!m_stdX && !m_stdY)
return true;
@@ -543,6 +541,7 @@
if (!tmpImageData)
return false;
+ auto& destinationPixelArray = destinationPixelBuffer->data();
platformApply(destinationPixelArray, *tmpImageData, kernelSize.width(), kernelSize.height(), paintSize);
return true;
}
Modified: trunk/Source/WebCore/platform/graphics/filters/FELighting.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FELighting.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FELighting.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -475,16 +475,15 @@
{
FilterEffect* in = inputEffect(0);
- auto& destinationPixelBuffer = createPremultipliedImageResult();
+ auto destinationPixelBuffer = pixelBufferResult(AlphaPremultiplication::Premultiplied);
if (!destinationPixelBuffer)
return false;
- auto& destinationPixelArray = destinationPixelBuffer->data();
-
setIsAlphaImage(false);
IntRect effectDrawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect());
- in->copyPremultipliedResult(destinationPixelArray, effectDrawingRect, operatingColorSpace());
+ in->copyPixelBufferResult(*destinationPixelBuffer, effectDrawingRect);
+
// FIXME: support kernelUnitLengths other than (1,1). The issue here is that the W3
// standard has no test case for them, and other browsers (like Firefox) has strange
// output for various kernelUnitLengths, and I am not sure they are reliable.
@@ -491,6 +490,8 @@
// Anyway, feConvolveMatrix should also use the implementation
IntSize absolutePaintSize = absolutePaintRect().size();
+ auto& destinationPixelArray = destinationPixelBuffer->data();
+
drawLighting(destinationPixelArray, absolutePaintSize.width(), absolutePaintSize.height());
return true;
}
Modified: trunk/Source/WebCore/platform/graphics/filters/FEMerge.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FEMerge.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FEMerge.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -43,7 +43,7 @@
unsigned size = numberOfEffectInputs();
ASSERT(size > 0);
- ImageBuffer* resultImage = createImageBufferResult();
+ auto resultImage = imageBufferResult();
if (!resultImage)
return false;
@@ -50,7 +50,7 @@
GraphicsContext& filterContext = resultImage->context();
for (unsigned i = 0; i < size; ++i) {
FilterEffect* in = inputEffect(i);
- if (ImageBuffer* inBuffer = in->imageBufferResult())
+ if (auto inBuffer = in->imageBufferResult())
filterContext.drawImageBuffer(*inBuffer, drawingRegionOfInputImage(in->absolutePaintRect()));
}
Modified: trunk/Source/WebCore/platform/graphics/filters/FEMorphology.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FEMorphology.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FEMorphology.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -229,14 +229,9 @@
platformApplyGeneric(paintingData, 0, paintingData.height);
}
-bool FEMorphology::platformApplyDegenerate(Uint8ClampedArray& dstPixelArray, const IntRect& imageRect, int radiusX, int radiusY)
+bool FEMorphology::isDegenerate(int radiusX, int radiusY) const
{
- if (radiusX < 0 || radiusY < 0 || (!radiusX && !radiusY)) {
- FilterEffect* in = inputEffect(0);
- in->copyPremultipliedResult(dstPixelArray, imageRect, operatingColorSpace());
- return true;
- }
- return false;
+ return radiusX < 0 || radiusY < 0 || (!radiusX && !radiusY);
}
bool FEMorphology::platformApplySoftware(const Filter& filter)
@@ -243,33 +238,38 @@
{
FilterEffect* in = inputEffect(0);
- auto& destinationPixelBuffer = createPremultipliedImageResult();
+ auto destinationPixelBuffer = pixelBufferResult(AlphaPremultiplication::Premultiplied);
if (!destinationPixelBuffer)
return false;
- auto& destinationPixelArray = destinationPixelBuffer->data();
-
setIsAlphaImage(in->isAlphaImage());
IntRect effectDrawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect());
IntSize radius = flooredIntSize(FloatSize(m_radiusX, m_radiusY));
- if (platformApplyDegenerate(destinationPixelArray, effectDrawingRect, radius.width(), radius.height()))
+ if (isDegenerate(radius.width(), radius.height())) {
+ in->copyPixelBufferResult(*destinationPixelBuffer, effectDrawingRect);
return true;
+ }
- auto sourcePixelArray = in->premultipliedResult(effectDrawingRect, operatingColorSpace());
- if (!sourcePixelArray)
- return false;
-
radius = flooredIntSize(filter.scaledByFilterScale({ m_radiusX, m_radiusY }));
int radiusX = std::min(effectDrawingRect.width() - 1, radius.width());
int radiusY = std::min(effectDrawingRect.height() - 1, radius.height());
- if (platformApplyDegenerate(destinationPixelArray, effectDrawingRect, radiusX, radiusY))
+ if (isDegenerate(radiusX, radiusY)) {
+ in->copyPixelBufferResult(*destinationPixelBuffer, effectDrawingRect);
return true;
-
+ }
+
+ auto sourcePixelBuffer = in->getPixelBufferResult(AlphaPremultiplication::Premultiplied, effectDrawingRect, operatingColorSpace());
+ if (!sourcePixelBuffer)
+ return false;
+
+ auto& sourcePixelArray = sourcePixelBuffer->data();
+ auto& destinationPixelArray = destinationPixelBuffer->data();
+
PaintingData paintingData;
- paintingData.srcPixelArray = sourcePixelArray.get();
+ paintingData.srcPixelArray = &sourcePixelArray;
paintingData.dstPixelArray = &destinationPixelArray;
paintingData.width = ceilf(effectDrawingRect.width());
paintingData.height = ceilf(effectDrawingRect.height());
Modified: trunk/Source/WebCore/platform/graphics/filters/FEMorphology.h (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FEMorphology.h 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FEMorphology.h 2021-11-23 09:22:16 UTC (rev 286129)
@@ -53,7 +53,7 @@
WTF::TextStream& externalRepresentation(WTF::TextStream&, RepresentationType) const override;
- bool platformApplyDegenerate(Uint8ClampedArray& dstPixelArray, const IntRect& imageRect, int radiusX, int radiusY);
+ bool isDegenerate(int radiusX, int radiusY) const;
struct PaintingData {
const Uint8ClampedArray* srcPixelArray;
Modified: trunk/Source/WebCore/platform/graphics/filters/FEOffset.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FEOffset.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FEOffset.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -68,8 +68,8 @@
{
FilterEffect* in = inputEffect(0);
- ImageBuffer* resultImage = createImageBufferResult();
- ImageBuffer* inBuffer = in->imageBufferResult();
+ auto resultImage = imageBufferResult();
+ auto inBuffer = in->imageBufferResult();
if (!resultImage || !inBuffer)
return false;
Modified: trunk/Source/WebCore/platform/graphics/filters/FETile.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FETile.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FETile.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -44,11 +44,10 @@
bool FETile::platformApplySoftware(const Filter& filter)
{
-// 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->imageBufferResult();
+ auto resultImage = imageBufferResult();
+ auto inBuffer = in->imageBufferResult();
if (!resultImage || !inBuffer)
return false;
Modified: trunk/Source/WebCore/platform/graphics/filters/FETurbulence.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FETurbulence.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FETurbulence.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -395,7 +395,7 @@
bool FETurbulence::platformApplySoftware(const Filter& filter)
{
- auto& destinationPixelBuffer = createUnmultipliedImageResult();
+ auto destinationPixelBuffer = pixelBufferResult(AlphaPremultiplication::Unpremultiplied);
if (!destinationPixelBuffer)
return false;
Modified: trunk/Source/WebCore/platform/graphics/filters/FilterEffect.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FilterEffect.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FilterEffect.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -27,29 +27,13 @@
#include "Color.h"
#include "Filter.h"
#include "GeometryUtilities.h"
-#include "GraphicsContext.h"
#include "ImageBuffer.h"
#include "Logging.h"
#include "PixelBuffer.h"
-#include <_javascript_Core/JSCInlines.h>
-#include <_javascript_Core/TypedArrayInlines.h>
#include <wtf/text/TextStream.h>
-#if HAVE(ARM_NEON_INTRINSICS)
-#include <arm_neon.h>
-#endif
-
-#if USE(ACCELERATE)
-#include <Accelerate/Accelerate.h>
-#endif
-
namespace WebCore {
-FilterEffect::FilterEffect(FilterEffect::Type type)
- : FilterFunction(type)
-{
-}
-
void FilterEffect::determineAbsolutePaintRect(const Filter&)
{
m_absolutePaintRect = IntRect();
@@ -157,7 +141,6 @@
}
determineAbsolutePaintRect(filter);
- setResultColorSpace(m_operatingColorSpace);
LOG_WITH_STREAM(Filters, stream
<< "FilterEffect " << filterName() << " " << this << " apply():"
@@ -171,69 +154,27 @@
if (m_absolutePaintRect.isEmpty() || ImageBuffer::sizeNeedsClamping(m_absolutePaintRect.size()))
return false;
- if (requiresValidPreMultipliedPixels()) {
- for (unsigned i = 0; i < size; ++i)
- inputEffect(i)->correctFilterResultIfNeeded();
+ if (!mayProduceInvalidPremultipliedPixels()) {
+ for (auto& in : m_inputEffects)
+ in->correctPremultipliedResultIfNeeded();
}
+
+ if (!createResult())
+ return false;
// Add platform specific apply functions here and return earlier.
return platformApplySoftware(filter);
}
-void FilterEffect::forceValidPreMultipliedPixels()
+bool FilterEffect::createResult()
{
- // Must operate on pre-multiplied results; other formats cannot have invalid pixels.
- if (!m_premultipliedImageResult)
- return;
-
- auto& imageArray = m_premultipliedImageResult->data();
- uint8_t* pixelData = imageArray.data();
- int pixelArrayLength = imageArray.length();
-
- // We must have four bytes per pixel, and complete pixels
- ASSERT(!(pixelArrayLength % 4));
-
-#if HAVE(ARM_NEON_INTRINSICS)
- if (pixelArrayLength >= 64) {
- uint8_t* lastPixel = pixelData + (pixelArrayLength & ~0x3f);
- do {
- // Increments pixelData by 64.
- uint8x16x4_t sixteenPixels = vld4q_u8(pixelData);
- sixteenPixels.val[0] = vminq_u8(sixteenPixels.val[0], sixteenPixels.val[3]);
- sixteenPixels.val[1] = vminq_u8(sixteenPixels.val[1], sixteenPixels.val[3]);
- sixteenPixels.val[2] = vminq_u8(sixteenPixels.val[2], sixteenPixels.val[3]);
- vst4q_u8(pixelData, sixteenPixels);
- pixelData += 64;
- } while (pixelData < lastPixel);
-
- pixelArrayLength &= 0x3f;
- if (!pixelArrayLength)
- return;
- }
-#endif
-
- int numPixels = pixelArrayLength / 4;
-
- // Iterate over each pixel, checking alpha and adjusting color components if necessary
- while (--numPixels >= 0) {
- // Alpha is the 4th byte in a pixel
- uint8_t a = *(pixelData + 3);
- // Clamp each component to alpha, and increment the pixel location
- for (int i = 0; i < 3; ++i) {
- if (*pixelData > a)
- *pixelData = a;
- ++pixelData;
- }
- // Increment for alpha
- ++pixelData;
- }
+ m_filterImage = FilterImage::create(m_absolutePaintRect, RenderingMode::Unaccelerated, resultColorSpace());
+ return m_filterImage;
}
void FilterEffect::clearResult()
{
- m_imageBufferResult = nullptr;
- m_unmultipliedImageResult = std::nullopt;
- m_premultipliedImageResult = std::nullopt;
+ m_filterImage = nullptr;
}
void FilterEffect::clearResultsRecursive()
@@ -240,399 +181,49 @@
{
// Clear all results, regardless that the current effect has
// a result. Can be used if an effect is in an erroneous state.
- if (hasResult())
- clearResult();
-
- unsigned size = m_inputEffects.size();
- for (unsigned i = 0; i < size; ++i)
- m_inputEffects.at(i).get()->clearResultsRecursive();
+ clearResult();
+ for (auto& effect : m_inputEffects)
+ effect->clearResultsRecursive();
}
ImageBuffer* FilterEffect::imageBufferResult()
{
- LOG_WITH_STREAM(Filters, stream << "FilterEffect " << filterName() << " " << this << " imageBufferResult(). Existing image buffer " << m_imageBufferResult.get() << " m_premultipliedImageResult " << m_premultipliedImageResult << " m_unmultipliedImageResult " << m_unmultipliedImageResult);
-
if (!hasResult())
return nullptr;
-
- if (m_imageBufferResult)
- return m_imageBufferResult.get();
-
- // FIXME: Respect the Filter::renderingMode() when creating the filter ImageBuffer result.
- // For now just pass RenderingMode::Unaccelerated. This will not be a behavior change since
- // this is what we do for the software filter code path anyway.
- m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), RenderingMode::Unaccelerated, 1, m_resultColorSpace, PixelFormat::BGRA8);
- if (!m_imageBufferResult)
- return nullptr;
-
- IntRect destinationRect(IntPoint(), m_absolutePaintRect.size());
- if (m_premultipliedImageResult)
- m_imageBufferResult->putPixelBuffer(*m_premultipliedImageResult, destinationRect);
- else
- m_imageBufferResult->putPixelBuffer(*m_unmultipliedImageResult, destinationRect);
- return m_imageBufferResult.get();
+ return m_filterImage->imageBuffer();
}
-RefPtr<Uint8ClampedArray> FilterEffect::unmultipliedResult(const IntRect& rect, std::optional<DestinationColorSpace> colorSpace)
+PixelBuffer* FilterEffect::pixelBufferResult(AlphaPremultiplication alphaFormat)
{
- IntSize scaledSize(rect.size());
- ASSERT(!ImageBuffer::sizeNeedsClamping(scaledSize));
- auto checkedArea = scaledSize.area<RecordOverflow>() * 4;
- if (checkedArea.hasOverflowed())
+ if (!hasResult())
return nullptr;
- auto pixelArray = Uint8ClampedArray::tryCreateUninitialized(checkedArea);
- if (!pixelArray)
- return nullptr;
- copyUnmultipliedResult(*pixelArray, rect, colorSpace);
- return pixelArray;
+ return m_filterImage->pixelBuffer(alphaFormat);
}
-RefPtr<Uint8ClampedArray> FilterEffect::premultipliedResult(const IntRect& rect, std::optional<DestinationColorSpace> colorSpace)
+std::optional<PixelBuffer> FilterEffect::getPixelBufferResult(AlphaPremultiplication alphaFormat, const IntRect& sourceRect, std::optional<DestinationColorSpace> colorSpace)
{
- IntSize scaledSize(rect.size());
- ASSERT(!ImageBuffer::sizeNeedsClamping(scaledSize));
- auto checkedArea = scaledSize.area<RecordOverflow>() * 4;
- if (checkedArea.hasOverflowed())
- return nullptr;
- auto pixelArray = Uint8ClampedArray::tryCreateUninitialized(checkedArea);
- if (!pixelArray)
- return nullptr;
- copyPremultipliedResult(*pixelArray, rect, colorSpace);
- return pixelArray;
+ ASSERT(hasResult());
+ return m_filterImage->getPixelBuffer(alphaFormat, sourceRect, colorSpace);
}
-void FilterEffect::copyImageBytes(const Uint8ClampedArray& source, Uint8ClampedArray& destination, const IntRect& rect) const
+void FilterEffect::copyPixelBufferResult(PixelBuffer& destinationPixelBuffer, const IntRect& sourceRect) const
{
- IntRect scaledRect(rect);
- IntSize scaledPaintSize(m_absolutePaintRect.size());
-
- // Initialize the destination to transparent black, if not entirely covered by the source.
- 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 (scaledRect.maxX() <= 0 || scaledRect.maxY() <= 0 || scaledRect.x() >= scaledPaintSize.width() || scaledRect.y() >= scaledPaintSize.height())
- return;
-
- int xOrigin = scaledRect.x();
- int xDest = 0;
- if (xOrigin < 0) {
- xDest = -xOrigin;
- xOrigin = 0;
- }
- int xEnd = scaledRect.maxX();
- if (xEnd > scaledPaintSize.width())
- xEnd = scaledPaintSize.width();
-
- int yOrigin = scaledRect.y();
- int yDest = 0;
- if (yOrigin < 0) {
- yDest = -yOrigin;
- yOrigin = 0;
- }
- int yEnd = scaledRect.maxY();
- if (yEnd > scaledPaintSize.height())
- yEnd = scaledPaintSize.height();
-
- int size = (xEnd - xOrigin) * 4;
- int destinationScanline = scaledRect.width() * 4;
- int sourceScanline = scaledPaintSize.width() * 4;
- uint8_t* destinationPixel = destination.data() + ((yDest * scaledRect.width()) + xDest) * 4;
- const uint8_t* sourcePixel = source.data() + ((yOrigin * scaledPaintSize.width()) + xOrigin) * 4;
-
- while (yOrigin < yEnd) {
- memcpy(destinationPixel, sourcePixel, size);
- destinationPixel += destinationScanline;
- sourcePixel += sourceScanline;
- ++yOrigin;
- }
-}
-
-static void copyPremultiplyingAlpha(const Uint8ClampedArray& source, Uint8ClampedArray& destination, const IntSize& inputSize)
-{
-#if USE(ACCELERATE)
- size_t rowBytes = inputSize.width() * 4;
-
- vImage_Buffer src;
- src.width = inputSize.width();
- src.height = inputSize.height();
- src.rowBytes = rowBytes;
- src.data = ""
-
- vImage_Buffer dest;
- dest.width = inputSize.width();
- dest.height = inputSize.height();
- dest.rowBytes = rowBytes;
- dest.data = ""
-
- vImagePremultiplyData_RGBA8888(&src, &dest, kvImageNoFlags);
-#else
- const uint8_t* sourceComponent = source.data();
- const uint8_t* end = sourceComponent + (inputSize.area() * 4).value();
- uint8_t* destinationComponent = destination.data();
-
- while (sourceComponent < end) {
- int alpha = sourceComponent[3];
- destinationComponent[0] = static_cast<int>(sourceComponent[0]) * alpha / 255;
- destinationComponent[1] = static_cast<int>(sourceComponent[1]) * alpha / 255;
- destinationComponent[2] = static_cast<int>(sourceComponent[2]) * alpha / 255;
- destinationComponent[3] = alpha;
- sourceComponent += 4;
- destinationComponent += 4;
- }
-#endif
-}
-
-static void copyUnpremultiplyingAlpha(const Uint8ClampedArray& source, Uint8ClampedArray& destination, const IntSize& inputSize)
-{
-#if USE(ACCELERATE)
- size_t rowBytes = inputSize.width() * 4;
-
- vImage_Buffer src;
- src.width = inputSize.width();
- src.height = inputSize.height();
- src.rowBytes = rowBytes;
- src.data = ""
-
- vImage_Buffer dest;
- dest.width = inputSize.width();
- dest.height = inputSize.height();
- dest.rowBytes = rowBytes;
- dest.data = ""
-
- vImageUnpremultiplyData_RGBA8888(&src, &dest, kvImageNoFlags);
-#else
- const uint8_t* sourceComponent = source.data();
- const uint8_t* end = sourceComponent + (inputSize.area() * 4).value();
- uint8_t* destinationComponent = destination.data();
- while (sourceComponent < end) {
- int alpha = sourceComponent[3];
- if (alpha) {
- destinationComponent[0] = static_cast<int>(sourceComponent[0]) * 255 / alpha;
- destinationComponent[1] = static_cast<int>(sourceComponent[1]) * 255 / alpha;
- destinationComponent[2] = static_cast<int>(sourceComponent[2]) * 255 / alpha;
- } else {
- destinationComponent[0] = 0;
- destinationComponent[1] = 0;
- destinationComponent[2] = 0;
- }
- destinationComponent[3] = alpha;
- sourceComponent += 4;
- destinationComponent += 4;
- }
-#endif
-}
-
-std::optional<PixelBuffer> FilterEffect::convertPixelBufferToColorSpace(const DestinationColorSpace& targetColorSpace, PixelBuffer& pixelBuffer)
-{
- // FIXME: Using an ImageBuffer to perform the color space conversion is unnecessary. We can do it directly.
-
- IntRect destinationRect(IntPoint(), pixelBuffer.size());
- FloatSize clampedSize = ImageBuffer::clampedSize(destinationRect.size());
- // Create an ImageBuffer to store incoming PixelBuffer
- auto buffer = ImageBuffer::create(clampedSize, RenderingMode::Unaccelerated, 1, operatingColorSpace(), PixelFormat::BGRA8);
- if (!buffer)
- return std::nullopt;
- buffer->putPixelBuffer(pixelBuffer, destinationRect);
- return convertImageBufferToColorSpace(targetColorSpace, *buffer, destinationRect, pixelBuffer.format().alphaFormat);
-}
-
-std::optional<PixelBuffer> FilterEffect::convertImageBufferToColorSpace(const DestinationColorSpace& targetColorSpace, ImageBuffer& inputBuffer, const IntRect& rect, AlphaPremultiplication outputAlphaFormat)
-{
- // FIXME: This can be done more directly using PixelBufferConversion.
-
- FloatSize clampedSize = ImageBuffer::clampedSize(rect.size());
-
- // Create an ImageBuffer with the correct color space and utilize CG to handle color space conversion
- auto convertedBuffer = ImageBuffer::create(clampedSize, RenderingMode::Unaccelerated, 1, targetColorSpace, PixelFormat::BGRA8);
- if (!convertedBuffer)
- return std::nullopt;
-
- // Color space conversion happens internally when drawing from one image buffer to another
- convertedBuffer->context().drawImageBuffer(inputBuffer, rect);
-
- PixelBufferFormat format { outputAlphaFormat, PixelFormat::RGBA8, targetColorSpace };
- return convertedBuffer->getPixelBuffer(format, rect);
-}
-
-void FilterEffect::copyConvertedImageBufferToDestination(Uint8ClampedArray& destination, const DestinationColorSpace& colorSpace, AlphaPremultiplication outputFormat, const IntRect& destRect)
-{
- // Converts the data stored in m_imageBufferResult, and save to destination
- auto convertedPixelBuffer = convertImageBufferToColorSpace(colorSpace, *m_imageBufferResult, { IntPoint(), m_absolutePaintRect.size() }, outputFormat);
- if (!convertedPixelBuffer)
- return;
- copyImageBytes(convertedPixelBuffer->data(), destination, destRect);
-}
-
-void FilterEffect::copyConvertedPixelBufferToDestination(Uint8ClampedArray& destination, PixelBuffer& pixelBuffer, const DestinationColorSpace& colorSpace, const IntRect& destRect)
-{
- // Converts the data stored in m_unmultipliedImageResult/m_premultipliedImageResult,
- // whichever isn't null, and save to destination
- auto convertedPixelBuffer = convertPixelBufferToColorSpace(colorSpace, pixelBuffer);
- if (!convertedPixelBuffer)
- return;
- copyImageBytes(convertedPixelBuffer->data(), destination, destRect);
-}
-
-void FilterEffect::copyUnmultipliedResult(Uint8ClampedArray& destination, const IntRect& rect, std::optional<DestinationColorSpace> colorSpace)
-{
ASSERT(hasResult());
-
- LOG_WITH_STREAM(Filters, stream << "FilterEffect " << filterName() << " " << this << " copyUnmultipliedResult(). Existing image buffer " << m_imageBufferResult.get() << " m_premultipliedImageResult " << m_premultipliedImageResult << " m_unmultipliedImageResult " << m_unmultipliedImageResult);
-
- if (!m_unmultipliedImageResult) {
- // We prefer a conversion from the image buffer.
- if (m_imageBufferResult) {
- if (requiresPixelBufferColorSpaceConversion(colorSpace)) {
- copyConvertedImageBufferToDestination(destination, *colorSpace, AlphaPremultiplication::Unpremultiplied, rect);
- return;
- }
-
- ASSERT(m_imageBufferResult->colorSpace() == m_resultColorSpace);
- PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, m_resultColorSpace };
- m_unmultipliedImageResult = m_imageBufferResult->getPixelBuffer(format, { IntPoint(), m_absolutePaintRect.size() });
- if (!m_unmultipliedImageResult)
- return;
- } else {
- IntSize inputSize(m_absolutePaintRect.size());
- ASSERT(!ImageBuffer::sizeNeedsClamping(inputSize));
-
- ASSERT(m_premultipliedImageResult->format().colorSpace == m_resultColorSpace);
- PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, m_resultColorSpace };
- m_unmultipliedImageResult = PixelBuffer::tryCreate(format, inputSize);
- if (!m_unmultipliedImageResult)
- return;
- copyUnpremultiplyingAlpha(m_premultipliedImageResult->data(), m_unmultipliedImageResult->data(), inputSize);
- }
- }
- if (requiresPixelBufferColorSpaceConversion(colorSpace)) {
- copyConvertedPixelBufferToDestination(destination, *m_unmultipliedImageResult, *colorSpace, rect);
- return;
- }
- copyImageBytes(m_unmultipliedImageResult->data(), destination, rect);
+ m_filterImage->copyPixelBuffer(destinationPixelBuffer, sourceRect);
}
-void FilterEffect::copyPremultipliedResult(Uint8ClampedArray& destination, const IntRect& rect, std::optional<DestinationColorSpace> colorSpace)
+void FilterEffect::correctPremultipliedResultIfNeeded()
{
- ASSERT(hasResult());
-
- LOG_WITH_STREAM(Filters, stream << "FilterEffect " << filterName() << " " << this << " copyPremultipliedResult(). Existing image buffer " << m_imageBufferResult.get() << " m_premultipliedImageResult " << m_premultipliedImageResult << " m_unmultipliedImageResult " << m_unmultipliedImageResult);
-
- if (!m_premultipliedImageResult) {
- // We prefer a conversion from the image buffer.
- if (m_imageBufferResult) {
- if (requiresPixelBufferColorSpaceConversion(colorSpace)) {
- copyConvertedImageBufferToDestination(destination, *colorSpace, AlphaPremultiplication::Premultiplied, rect);
- return;
- }
-
- ASSERT(m_imageBufferResult->colorSpace() == m_resultColorSpace);
- PixelBufferFormat format { AlphaPremultiplication::Premultiplied, PixelFormat::RGBA8, m_resultColorSpace };
- m_premultipliedImageResult = m_imageBufferResult->getPixelBuffer(format, { IntPoint(), m_absolutePaintRect.size() });
- if (!m_premultipliedImageResult)
- return;
- } else {
- IntSize inputSize(m_absolutePaintRect.size());
- ASSERT(!ImageBuffer::sizeNeedsClamping(inputSize));
-
- ASSERT(m_unmultipliedImageResult->format().colorSpace == m_resultColorSpace);
- PixelBufferFormat format { AlphaPremultiplication::Premultiplied, PixelFormat::RGBA8, m_resultColorSpace };
- m_premultipliedImageResult = PixelBuffer::tryCreate(format, inputSize);
- if (!m_premultipliedImageResult)
- return;
- copyPremultiplyingAlpha(m_unmultipliedImageResult->data(), m_premultipliedImageResult->data(), inputSize);
- }
- }
-
- if (requiresPixelBufferColorSpaceConversion(colorSpace)) {
- copyConvertedPixelBufferToDestination(destination, *m_premultipliedImageResult, *colorSpace, rect);
+ if (!hasResult() || !mayProduceInvalidPremultipliedPixels())
return;
- }
- copyImageBytes(m_premultipliedImageResult->data(), destination, rect);
+ m_filterImage->correctPremultipliedPixelBuffer();
}
-ImageBuffer* FilterEffect::createImageBufferResult()
-{
- LOG(Filters, "FilterEffect %s %p createImageBufferResult %dx%d", filterName().characters8(), this, m_absolutePaintRect.size().width(), m_absolutePaintRect.size().height());
-
- // Only one result type is allowed.
- ASSERT(!hasResult());
- if (m_absolutePaintRect.isEmpty())
- return nullptr;
-
- FloatSize clampedSize = ImageBuffer::clampedSize(m_absolutePaintRect.size());
- m_imageBufferResult = ImageBuffer::create(clampedSize, RenderingMode::Unaccelerated, 1, m_resultColorSpace, PixelFormat::BGRA8);
- return m_imageBufferResult.get();
-}
-
-std::optional<PixelBuffer>& FilterEffect::createUnmultipliedImageResult()
-{
- LOG(Filters, "FilterEffect %s %p createUnmultipliedImageResult", filterName().characters8(), this);
-
- // Only one result type is allowed.
- ASSERT(!hasResult());
- ASSERT(!m_unmultipliedImageResult);
-
- if (m_absolutePaintRect.isEmpty())
- return m_unmultipliedImageResult;
-
- IntSize resultSize(m_absolutePaintRect.size());
- ASSERT(!ImageBuffer::sizeNeedsClamping(resultSize));
- PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, m_resultColorSpace };
- m_unmultipliedImageResult = PixelBuffer::tryCreate(format, resultSize);
- return m_unmultipliedImageResult;
-}
-
-std::optional<PixelBuffer>& FilterEffect::createPremultipliedImageResult()
-{
- LOG(Filters, "FilterEffect %s %p createPremultipliedImageResult", filterName().characters8(), this);
-
- // Only one result type is allowed.
- ASSERT(!hasResult());
- ASSERT(!m_premultipliedImageResult);
-
- if (m_absolutePaintRect.isEmpty())
- return m_premultipliedImageResult;
-
- IntSize resultSize(m_absolutePaintRect.size());
- ASSERT(!ImageBuffer::sizeNeedsClamping(resultSize));
- PixelBufferFormat format { AlphaPremultiplication::Premultiplied, PixelFormat::RGBA8, m_resultColorSpace };
- m_premultipliedImageResult = PixelBuffer::tryCreate(format, resultSize);
- return m_premultipliedImageResult;
-}
-
-bool FilterEffect::requiresPixelBufferColorSpaceConversion(std::optional<DestinationColorSpace> destinationColorSpace)
-{
-#if USE(CG)
- // This function determines whether we need the step of an extra color space conversion
- // We only need extra color conversion when 1) color space is different in the input
- // AND 2) the filter is manipulating raw pixels
- return destinationColorSpace && resultColorSpace() != *destinationColorSpace;
-#else
- // Additional color space conversion is not needed on non-CG
- UNUSED_PARAM(destinationColorSpace);
- return false;
-#endif
-}
-
void FilterEffect::transformResultColorSpace(const DestinationColorSpace& destinationColorSpace)
{
-#if USE(CG)
- // CG handles color space adjustments internally.
- UNUSED_PARAM(destinationColorSpace);
-#else
- if (!hasResult() || destinationColorSpace == m_resultColorSpace)
+ if (!hasResult())
return;
-
- // FIXME: We can avoid this potentially unnecessary ImageBuffer conversion by adding
- // color space transform support for the {pre,un}multiplied arrays.
- imageBufferResult()->transformToColorSpace(destinationColorSpace);
-
- m_resultColorSpace = destinationColorSpace;
-
- m_unmultipliedImageResult = std::nullopt;
- m_premultipliedImageResult = std::nullopt;
-#endif
+ m_filterImage->transformToColorSpace(destinationColorSpace);
}
TextStream& FilterEffect::externalRepresentation(TextStream& ts, RepresentationType representationType) const
@@ -643,8 +234,8 @@
if (representationType == RepresentationType::Debugging) {
TextStream::IndentScope indentScope(ts);
ts.dumpProperty("alpha image", m_alphaImage);
- ts.dumpProperty("operating colorspace", m_operatingColorSpace);
- ts.dumpProperty("result colorspace", m_resultColorSpace);
+ ts.dumpProperty("operating colorspace", operatingColorSpace());
+ ts.dumpProperty("result colorspace", resultColorSpace());
ts << "\n" << indent;
}
return ts;
Modified: trunk/Source/WebCore/platform/graphics/filters/FilterEffect.h (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FilterEffect.h 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/FilterEffect.h 2021-11-23 09:22:16 UTC (rev 286129)
@@ -22,17 +22,11 @@
#pragma once
-#include "AlphaPremultiplication.h"
#include "DestinationColorSpace.h"
#include "FilterEffectVector.h"
#include "FilterFunction.h"
-#include "FloatRect.h"
+#include "FilterImage.h"
#include "IntRect.h"
-#include "IntRectExtent.h"
-#include "PixelBuffer.h"
-#include <_javascript_Core/Forward.h>
-#include <wtf/MathExtras.h>
-#include <wtf/RefPtr.h>
#include <wtf/Vector.h>
namespace WTF {
@@ -46,26 +40,22 @@
class FilterEffect : public FilterFunction {
public:
+ bool createResult();
void clearResult() override;
void clearResultsRecursive();
+ bool hasResult() const { return m_filterImage; }
+
ImageBuffer* imageBufferResult();
- RefPtr<Uint8ClampedArray> unmultipliedResult(const IntRect&, std::optional<DestinationColorSpace> = std::nullopt);
- RefPtr<Uint8ClampedArray> premultipliedResult(const IntRect&, std::optional<DestinationColorSpace> = std::nullopt);
- void copyUnmultipliedResult(Uint8ClampedArray& destination, const IntRect&, std::optional<DestinationColorSpace> = std::nullopt);
- void copyPremultipliedResult(Uint8ClampedArray& destination, const IntRect&, std::optional<DestinationColorSpace> = std::nullopt);
+ PixelBuffer* pixelBufferResult(AlphaPremultiplication);
+ std::optional<PixelBuffer> getPixelBufferResult(AlphaPremultiplication, const IntRect& sourceRect, std::optional<DestinationColorSpace> = std::nullopt);
+ void copyPixelBufferResult(PixelBuffer& destinationPixelBuffer, const IntRect& sourceRect) const;
+ void correctPremultipliedResultIfNeeded();
+
FilterEffectVector& inputEffects() { return m_inputEffects; }
FilterEffect* inputEffect(unsigned) const;
unsigned numberOfEffectInputs() const { return m_inputEffects.size(); }
- inline bool hasResult() const
- {
- // This function needs platform specific checks, if the memory managment is not done by FilterEffect.
- return m_imageBufferResult
- || m_unmultipliedImageResult
- || m_premultipliedImageResult;
- }
-
FloatRect drawingRegionOfInputImage(const IntRect&) const;
IntRect requestedRegionOfInputPixelBuffer(const IntRect&) const;
@@ -123,9 +113,9 @@
const DestinationColorSpace& operatingColorSpace() const { return m_operatingColorSpace; }
virtual void setOperatingColorSpace(const DestinationColorSpace& colorSpace) { m_operatingColorSpace = colorSpace; }
- const DestinationColorSpace& resultColorSpace() const { return m_resultColorSpace; }
- virtual void setResultColorSpace(const DestinationColorSpace& colorSpace) { m_resultColorSpace = colorSpace; }
+ virtual const DestinationColorSpace& resultColorSpace() const { return m_operatingColorSpace; }
+
virtual void transformResultColorSpace(FilterEffect* in, const int) { in->transformResultColorSpace(m_operatingColorSpace); }
void transformResultColorSpace(const DestinationColorSpace&);
@@ -138,36 +128,18 @@
}
protected:
- FilterEffect(Type);
-
- ImageBuffer* createImageBufferResult();
- std::optional<PixelBuffer>& createUnmultipliedImageResult();
- std::optional<PixelBuffer>& createPremultipliedImageResult();
+ using FilterFunction::FilterFunction;
- // Return true if the filter will only operate correctly on valid RGBA values, with
- // alpha in [0,255] and each color component in [0, alpha].
- virtual bool requiresValidPreMultipliedPixels() { return true; }
+ virtual bool mayProduceInvalidPremultipliedPixels() const { return false; }
- // If a pre-multiplied image, check every pixel for validity and correct if necessary.
- void forceValidPreMultipliedPixels();
-
void clipAbsolutePaintRect();
private:
virtual bool platformApplySoftware(const Filter&) = 0;
- void copyImageBytes(const Uint8ClampedArray& source, Uint8ClampedArray& destination, const IntRect&) const;
- void copyConvertedImageBufferToDestination(Uint8ClampedArray&, const DestinationColorSpace&, AlphaPremultiplication, const IntRect&);
- void copyConvertedPixelBufferToDestination(Uint8ClampedArray&, PixelBuffer&, const DestinationColorSpace&, const IntRect&);
- bool requiresPixelBufferColorSpaceConversion(std::optional<DestinationColorSpace>);
- std::optional<PixelBuffer> convertImageBufferToColorSpace(const DestinationColorSpace&, ImageBuffer&, const IntRect&, AlphaPremultiplication);
- std::optional<PixelBuffer> convertPixelBufferToColorSpace(const DestinationColorSpace&, PixelBuffer&);
-
FilterEffectVector m_inputEffects;
- RefPtr<ImageBuffer> m_imageBufferResult;
- std::optional<PixelBuffer> m_unmultipliedImageResult;
- std::optional<PixelBuffer> m_premultipliedImageResult;
+ RefPtr<FilterImage> m_filterImage;
IntRect m_absolutePaintRect;
@@ -195,12 +167,7 @@
// Should the effect clip to its primitive region, or expand to use the combined region of its inputs.
bool m_clipsToBounds { true };
-#if ENABLE(DESTINATION_COLOR_SPACE_LINEAR_SRGB)
- DestinationColorSpace m_operatingColorSpace { DestinationColorSpace::LinearSRGB() };
-#else
DestinationColorSpace m_operatingColorSpace { DestinationColorSpace::SRGB() };
-#endif
- DestinationColorSpace m_resultColorSpace { DestinationColorSpace::SRGB() };
};
WEBCORE_EXPORT WTF::TextStream& operator<<(WTF::TextStream&, const FilterEffect&);
Added: trunk/Source/WebCore/platform/graphics/filters/FilterImage.cpp (0 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FilterImage.cpp (rev 0)
+++ trunk/Source/WebCore/platform/graphics/filters/FilterImage.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FilterImage.h"
+
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+#include "PixelBuffer.h"
+#include "PixelBufferConversion.h"
+
+#if HAVE(ARM_NEON_INTRINSICS)
+#include <arm_neon.h>
+#endif
+
+namespace WebCore {
+
+RefPtr<FilterImage> FilterImage::create(const IntRect& absoluteImageRect, RenderingMode renderingMode, const DestinationColorSpace& colorSpace)
+{
+ ASSERT(!ImageBuffer::sizeNeedsClamping(absoluteImageRect.size()));
+ return adoptRef(new FilterImage(absoluteImageRect, renderingMode, colorSpace));
+}
+
+FilterImage::FilterImage(const IntRect& absoluteImageRect, RenderingMode renderingMode, const DestinationColorSpace& colorSpace)
+ : m_absoluteImageRect(absoluteImageRect)
+ , m_renderingMode(renderingMode)
+ , m_colorSpace(colorSpace)
+{
+}
+
+ImageBuffer* FilterImage::imageBuffer()
+{
+ if (m_imageBuffer)
+ return m_imageBuffer.get();
+
+ m_imageBuffer = ImageBuffer::create(m_absoluteImageRect.size(), m_renderingMode, 1, m_colorSpace, PixelFormat::BGRA8);
+ if (!m_imageBuffer)
+ return nullptr;
+
+ auto imageBufferRect = IntRect { { }, m_absoluteImageRect.size() };
+
+ if (pixelBufferSlot(AlphaPremultiplication::Premultiplied))
+ m_imageBuffer->putPixelBuffer(*pixelBufferSlot(AlphaPremultiplication::Premultiplied), imageBufferRect);
+ else if (pixelBufferSlot(AlphaPremultiplication::Unpremultiplied))
+ m_imageBuffer->putPixelBuffer(*pixelBufferSlot(AlphaPremultiplication::Unpremultiplied), imageBufferRect);
+
+ return m_imageBuffer.get();
+}
+
+static void copyImageBytes(const PixelBuffer& sourcePixelBuffer, PixelBuffer& destinationPixelBuffer)
+{
+ ASSERT(sourcePixelBuffer.size() == destinationPixelBuffer.size());
+
+ auto destinationSize = destinationPixelBuffer.size();
+ unsigned rowBytes = destinationSize.width() * 4;
+
+ ConstPixelBufferConversionView source { sourcePixelBuffer.format(), rowBytes, sourcePixelBuffer.data().data() };
+ PixelBufferConversionView destination { destinationPixelBuffer.format(), rowBytes, destinationPixelBuffer.data().data() };
+
+ convertImagePixels(source, destination, destinationSize);
+}
+
+static void copyImageBytes(const PixelBuffer& sourcePixelBuffer, PixelBuffer& destinationPixelBuffer, const IntRect& sourceRect)
+{
+ auto& source = sourcePixelBuffer.data();
+ auto& destination = destinationPixelBuffer.data();
+
+ auto sourcePixelBufferRect = IntRect { { }, sourcePixelBuffer.size() };
+ auto destinationPixelBufferRect = IntRect { { }, destinationPixelBuffer.size() };
+
+ auto sourceRectClipped = intersection(sourcePixelBufferRect, sourceRect);
+ auto destinationRect = IntRect { { }, sourceRectClipped.size() };
+
+ if (sourceRect.x() < 0)
+ destinationRect.setX(-sourceRect.x());
+
+ if (sourceRect.y() < 0)
+ destinationRect.setY(-sourceRect.y());
+
+ destinationRect.intersect(destinationPixelBufferRect);
+ sourceRectClipped.setSize(destinationRect.size());
+
+ // Initialize the destination to transparent black, if not entirely covered by the source.
+ if (destinationRect.size() != destinationPixelBufferRect.size())
+ destination.zeroFill();
+
+ // Early return if the rect does not intersect with the source.
+ if (destinationRect.isEmpty())
+ return;
+
+ int size = sourceRectClipped.width() * 4;
+ int destinationBytesPerRow = destinationPixelBufferRect.width() * 4;
+ int sourceBytesPerRow = sourcePixelBufferRect.width() * 4;
+ uint8_t* destinationPixel = destination.data() + destinationRect.y() * destinationBytesPerRow + destinationRect.x() * 4;
+ const uint8_t* sourcePixel = source.data() + sourceRectClipped.y() * sourceBytesPerRow + sourceRectClipped.x() * 4;
+
+ for (int y = 0; y < sourceRectClipped.height(); ++y) {
+ memcpy(destinationPixel, sourcePixel, size);
+ destinationPixel += destinationBytesPerRow;
+ sourcePixel += sourceBytesPerRow;
+ }
+}
+
+static std::optional<PixelBuffer> getConvertedPixelBuffer(ImageBuffer& imageBuffer, AlphaPremultiplication alphaFormat, const IntRect& sourceRect, DestinationColorSpace colorSpace)
+{
+ auto clampedSize = ImageBuffer::clampedSize(sourceRect.size());
+ auto convertedImageBuffer = ImageBuffer::create(clampedSize, RenderingMode::Unaccelerated, 1, colorSpace, PixelFormat::BGRA8);
+
+ if (!convertedImageBuffer)
+ return std::nullopt;
+
+ // Color space conversion happens internally when drawing from one image buffer to another
+ convertedImageBuffer->context().drawImageBuffer(imageBuffer, sourceRect);
+ PixelBufferFormat format { alphaFormat, PixelFormat::RGBA8, colorSpace };
+ return convertedImageBuffer->getPixelBuffer(format, sourceRect);
+}
+
+static std::optional<PixelBuffer> getConvertedPixelBuffer(PixelBuffer& sourcePixelBuffer, AlphaPremultiplication alphaFormat, DestinationColorSpace colorSpace)
+{
+ auto sourceRect = IntRect { { } , sourcePixelBuffer.size() };
+ auto clampedSize = ImageBuffer::clampedSize(sourceRect.size());
+
+ auto& sourceColorSpace = sourcePixelBuffer.format().colorSpace;
+ auto imageBuffer = ImageBuffer::create(clampedSize, RenderingMode::Unaccelerated, 1, sourceColorSpace, PixelFormat::BGRA8);
+ if (!imageBuffer)
+ return std::nullopt;
+
+ imageBuffer->putPixelBuffer(sourcePixelBuffer, sourceRect);
+ return getConvertedPixelBuffer(*imageBuffer, alphaFormat, sourceRect, colorSpace);
+}
+
+bool FilterImage::requiresPixelBufferColorSpaceConversion(std::optional<DestinationColorSpace> colorSpace) const
+{
+#if USE(CG)
+ // This function determines whether we need the step of an extra color space conversion
+ // We only need extra color conversion when 1) color space is different in the input
+ // AND 2) the filter is manipulating raw pixels
+ return colorSpace && m_colorSpace != *colorSpace;
+#else
+ // Additional color space conversion is not needed on non-CG
+ UNUSED_PARAM(colorSpace);
+ return false;
+#endif
+}
+
+std::optional<PixelBuffer>& FilterImage::pixelBufferSlot(AlphaPremultiplication alphaFormat)
+{
+ return alphaFormat == AlphaPremultiplication::Unpremultiplied ? m_unpremultipliedPixelBuffer : m_premultipliedPixelBuffer;
+}
+
+PixelBuffer* FilterImage::pixelBuffer(AlphaPremultiplication alphaFormat)
+{
+ auto& pixelBuffer = pixelBufferSlot(alphaFormat);
+ if (pixelBuffer)
+ return &pixelBuffer.value();
+
+ PixelBufferFormat format { alphaFormat, PixelFormat::RGBA8, m_colorSpace };
+
+ if (m_imageBuffer) {
+ pixelBuffer = m_imageBuffer->getPixelBuffer(format, { { }, m_absoluteImageRect.size() });
+ if (!pixelBuffer)
+ return nullptr;
+ return &pixelBuffer.value();
+ }
+
+ IntSize logicalSize(m_absoluteImageRect.size());
+ ASSERT(!ImageBuffer::sizeNeedsClamping(logicalSize));
+
+ pixelBuffer = PixelBuffer::tryCreate(format, logicalSize);
+ if (!pixelBuffer)
+ return nullptr;
+
+ if (alphaFormat == AlphaPremultiplication::Unpremultiplied) {
+ if (auto& sourcePixelBuffer = pixelBufferSlot(AlphaPremultiplication::Premultiplied))
+ copyImageBytes(*sourcePixelBuffer, *pixelBuffer);
+ } else {
+ if (auto& sourcePixelBuffer = pixelBufferSlot(AlphaPremultiplication::Unpremultiplied))
+ copyImageBytes(*sourcePixelBuffer, *pixelBuffer);
+ }
+
+ return &pixelBuffer.value();
+}
+
+std::optional<PixelBuffer> FilterImage::getPixelBuffer(AlphaPremultiplication alphaFormat, const IntRect& sourceRect, std::optional<DestinationColorSpace> colorSpace)
+{
+ ASSERT(!ImageBuffer::sizeNeedsClamping(sourceRect.size()));
+
+ PixelBufferFormat format { alphaFormat, PixelFormat::RGBA8, colorSpace? *colorSpace : m_colorSpace };
+
+ auto pixelBuffer = PixelBuffer::tryCreate(format, sourceRect.size());
+ if (!pixelBuffer)
+ return std::nullopt;
+
+ copyPixelBuffer(*pixelBuffer, sourceRect);
+ return pixelBuffer;
+}
+
+void FilterImage::copyPixelBuffer(PixelBuffer& destinationPixelBuffer, const IntRect& sourceRect)
+{
+ auto alphaFormat = destinationPixelBuffer.format().alphaFormat;
+ auto& colorSpace = destinationPixelBuffer.format().colorSpace;
+
+ auto* sourcePixelBuffer = pixelBufferSlot(alphaFormat) ? &pixelBufferSlot(alphaFormat).value() : nullptr;
+
+ if (!sourcePixelBuffer) {
+ if (requiresPixelBufferColorSpaceConversion(colorSpace)) {
+ // We prefer a conversion from the image buffer.
+ if (m_imageBuffer) {
+ IntRect rect { { }, m_absoluteImageRect.size() };
+ if (auto convertedPixelBuffer = getConvertedPixelBuffer(*m_imageBuffer, alphaFormat, rect, colorSpace))
+ copyImageBytes(*convertedPixelBuffer, destinationPixelBuffer, sourceRect);
+ return;
+ }
+ }
+
+ sourcePixelBuffer = this->pixelBuffer(alphaFormat);
+ }
+
+ if (!sourcePixelBuffer)
+ return;
+
+ if (requiresPixelBufferColorSpaceConversion(colorSpace)) {
+ if (auto convertedPixelBuffer = getConvertedPixelBuffer(*sourcePixelBuffer, alphaFormat, colorSpace))
+ copyImageBytes(*convertedPixelBuffer, destinationPixelBuffer, sourceRect);
+ return;
+ }
+
+ copyImageBytes(*sourcePixelBuffer, destinationPixelBuffer, sourceRect);
+}
+
+void FilterImage::correctPremultipliedPixelBuffer()
+{
+ // Must operate on pre-multiplied results; other formats cannot have invalid pixels.
+ if (!m_premultipliedPixelBuffer)
+ return;
+
+ Uint8ClampedArray& imageArray = m_premultipliedPixelBuffer->data();
+ uint8_t* pixelData = imageArray.data();
+ int pixelArrayLength = imageArray.length();
+
+ // We must have four bytes per pixel, and complete pixels
+ ASSERT(!(pixelArrayLength % 4));
+
+#if HAVE(ARM_NEON_INTRINSICS)
+ if (pixelArrayLength >= 64) {
+ uint8_t* lastPixel = pixelData + (pixelArrayLength & ~0x3f);
+ do {
+ // Increments pixelData by 64.
+ uint8x16x4_t sixteenPixels = vld4q_u8(pixelData);
+ sixteenPixels.val[0] = vminq_u8(sixteenPixels.val[0], sixteenPixels.val[3]);
+ sixteenPixels.val[1] = vminq_u8(sixteenPixels.val[1], sixteenPixels.val[3]);
+ sixteenPixels.val[2] = vminq_u8(sixteenPixels.val[2], sixteenPixels.val[3]);
+ vst4q_u8(pixelData, sixteenPixels);
+ pixelData += 64;
+ } while (pixelData < lastPixel);
+
+ pixelArrayLength &= 0x3f;
+ if (!pixelArrayLength)
+ return;
+ }
+#endif
+
+ int numPixels = pixelArrayLength / 4;
+
+ // Iterate over each pixel, checking alpha and adjusting color components if necessary
+ while (--numPixels >= 0) {
+ // Alpha is the 4th byte in a pixel
+ uint8_t a = *(pixelData + 3);
+ // Clamp each component to alpha, and increment the pixel location
+ for (int i = 0; i < 3; ++i) {
+ if (*pixelData > a)
+ *pixelData = a;
+ ++pixelData;
+ }
+ // Increment for alpha
+ ++pixelData;
+ }
+}
+
+void FilterImage::transformToColorSpace(const DestinationColorSpace& colorSpace)
+{
+#if USE(CG)
+ // CG handles color space adjustments internally.
+ UNUSED_PARAM(colorSpace);
+#else
+ if (colorSpace == m_colorSpace)
+ return;
+
+ // FIXME: We can avoid this potentially unnecessary ImageBuffer conversion by adding
+ // color space transform support for the {pre,un}multiplied arrays.
+ if (auto imageBuffer = this->imageBuffer())
+ imageBuffer->transformToColorSpace(colorSpace);
+
+ m_colorSpace = colorSpace;
+ m_unpremultipliedPixelBuffer = std::nullopt;
+ m_premultipliedPixelBuffer = std::nullopt;
+#endif
+}
+
+} // namespace WebCore
Added: trunk/Source/WebCore/platform/graphics/filters/FilterImage.h (0 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/FilterImage.h (rev 0)
+++ trunk/Source/WebCore/platform/graphics/filters/FilterImage.h 2021-11-23 09:22:16 UTC (rev 286129)
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "ImageBuffer.h"
+#include "PixelBuffer.h"
+#include <_javascript_Core/Forward.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class ImageBuffer;
+class PixelBuffer;
+
+class FilterImage : public RefCounted<FilterImage> {
+public:
+ static RefPtr<FilterImage> create(const IntRect& absoluteImageRect, RenderingMode, const DestinationColorSpace&);
+
+ IntRect absoluteImageRect() const { return m_absoluteImageRect; }
+
+ RenderingMode renderingMode() const { return m_renderingMode; }
+ const DestinationColorSpace& colorSpace() const { return m_colorSpace; }
+
+ ImageBuffer* imageBuffer();
+ PixelBuffer* pixelBuffer(AlphaPremultiplication);
+
+ std::optional<PixelBuffer> getPixelBuffer(AlphaPremultiplication, const IntRect& sourceRect, std::optional<DestinationColorSpace> = std::nullopt);
+ void copyPixelBuffer(PixelBuffer& destinationPixelBuffer, const IntRect& sourceRect);
+
+ void correctPremultipliedPixelBuffer();
+ void transformToColorSpace(const DestinationColorSpace&);
+
+private:
+ FilterImage(const IntRect& absoluteImageRect, RenderingMode, const DestinationColorSpace&);
+
+ std::optional<PixelBuffer>& pixelBufferSlot(AlphaPremultiplication);
+
+ bool requiresPixelBufferColorSpaceConversion(std::optional<DestinationColorSpace>) const;
+
+ IntRect m_absoluteImageRect;
+
+ RenderingMode m_renderingMode;
+ DestinationColorSpace m_colorSpace;
+
+ RefPtr<ImageBuffer> m_imageBuffer;
+ std::optional<PixelBuffer> m_unpremultipliedPixelBuffer;
+ std::optional<PixelBuffer> m_premultipliedPixelBuffer;
+};
+
+} // namespace WebCore
Modified: trunk/Source/WebCore/platform/graphics/filters/SourceAlpha.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/SourceAlpha.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/SourceAlpha.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -47,7 +47,7 @@
bool SourceAlpha::platformApplySoftware(const Filter&)
{
- ImageBuffer* resultImage = createImageBufferResult();
+ ImageBuffer* resultImage = imageBufferResult();
if (!resultImage)
return false;
Modified: trunk/Source/WebCore/platform/graphics/filters/SourceGraphic.cpp (286128 => 286129)
--- trunk/Source/WebCore/platform/graphics/filters/SourceGraphic.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/platform/graphics/filters/SourceGraphic.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -34,7 +34,6 @@
SourceGraphic::SourceGraphic()
: FilterEffect(FilterEffect::Type::SourceGraphic)
{
- setOperatingColorSpace(DestinationColorSpace::SRGB());
}
void SourceGraphic::determineAbsolutePaintRect(const Filter& filter)
@@ -45,7 +44,7 @@
bool SourceGraphic::platformApplySoftware(const Filter& filter)
{
- ImageBuffer* resultImage = createImageBufferResult();
+ ImageBuffer* resultImage = imageBufferResult();
ImageBuffer* sourceImage = filter.sourceImage();
if (!resultImage || !sourceImage)
return false;
Modified: trunk/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp (286128 => 286129)
--- trunk/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -241,7 +241,7 @@
if (!lastEffect->hasResult()) {
filterData.state = FilterData::Applying;
filterData.filter->apply();
- lastEffect->correctFilterResultIfNeeded();
+ lastEffect->correctPremultipliedResultIfNeeded();
lastEffect->transformResultColorSpace(DestinationColorSpace::SRGB());
}
filterData.state = FilterData::Built;
Modified: trunk/Source/WebCore/svg/graphics/filters/SVGFEImage.cpp (286128 => 286129)
--- trunk/Source/WebCore/svg/graphics/filters/SVGFEImage.cpp 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/svg/graphics/filters/SVGFEImage.cpp 2021-11-23 09:22:16 UTC (rev 286129)
@@ -76,10 +76,7 @@
bool FEImage::platformApplySoftware(const Filter& filter)
{
- // FEImage results are always in DestinationColorSpace::SRGB()
- setResultColorSpace(DestinationColorSpace::SRGB());
-
- ImageBuffer* resultImage = createImageBufferResult();
+ auto resultImage = imageBufferResult();
if (!resultImage)
return false;
Modified: trunk/Source/WebCore/svg/graphics/filters/SVGFEImage.h (286128 => 286129)
--- trunk/Source/WebCore/svg/graphics/filters/SVGFEImage.h 2021-11-23 08:57:03 UTC (rev 286128)
+++ trunk/Source/WebCore/svg/graphics/filters/SVGFEImage.h 2021-11-23 09:22:16 UTC (rev 286129)
@@ -44,6 +44,9 @@
private:
FEImage(SourceImage&&, const FloatRect& sourceImageRect, const SVGPreserveAspectRatioValue&);
+ // FEImage results are always in DestinationColorSpace::SRGB()
+ void setOperatingColorSpace(const DestinationColorSpace&) override { }
+
void determineAbsolutePaintRect(const Filter&) final;
bool platformApplySoftware(const Filter&) final;