Changeset 286129 in webkit
- Timestamp:
- Nov 23, 2021, 1:22:16 AM (5 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 2 added
- 31 edited
-
ChangeLog (modified) (1 diff)
-
Sources.txt (modified) (1 diff)
-
WebCore.xcodeproj/project.pbxproj (modified) (2 diffs)
-
platform/graphics/coreimage/FilterEffectRendererCoreImage.mm (modified) (1 diff)
-
platform/graphics/cpu/arm/filters/FEBlendNEON.h (modified) (2 diffs)
-
platform/graphics/filters/FEBlend.cpp (modified) (1 diff)
-
platform/graphics/filters/FEColorMatrix.cpp (modified) (1 diff)
-
platform/graphics/filters/FEComponentTransfer.cpp (modified) (2 diffs)
-
platform/graphics/filters/FEComposite.cpp (modified) (2 diffs)
-
platform/graphics/filters/FEComposite.h (modified) (1 diff)
-
platform/graphics/filters/FEConvolveMatrix.cpp (modified) (1 diff)
-
platform/graphics/filters/FEDisplacementMap.cpp (modified) (5 diffs)
-
platform/graphics/filters/FEDisplacementMap.h (modified) (1 diff)
-
platform/graphics/filters/FEDropShadow.cpp (modified) (2 diffs)
-
platform/graphics/filters/FEFlood.cpp (modified) (1 diff)
-
platform/graphics/filters/FEFlood.h (modified) (1 diff)
-
platform/graphics/filters/FEGaussianBlur.cpp (modified) (2 diffs)
-
platform/graphics/filters/FELighting.cpp (modified) (2 diffs)
-
platform/graphics/filters/FEMerge.cpp (modified) (2 diffs)
-
platform/graphics/filters/FEMorphology.cpp (modified) (2 diffs)
-
platform/graphics/filters/FEMorphology.h (modified) (1 diff)
-
platform/graphics/filters/FEOffset.cpp (modified) (1 diff)
-
platform/graphics/filters/FETile.cpp (modified) (1 diff)
-
platform/graphics/filters/FETurbulence.cpp (modified) (1 diff)
-
platform/graphics/filters/FilterEffect.cpp (modified) (6 diffs)
-
platform/graphics/filters/FilterEffect.h (modified) (6 diffs)
-
platform/graphics/filters/FilterImage.cpp (added)
-
platform/graphics/filters/FilterImage.h (added)
-
platform/graphics/filters/SourceAlpha.cpp (modified) (1 diff)
-
platform/graphics/filters/SourceGraphic.cpp (modified) (2 diffs)
-
rendering/svg/RenderSVGResourceFilter.cpp (modified) (1 diff)
-
svg/graphics/filters/SVGFEImage.cpp (modified) (1 diff)
-
svg/graphics/filters/SVGFEImage.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r286126 r286129 1 2021-11-23 Said Abou-Hallawa <said@apple.com> 2 3 [GPU Process] Refactor the FilterEffect result buffers into a new class named 'FilterImage' 4 https://bugs.webkit.org/show_bug.cgi?id=225088 5 rdar://77487760 6 7 Reviewed by Cameron McCormack. 8 9 Move the storage and the logic for managing the result of applying the 10 FilterEffect to its inputs to a new class named 'FilterImage'. This will 11 simplify the implementation of FilterEffect. It will also allow integrating 12 the CoreImage seamlessly and simplifying the geometry calculation. 13 14 Instead of having three ways to create the result of a FilterEffect, there 15 will be one way which is by calling FilterImage::create(). This call will 16 not create a concrete result. But requesting the ImageBuffer or a PixelBuffer 17 from FilterImage will make this creation happen 18 19 The default of the operating ColorSpace is sRGB. But it will be set to 20 linearRGB if the color interpolation of the filter effect element is 21 linearRGB. The only exception is the FEImage whose result has to be in 22 sRGB always. 23 24 The default value of the result ColorSpace is the operating ColorSpace. 25 The only exception is FEDisplacementMap whose result has to be in the 26 ColorSpace of its first input FilterEffect. 27 28 * Sources.txt: 29 * WebCore.xcodeproj/project.pbxproj: 30 * platform/graphics/coreimage/FilterEffectRendererCoreImage.mm: 31 (WebCore::FilterEffectRendererCoreImage::connectCIFilters): 32 * platform/graphics/cpu/arm/filters/FEBlendNEON.h: 33 (WebCore::FEBlend::platformApplySoftware): 34 * platform/graphics/filters/FEBlend.cpp: 35 (WebCore::FEBlend::platformApplySoftware): 36 * platform/graphics/filters/FEColorMatrix.cpp: 37 (WebCore::FEColorMatrix::platformApplySoftware): 38 * platform/graphics/filters/FEComponentTransfer.cpp: 39 (WebCore::FEComponentTransfer::platformApplySoftware): 40 * platform/graphics/filters/FEComposite.cpp: 41 (WebCore::FEComposite::platformApplySoftware): 42 (WebCore::FEComposite::correctFilterResultIfNeeded): Deleted. 43 * platform/graphics/filters/FEComposite.h: 44 requiresValidPreMultipliedPixels() is replaced by the opposite 45 mayProduceInvalidPremultipliedPixels(). Correcting the premultiplied 46 result will be done by FilterEffect. 47 48 * platform/graphics/filters/FEConvolveMatrix.cpp: 49 (WebCore::FEConvolveMatrix::platformApplySoftware): 50 * platform/graphics/filters/FEDisplacementMap.cpp: 51 (WebCore::FEDisplacementMap::resultColorSpace const): 52 (WebCore::FEDisplacementMap::platformApplySoftware): 53 (WebCore::FEDisplacementMap::setResultColorSpace): Deleted. 54 * platform/graphics/filters/FEDisplacementMap.h: 55 (WebCore::FEDisplacementMap::xChannelIndex const): 56 (WebCore::FEDisplacementMap::yChannelIndex const): 57 * platform/graphics/filters/FEDropShadow.cpp: 58 (WebCore::FEDropShadow::platformApplySoftware): 59 * platform/graphics/filters/FEFlood.cpp: 60 (WebCore::FEFlood::platformApplySoftware): 61 * platform/graphics/filters/FEFlood.h: 62 * platform/graphics/filters/FEGaussianBlur.cpp: 63 (WebCore::FEGaussianBlur::platformApplySoftware): 64 * platform/graphics/filters/FELighting.cpp: 65 (WebCore::FELighting::platformApplySoftware): 66 * platform/graphics/filters/FEMerge.cpp: 67 (WebCore::FEMerge::platformApplySoftware): 68 * platform/graphics/filters/FEMorphology.cpp: 69 (WebCore::FEMorphology::platformApplySoftware): 70 * platform/graphics/filters/FEOffset.cpp: 71 (WebCore::FEOffset::platformApplySoftware): 72 * platform/graphics/filters/FETile.cpp: 73 (WebCore::FETile::platformApplySoftware): 74 * platform/graphics/filters/FETurbulence.cpp: 75 (WebCore::FETurbulence::platformApplySoftware): 76 * platform/graphics/filters/FilterEffect.cpp: 77 (WebCore::FilterEffect::apply): 78 (WebCore::FilterEffect::createResult): 79 80 (WebCore::FilterEffect::clearResult): 81 (WebCore::FilterEffect::clearResultsRecursive): 82 Clearing the result can be done by nullifying a single pointer. 83 84 (WebCore::FilterEffect::imageBufferResult): 85 (WebCore::FilterEffect::unpremultipliedResult): 86 (WebCore::FilterEffect::premultipliedResult): 87 (WebCore::FilterEffect::getUnpremultipliedResult): 88 (WebCore::FilterEffect::getPremultipliedResult): 89 (WebCore::FilterEffect::copyUnpremultipliedResult const): 90 (WebCore::FilterEffect::copyPremultipliedResult const): 91 (WebCore::FilterEffect::correctPremultipliedResultIfNeeded): 92 (WebCore::FilterEffect::transformResultColorSpace): 93 (WebCore::FilterEffect::externalRepresentation const): 94 (WebCore::FilterEffect::forceValidPreMultipliedPixels): Deleted. 95 (WebCore::FilterEffect::unmultipliedResult): Deleted. 96 (WebCore::FilterEffect::copyImageBytes const): Deleted. 97 (WebCore::copyPremultiplyingAlpha): Deleted. 98 (WebCore::copyUnpremultiplyingAlpha): Deleted. 99 (WebCore::FilterEffect::convertPixelBufferToColorSpace): Deleted. 100 (WebCore::FilterEffect::convertImageBufferToColorSpace): Deleted. 101 (WebCore::FilterEffect::copyConvertedImageBufferToDestination): Deleted. 102 (WebCore::FilterEffect::copyConvertedPixelBufferToDestination): Deleted. 103 (WebCore::FilterEffect::copyUnmultipliedResult): Deleted. 104 (WebCore::FilterEffect::copyPremultipliedResult): Deleted. 105 (WebCore::FilterEffect::createImageBufferResult): Deleted. 106 (WebCore::FilterEffect::createUnmultipliedImageResult): Deleted. 107 (WebCore::FilterEffect::createPremultipliedImageResult): Deleted. 108 (WebCore::FilterEffect::requiresPixelBufferColorSpaceConversion): Deleted. 109 All the logic of these functions was moved to FilterImage.cpp. 110 111 * platform/graphics/filters/FilterEffect.h: 112 (WebCore::FilterEffect::hasResult const): 113 (WebCore::FilterEffect::resultColorSpace const): 114 (WebCore::FilterEffect::mayProduceInvalidPremultipliedPixels const): 115 (WebCore::FilterEffect::correctFilterResultIfNeeded): Deleted. 116 (WebCore::FilterEffect::setResultColorSpace): Deleted. 117 (WebCore::FilterEffect::requiresValidPreMultipliedPixels): Deleted. 118 * platform/graphics/filters/FilterImage.cpp: Added. 119 (WebCore::FilterImage::create): 120 (WebCore::FilterImage::FilterImage): 121 (WebCore::FilterImage::imageBuffer): 122 (WebCore::copyPremultiplyingAlpha): 123 (WebCore::copyUnpremultiplyingAlpha): 124 (WebCore::FilterImage::pixelBufferIfExists): 125 (WebCore::FilterImage::pixelBuffer): 126 (WebCore::FilterImage::getPixelBuffer): 127 (WebCore::FilterImage::requiresPixelBufferColorSpaceConversion const): 128 (WebCore::FilterImage::copyImageBytes const): 129 (WebCore::FilterImage::getConvertedPixelBuffer const): 130 (WebCore::FilterImage::copyPixelBuffer): 131 (WebCore::FilterImage::correctPremultipliedPixelBuffer): 132 (WebCore::FilterImage::transformToColorSpace): 133 * platform/graphics/filters/FilterImage.h: Added. 134 (WebCore::FilterImage::absoluteImageRect const): 135 (WebCore::FilterImage::renderingMode const): 136 (WebCore::FilterImage::colorSpace const): 137 (WebCore::FilterImage::imageBufferIfExists): 138 * platform/graphics/filters/SourceAlpha.cpp: 139 (WebCore::SourceAlpha::platformApplySoftware): 140 * platform/graphics/filters/SourceGraphic.cpp: 141 (WebCore::SourceGraphic::platformApplySoftware): 142 * platform/graphics/filters/SourceGraphic.h: 143 (WebCore::SourceGraphic::SourceGraphic): 144 * rendering/svg/RenderSVGResourceFilter.cpp: 145 (WebCore::RenderSVGResourceFilter::postApplyResource): 146 * svg/graphics/filters/SVGFEImage.cpp: 147 (WebCore::FEImage::platformApplySoftware): 148 * svg/graphics/filters/SVGFEImage.h: 149 1 150 2021-11-22 Simon Fraser <simon.fraser@apple.com> 2 151 -
trunk/Source/WebCore/Sources.txt
r286112 r286129 2104 2104 platform/graphics/filters/FilterEffectRenderer.cpp 2105 2105 platform/graphics/filters/FilterFunction.cpp 2106 platform/graphics/filters/FilterImage.cpp 2106 2107 platform/graphics/filters/FilterOperation.cpp 2107 2108 platform/graphics/filters/FilterOperations.cpp -
trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj
r286112 r286129 10868 10868 721B49702512AC0400FE9D3B /* ImageBitmapBacking.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImageBitmapBacking.h; sourceTree = "<group>"; }; 10869 10869 722A815C238FD50500C00583 /* AnimationFrameRate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AnimationFrameRate.h; sourceTree = "<group>"; }; 10870 72435EF4273D07670005E7EE /* FilterImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FilterImage.h; sourceTree = "<group>"; }; 10871 72435EF5273D07670005E7EE /* FilterImage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FilterImage.cpp; sourceTree = "<group>"; }; 10870 10872 724ED3291A3A7E5400F5F13C /* EXTBlendMinMax.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EXTBlendMinMax.cpp; sourceTree = "<group>"; }; 10871 10873 724ED32A1A3A7E5400F5F13C /* EXTBlendMinMax.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EXTBlendMinMax.h; sourceTree = "<group>"; }; … … 25946 25948 7262D757272A174100C56A09 /* FilterFunction.cpp */, 25947 25949 7262D756272A174100C56A09 /* FilterFunction.h */, 25950 72435EF5273D07670005E7EE /* FilterImage.cpp */, 25951 72435EF4273D07670005E7EE /* FilterImage.h */, 25948 25952 49ECEB631499790D00CDD3A4 /* FilterOperation.cpp */, 25949 25953 49ECEB641499790D00CDD3A4 /* FilterOperation.h */, -
trunk/Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm
r285796 r286129 117 117 } 118 118 effect.determineAbsolutePaintRect(filter); 119 effect.setResultColorSpace(effect.operatingColorSpace());120 119 121 120 if (effect.absolutePaintRect().isEmpty() || ImageBuffer::sizeNeedsClamping(effect.absolutePaintRect().size())) -
trunk/Source/WebCore/platform/graphics/cpu/arm/filters/FEBlendNEON.h
r285916 r286129 112 112 FilterEffect* in2 = inputEffect(1); 113 113 114 auto& destinationPixelBuffer = createPremultipliedImageResult();114 auto& destinationPixelBuffer = pixelBufferResult(AlphaPremultiplication::Premultiplied); 115 115 if (!destinationPixelBuffer) 116 116 return false; … … 119 119 120 120 IntRect effectADrawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect()); 121 auto sourcePixelArrayA = in-> premultipliedResult(effectADrawingRect);121 auto sourcePixelArrayA = in->getPixelBufferResult(AlphaPremultiplication::Premultiplied, effectADrawingRect); 122 122 123 123 IntRect effectBDrawingRect = requestedRegionOfInputPixelBuffer(in2->absolutePaintRect()); 124 auto sourcePixelArrayB = in2-> premultipliedResult(effectBDrawingRect);124 auto sourcePixelArrayB = in2->getPixelBufferResult(AlphaPremultiplication::Premultiplied, effectBDrawingRect); 125 125 126 126 unsigned sourcePixelArrayLength = sourcePixelArrayA->length(); -
trunk/Source/WebCore/platform/graphics/filters/FEBlend.cpp
r285916 r286129 60 60 FilterEffect* in2 = inputEffect(1); 61 61 62 ImageBuffer* resultImage = createImageBufferResult();62 auto resultImage = imageBufferResult(); 63 63 if (!resultImage) 64 64 return false; 65 GraphicsContext& filterContext = resultImage->context();66 65 67 ImageBuffer*imageBuffer = in->imageBufferResult();68 ImageBuffer*imageBuffer2 = in2->imageBufferResult();66 auto imageBuffer = in->imageBufferResult(); 67 auto imageBuffer2 = in2->imageBufferResult(); 69 68 if (!imageBuffer || !imageBuffer2) 70 69 return false; 71 70 71 GraphicsContext& filterContext = resultImage->context(); 72 72 filterContext.drawImageBuffer(*imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect())); 73 73 filterContext.drawImageBuffer(*imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()), { { }, imageBuffer->logicalSize() }, { CompositeOperator::SourceOver, m_mode }); -
trunk/Source/WebCore/platform/graphics/filters/FEColorMatrix.cpp
r285916 r286129 278 278 FilterEffect* in = inputEffect(0); 279 279 280 ImageBuffer* resultImage = createImageBufferResult();280 auto resultImage = imageBufferResult(); 281 281 if (!resultImage) 282 282 return false; 283 283 284 ImageBuffer*inBuffer = in->imageBufferResult();284 auto inBuffer = in->imageBufferResult(); 285 285 if (inBuffer) 286 286 resultImage->context().drawImageBuffer(*inBuffer, drawingRegionOfInputImage(in->absolutePaintRect())); -
trunk/Source/WebCore/platform/graphics/filters/FEComponentTransfer.cpp
r285916 r286129 106 106 FilterEffect* in = inputEffect(0); 107 107 108 auto & destinationPixelBuffer = createUnmultipliedImageResult();108 auto destinationPixelBuffer = pixelBufferResult(AlphaPremultiplication::Unpremultiplied); 109 109 if (!destinationPixelBuffer) 110 110 return false; 111 112 auto& destinationPixelArray = destinationPixelBuffer->data();113 111 114 112 LookupTable redTable; … … 119 117 120 118 IntRect drawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect()); 121 in->copyUnmultipliedResult(destinationPixelArray, drawingRect, operatingColorSpace()); 119 in->copyPixelBufferResult(*destinationPixelBuffer, drawingRect); 120 121 auto& destinationPixelArray = destinationPixelBuffer->data(); 122 uint8_t* data = destinationPixelArray.data(); 122 123 unsigned destinationPixelArrayLength = destinationPixelArray.length(); 123 uint8_t* data = destinationPixelArray.data(); 124 124 125 for (unsigned pixelOffset = 0; pixelOffset < destinationPixelArrayLength; pixelOffset += 4) { 125 126 data[pixelOffset] = redTable[data[pixelOffset]]; -
trunk/Source/WebCore/platform/graphics/filters/FEComposite.cpp
r285916 r286129 88 88 } 89 89 90 void FEComposite::correctFilterResultIfNeeded()91 {92 if (m_type != FECOMPOSITE_OPERATOR_ARITHMETIC)93 return;94 95 forceValidPreMultipliedPixels();96 }97 98 90 static unsigned char clampByte(int c) 99 91 { … … 230 222 231 223 if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC) { 232 auto & destinationPixelBuffer = createPremultipliedImageResult();224 auto destinationPixelBuffer = pixelBufferResult(AlphaPremultiplication::Premultiplied); 233 225 if (!destinationPixelBuffer) 234 226 return false; 235 227 228 IntRect effectADrawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect()); 229 auto sourcePixelBuffer = in->getPixelBufferResult(AlphaPremultiplication::Premultiplied, effectADrawingRect, operatingColorSpace()); 230 if (!sourcePixelBuffer) 231 return false; 232 233 IntRect effectBDrawingRect = requestedRegionOfInputPixelBuffer(in2->absolutePaintRect()); 234 in2->copyPixelBufferResult(*destinationPixelBuffer, effectBDrawingRect); 235 236 auto& sourcePixelArray = sourcePixelBuffer->data(); 236 237 auto& destinationPixelArray = destinationPixelBuffer->data(); 237 238 IntRect effectADrawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect()); 239 auto sourcePixelArray = in->premultipliedResult(effectADrawingRect, operatingColorSpace()); 240 if (!sourcePixelArray) 241 return false; 242 243 IntRect effectBDrawingRect = requestedRegionOfInputPixelBuffer(in2->absolutePaintRect()); 244 in2->copyPremultipliedResult(destinationPixelArray, effectBDrawingRect, operatingColorSpace()); 245 246 platformArithmeticSoftware(*sourcePixelArray, destinationPixelArray, m_k1, m_k2, m_k3, m_k4); 238 platformArithmeticSoftware(sourcePixelArray, destinationPixelArray, m_k1, m_k2, m_k3, m_k4); 247 239 return true; 248 240 } 249 241 250 ImageBuffer* resultImage = createImageBufferResult();242 auto resultImage = imageBufferResult(); 251 243 if (!resultImage) 252 244 return false; 245 246 auto imageBuffer = in->imageBufferResult(); 247 auto imageBuffer2 = in2->imageBufferResult(); 248 if (!imageBuffer || !imageBuffer2) 249 return false; 250 253 251 GraphicsContext& filterContext = resultImage->context(); 254 255 ImageBuffer* imageBuffer = in->imageBufferResult();256 ImageBuffer* imageBuffer2 = in2->imageBufferResult();257 if (!imageBuffer || !imageBuffer2)258 return false;259 252 260 253 switch (m_type) { -
trunk/Source/WebCore/platform/graphics/filters/FEComposite.h
r285916 r286129 60 60 FEComposite(const CompositeOperationType&, float k1, float k2, float k3, float k4); 61 61 62 void correctFilterResultIfNeeded() override;62 void determineAbsolutePaintRect(const Filter&) override; 63 63 64 bool requiresValidPreMultipliedPixels() override { return m_type != FECOMPOSITE_OPERATOR_ARITHMETIC; } 65 66 void determineAbsolutePaintRect(const Filter&) override; 64 bool mayProduceInvalidPremultipliedPixels() const override { return m_type == FECOMPOSITE_OPERATOR_ARITHMETIC; } 67 65 68 66 bool platformApplySoftware(const Filter&) override; -
trunk/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp
r285916 r286129 366 366 FilterEffect* in = inputEffect(0); 367 367 368 auto& destinationPixelBuffer = m_preserveAlpha ? createUnmultipliedImageResult() : createPremultipliedImageResult(); 368 auto alphaFormat = m_preserveAlpha ? AlphaPremultiplication::Unpremultiplied : AlphaPremultiplication::Premultiplied; 369 auto destinationPixelBuffer = pixelBufferResult(alphaFormat); 369 370 if (!destinationPixelBuffer) 370 371 return false; 371 372 373 IntRect effectDrawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect()); 374 auto sourcePixelBuffer = in->getPixelBufferResult(alphaFormat, effectDrawingRect, operatingColorSpace()); 375 if (!sourcePixelBuffer) 376 return false; 377 378 auto& sourcePixelArray = sourcePixelBuffer->data(); 372 379 auto& destinationPixelArray = destinationPixelBuffer->data(); 373 374 IntRect effectDrawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect());375 376 RefPtr<Uint8ClampedArray> sourcePixelArray;377 if (m_preserveAlpha)378 sourcePixelArray = in->unmultipliedResult(effectDrawingRect, operatingColorSpace());379 else380 sourcePixelArray = in->premultipliedResult(effectDrawingRect, operatingColorSpace());381 if (!sourcePixelArray)382 return false;383 380 384 381 IntSize paintSize = absolutePaintRect().size(); 385 382 386 383 PaintingData paintingData = { 387 *sourcePixelArray,384 sourcePixelArray, 388 385 destinationPixelArray, 389 386 paintSize.width(), -
trunk/Source/WebCore/platform/graphics/filters/FEDisplacementMap.cpp
r285916 r286129 69 69 } 70 70 71 void FEDisplacementMap::setResultColorSpace(const DestinationColorSpace&) 71 const DestinationColorSpace& FEDisplacementMap::resultColorSpace() const 72 72 { 73 73 // Spec: The 'color-interpolation-filters' property only applies to the 'in2' source image 74 74 // and does not apply to the 'in' source image. The 'in' source image must remain in its 75 75 // current color space. 76 // The result is in that s mae color space because it is a displacement of the 'in' image.77 FilterEffect::setResultColorSpace(inputEffect(0)->resultColorSpace());76 // The result is in that same color space because it is a displacement of the 'in' image. 77 return inputEffect(0)->resultColorSpace(); 78 78 } 79 79 … … 99 99 ASSERT(m_yChannelSelector != CHANNEL_UNKNOWN); 100 100 101 auto & destinationPixelBuffer = createPremultipliedImageResult();101 auto destinationPixelBuffer = pixelBufferResult(AlphaPremultiplication::Premultiplied); 102 102 if (!destinationPixelBuffer) 103 103 return false; … … 106 106 107 107 IntRect effectADrawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect()); 108 auto input Image = in->premultipliedResult(effectADrawingRect);108 auto inputPixelBuffer = in->getPixelBufferResult(AlphaPremultiplication::Premultiplied, effectADrawingRect); 109 109 110 110 IntRect effectBDrawingRect = requestedRegionOfInputPixelBuffer(in2->absolutePaintRect()); 111 111 // The calculations using the pixel values from ‘in2’ are performed using non-premultiplied color values. 112 auto displacement Image = in2->unmultipliedResult(effectBDrawingRect);112 auto displacementPixelBuffer = in2->getPixelBufferResult(AlphaPremultiplication::Unpremultiplied, effectBDrawingRect); 113 113 114 if (!input Image || !displacementImage)114 if (!inputPixelBuffer || !displacementPixelBuffer) 115 115 return false; 116 116 117 ASSERT(inputImage->length() == displacementImage->length()); 117 auto& inputImage = inputPixelBuffer->data(); 118 auto& displacementImage = displacementPixelBuffer->data(); 119 ASSERT(inputImage.length() == displacementImage.length()); 118 120 119 121 IntSize paintSize = absolutePaintRect().size(); … … 136 138 int destinationIndex = lineStartOffset + x * 4; 137 139 138 int srcX = x + static_cast<int>(scaleForColorX * displacementImage ->item(destinationIndex + displacementChannelX) + scaledOffsetX);139 int srcY = y + static_cast<int>(scaleForColorY * displacementImage ->item(destinationIndex + displacementChannelY) + scaledOffsetY);140 int srcX = x + static_cast<int>(scaleForColorX * displacementImage.item(destinationIndex + displacementChannelX) + scaledOffsetX); 141 int srcY = y + static_cast<int>(scaleForColorY * displacementImage.item(destinationIndex + displacementChannelY) + scaledOffsetY); 140 142 141 143 unsigned* destinationPixelPtr = reinterpret_cast<unsigned*>(destinationPixelArray.data() + destinationIndex); … … 145 147 } 146 148 147 *destinationPixelPtr = *reinterpret_cast<unsigned*>(inputImage ->data() + byteOffsetOfPixel(srcX, srcY, rowBytes));149 *destinationPixelPtr = *reinterpret_cast<unsigned*>(inputImage.data() + byteOffsetOfPixel(srcX, srcY, rowBytes)); 148 150 } 149 151 } -
trunk/Source/WebCore/platform/graphics/filters/FEDisplacementMap.h
r285916 r286129 48 48 bool setScale(float); 49 49 50 void setResultColorSpace(const DestinationColorSpace&) override;51 void transformResultColorSpace(FilterEffect*, const int) override;52 53 50 private: 54 51 FEDisplacementMap(ChannelSelectorType xChannelSelector, ChannelSelectorType yChannelSelector, float); 55 52 56 bool platformApplySoftware(const Filter&) override; 53 int xChannelIndex() const { return m_xChannelSelector - 1; } 54 int yChannelIndex() const { return m_yChannelSelector - 1; } 57 55 58 56 void determineAbsolutePaintRect(const Filter&) override { setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); } 59 57 60 int xChannelIndex() const { return m_xChannelSelector - 1; } 61 int yChannelIndex() const { return m_yChannelSelector - 1; } 58 const DestinationColorSpace& resultColorSpace() const override; 59 void transformResultColorSpace(FilterEffect*, const int) override; 60 61 bool platformApplySoftware(const Filter&) override; 62 62 63 63 WTF::TextStream& externalRepresentation(WTF::TextStream&, RepresentationType) const override; -
trunk/Source/WebCore/platform/graphics/filters/FEDropShadow.cpp
r285916 r286129 74 74 FilterEffect* in = inputEffect(0); 75 75 76 ImageBuffer* resultImage = createImageBufferResult();76 auto resultImage = imageBufferResult(); 77 77 if (!resultImage) 78 78 return false; … … 85 85 drawingRegionWithOffset.move(offset); 86 86 87 ImageBuffer*sourceImage = in->imageBufferResult();87 auto sourceImage = in->imageBufferResult(); 88 88 if (!sourceImage) 89 89 return false; -
trunk/Source/WebCore/platform/graphics/filters/FEFlood.cpp
r285916 r286129 61 61 bool FEFlood::platformApplySoftware(const Filter&) 62 62 { 63 ImageBuffer* resultImage = createImageBufferResult();63 auto resultImage = imageBufferResult(); 64 64 if (!resultImage) 65 65 return false; -
trunk/Source/WebCore/platform/graphics/filters/FEFlood.h
r285916 r286129 40 40 // feFlood does not perform color interpolation of any kind, so the result is always in the current 41 41 // color space regardless of the value of color-interpolation-filters. 42 void setOperatingColorSpace(const DestinationColorSpace&) override { FilterEffect::setResultColorSpace(DestinationColorSpace::SRGB()); } 43 void setResultColorSpace(const DestinationColorSpace&) override { FilterEffect::setResultColorSpace(DestinationColorSpace::SRGB()); } 42 void setOperatingColorSpace(const DestinationColorSpace&) override { } 44 43 #endif 45 44 -
trunk/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp
r285916 r286129 524 524 FilterEffect* in = inputEffect(0); 525 525 526 auto & destinationPixelBuffer = createPremultipliedImageResult();526 auto destinationPixelBuffer = pixelBufferResult(AlphaPremultiplication::Premultiplied); 527 527 if (!destinationPixelBuffer) 528 528 return false; 529 529 530 auto& destinationPixelArray = destinationPixelBuffer->data();531 532 530 setIsAlphaImage(in->isAlphaImage()); 533 531 534 532 IntRect effectDrawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect()); 535 in->copyP remultipliedResult(destinationPixelArray, effectDrawingRect, operatingColorSpace());533 in->copyPixelBufferResult(*destinationPixelBuffer, effectDrawingRect); 536 534 if (!m_stdX && !m_stdY) 537 535 return true; … … 544 542 return false; 545 543 544 auto& destinationPixelArray = destinationPixelBuffer->data(); 546 545 platformApply(destinationPixelArray, *tmpImageData, kernelSize.width(), kernelSize.height(), paintSize); 547 546 return true; -
trunk/Source/WebCore/platform/graphics/filters/FELighting.cpp
r285916 r286129 476 476 FilterEffect* in = inputEffect(0); 477 477 478 auto & destinationPixelBuffer = createPremultipliedImageResult();478 auto destinationPixelBuffer = pixelBufferResult(AlphaPremultiplication::Premultiplied); 479 479 if (!destinationPixelBuffer) 480 480 return false; 481 481 482 auto& destinationPixelArray = destinationPixelBuffer->data();483 484 482 setIsAlphaImage(false); 485 483 486 484 IntRect effectDrawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect()); 487 in->copyPremultipliedResult(destinationPixelArray, effectDrawingRect, operatingColorSpace()); 485 in->copyPixelBufferResult(*destinationPixelBuffer, effectDrawingRect); 486 488 487 // FIXME: support kernelUnitLengths other than (1,1). The issue here is that the W3 489 488 // standard has no test case for them, and other browsers (like Firefox) has strange … … 492 491 493 492 IntSize absolutePaintSize = absolutePaintRect().size(); 493 auto& destinationPixelArray = destinationPixelBuffer->data(); 494 494 495 drawLighting(destinationPixelArray, absolutePaintSize.width(), absolutePaintSize.height()); 495 496 return true; -
trunk/Source/WebCore/platform/graphics/filters/FEMerge.cpp
r285916 r286129 44 44 ASSERT(size > 0); 45 45 46 ImageBuffer* resultImage = createImageBufferResult();46 auto resultImage = imageBufferResult(); 47 47 if (!resultImage) 48 48 return false; … … 51 51 for (unsigned i = 0; i < size; ++i) { 52 52 FilterEffect* in = inputEffect(i); 53 if ( ImageBuffer*inBuffer = in->imageBufferResult())53 if (auto inBuffer = in->imageBufferResult()) 54 54 filterContext.drawImageBuffer(*inBuffer, drawingRegionOfInputImage(in->absolutePaintRect())); 55 55 } -
trunk/Source/WebCore/platform/graphics/filters/FEMorphology.cpp
r285916 r286129 230 230 } 231 231 232 bool FEMorphology::platformApplyDegenerate(Uint8ClampedArray& dstPixelArray, const IntRect& imageRect, int radiusX, int radiusY) 233 { 234 if (radiusX < 0 || radiusY < 0 || (!radiusX && !radiusY)) { 235 FilterEffect* in = inputEffect(0); 236 in->copyPremultipliedResult(dstPixelArray, imageRect, operatingColorSpace()); 232 bool FEMorphology::isDegenerate(int radiusX, int radiusY) const 233 { 234 return radiusX < 0 || radiusY < 0 || (!radiusX && !radiusY); 235 } 236 237 bool FEMorphology::platformApplySoftware(const Filter& filter) 238 { 239 FilterEffect* in = inputEffect(0); 240 241 auto destinationPixelBuffer = pixelBufferResult(AlphaPremultiplication::Premultiplied); 242 if (!destinationPixelBuffer) 243 return false; 244 245 setIsAlphaImage(in->isAlphaImage()); 246 247 IntRect effectDrawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect()); 248 249 IntSize radius = flooredIntSize(FloatSize(m_radiusX, m_radiusY)); 250 if (isDegenerate(radius.width(), radius.height())) { 251 in->copyPixelBufferResult(*destinationPixelBuffer, effectDrawingRect); 237 252 return true; 238 253 } 239 return false;240 }241 242 bool FEMorphology::platformApplySoftware(const Filter& filter)243 {244 FilterEffect* in = inputEffect(0);245 246 auto& destinationPixelBuffer = createPremultipliedImageResult();247 if (!destinationPixelBuffer)248 return false;249 250 auto& destinationPixelArray = destinationPixelBuffer->data();251 252 setIsAlphaImage(in->isAlphaImage());253 254 IntRect effectDrawingRect = requestedRegionOfInputPixelBuffer(in->absolutePaintRect());255 256 IntSize radius = flooredIntSize(FloatSize(m_radiusX, m_radiusY));257 if (platformApplyDegenerate(destinationPixelArray, effectDrawingRect, radius.width(), radius.height()))258 return true;259 260 auto sourcePixelArray = in->premultipliedResult(effectDrawingRect, operatingColorSpace());261 if (!sourcePixelArray)262 return false;263 254 264 255 radius = flooredIntSize(filter.scaledByFilterScale({ m_radiusX, m_radiusY })); … … 266 257 int radiusY = std::min(effectDrawingRect.height() - 1, radius.height()); 267 258 268 if (platformApplyDegenerate(destinationPixelArray, effectDrawingRect, radiusX, radiusY)) 259 if (isDegenerate(radiusX, radiusY)) { 260 in->copyPixelBufferResult(*destinationPixelBuffer, effectDrawingRect); 269 261 return true; 270 262 } 263 264 auto sourcePixelBuffer = in->getPixelBufferResult(AlphaPremultiplication::Premultiplied, effectDrawingRect, operatingColorSpace()); 265 if (!sourcePixelBuffer) 266 return false; 267 268 auto& sourcePixelArray = sourcePixelBuffer->data(); 269 auto& destinationPixelArray = destinationPixelBuffer->data(); 270 271 271 PaintingData paintingData; 272 paintingData.srcPixelArray = sourcePixelArray.get();272 paintingData.srcPixelArray = &sourcePixelArray; 273 273 paintingData.dstPixelArray = &destinationPixelArray; 274 274 paintingData.width = ceilf(effectDrawingRect.width()); -
trunk/Source/WebCore/platform/graphics/filters/FEMorphology.h
r285916 r286129 54 54 WTF::TextStream& externalRepresentation(WTF::TextStream&, RepresentationType) const override; 55 55 56 bool platformApplyDegenerate(Uint8ClampedArray& dstPixelArray, const IntRect& imageRect, int radiusX, int radiusY);56 bool isDegenerate(int radiusX, int radiusY) const; 57 57 58 58 struct PaintingData { -
trunk/Source/WebCore/platform/graphics/filters/FEOffset.cpp
r285916 r286129 69 69 FilterEffect* in = inputEffect(0); 70 70 71 ImageBuffer* resultImage = createImageBufferResult();72 ImageBuffer*inBuffer = in->imageBufferResult();71 auto resultImage = imageBufferResult(); 72 auto inBuffer = in->imageBufferResult(); 73 73 if (!resultImage || !inBuffer) 74 74 return false; -
trunk/Source/WebCore/platform/graphics/filters/FETile.cpp
r285916 r286129 45 45 bool FETile::platformApplySoftware(const Filter& filter) 46 46 { 47 // FIXME: See bug 47315. This is a hack to work around a compile failure, but is incorrect behavior otherwise.48 47 FilterEffect* in = inputEffect(0); 49 48 50 ImageBuffer* resultImage = createImageBufferResult();51 ImageBuffer*inBuffer = in->imageBufferResult();49 auto resultImage = imageBufferResult(); 50 auto inBuffer = in->imageBufferResult(); 52 51 if (!resultImage || !inBuffer) 53 52 return false; -
trunk/Source/WebCore/platform/graphics/filters/FETurbulence.cpp
r285916 r286129 396 396 bool FETurbulence::platformApplySoftware(const Filter& filter) 397 397 { 398 auto & destinationPixelBuffer = createUnmultipliedImageResult();398 auto destinationPixelBuffer = pixelBufferResult(AlphaPremultiplication::Unpremultiplied); 399 399 if (!destinationPixelBuffer) 400 400 return false; -
trunk/Source/WebCore/platform/graphics/filters/FilterEffect.cpp
r285916 r286129 28 28 #include "Filter.h" 29 29 #include "GeometryUtilities.h" 30 #include "GraphicsContext.h"31 30 #include "ImageBuffer.h" 32 31 #include "Logging.h" 33 32 #include "PixelBuffer.h" 34 #include <JavaScriptCore/JSCInlines.h>35 #include <JavaScriptCore/TypedArrayInlines.h>36 33 #include <wtf/text/TextStream.h> 37 34 38 #if HAVE(ARM_NEON_INTRINSICS)39 #include <arm_neon.h>40 #endif41 42 #if USE(ACCELERATE)43 #include <Accelerate/Accelerate.h>44 #endif45 46 35 namespace WebCore { 47 48 FilterEffect::FilterEffect(FilterEffect::Type type)49 : FilterFunction(type)50 {51 }52 36 53 37 void FilterEffect::determineAbsolutePaintRect(const Filter&) … … 158 142 159 143 determineAbsolutePaintRect(filter); 160 setResultColorSpace(m_operatingColorSpace);161 144 162 145 LOG_WITH_STREAM(Filters, stream … … 172 155 return false; 173 156 174 if ( requiresValidPreMultipliedPixels()) {175 for ( unsigned i = 0; i < size; ++i)176 in putEffect(i)->correctFilterResultIfNeeded();157 if (!mayProduceInvalidPremultipliedPixels()) { 158 for (auto& in : m_inputEffects) 159 in->correctPremultipliedResultIfNeeded(); 177 160 } 161 162 if (!createResult()) 163 return false; 178 164 179 165 // Add platform specific apply functions here and return earlier. … … 181 167 } 182 168 183 void FilterEffect::forceValidPreMultipliedPixels() 184 { 185 // Must operate on pre-multiplied results; other formats cannot have invalid pixels. 186 if (!m_premultipliedImageResult) 187 return; 188 189 auto& imageArray = m_premultipliedImageResult->data(); 190 uint8_t* pixelData = imageArray.data(); 191 int pixelArrayLength = imageArray.length(); 192 193 // We must have four bytes per pixel, and complete pixels 194 ASSERT(!(pixelArrayLength % 4)); 195 196 #if HAVE(ARM_NEON_INTRINSICS) 197 if (pixelArrayLength >= 64) { 198 uint8_t* lastPixel = pixelData + (pixelArrayLength & ~0x3f); 199 do { 200 // Increments pixelData by 64. 201 uint8x16x4_t sixteenPixels = vld4q_u8(pixelData); 202 sixteenPixels.val[0] = vminq_u8(sixteenPixels.val[0], sixteenPixels.val[3]); 203 sixteenPixels.val[1] = vminq_u8(sixteenPixels.val[1], sixteenPixels.val[3]); 204 sixteenPixels.val[2] = vminq_u8(sixteenPixels.val[2], sixteenPixels.val[3]); 205 vst4q_u8(pixelData, sixteenPixels); 206 pixelData += 64; 207 } while (pixelData < lastPixel); 208 209 pixelArrayLength &= 0x3f; 210 if (!pixelArrayLength) 211 return; 212 } 213 #endif 214 215 int numPixels = pixelArrayLength / 4; 216 217 // Iterate over each pixel, checking alpha and adjusting color components if necessary 218 while (--numPixels >= 0) { 219 // Alpha is the 4th byte in a pixel 220 uint8_t a = *(pixelData + 3); 221 // Clamp each component to alpha, and increment the pixel location 222 for (int i = 0; i < 3; ++i) { 223 if (*pixelData > a) 224 *pixelData = a; 225 ++pixelData; 226 } 227 // Increment for alpha 228 ++pixelData; 229 } 169 bool FilterEffect::createResult() 170 { 171 m_filterImage = FilterImage::create(m_absolutePaintRect, RenderingMode::Unaccelerated, resultColorSpace()); 172 return m_filterImage; 230 173 } 231 174 232 175 void FilterEffect::clearResult() 233 176 { 234 m_imageBufferResult = nullptr; 235 m_unmultipliedImageResult = std::nullopt; 236 m_premultipliedImageResult = std::nullopt; 177 m_filterImage = nullptr; 237 178 } 238 179 … … 241 182 // Clear all results, regardless that the current effect has 242 183 // a result. Can be used if an effect is in an erroneous state. 243 if (hasResult()) 244 clearResult(); 245 246 unsigned size = m_inputEffects.size(); 247 for (unsigned i = 0; i < size; ++i) 248 m_inputEffects.at(i).get()->clearResultsRecursive(); 184 clearResult(); 185 for (auto& effect : m_inputEffects) 186 effect->clearResultsRecursive(); 249 187 } 250 188 251 189 ImageBuffer* FilterEffect::imageBufferResult() 252 190 { 253 LOG_WITH_STREAM(Filters, stream << "FilterEffect " << filterName() << " " << this << " imageBufferResult(). Existing image buffer " << m_imageBufferResult.get() << " m_premultipliedImageResult " << m_premultipliedImageResult << " m_unmultipliedImageResult " << m_unmultipliedImageResult);254 255 191 if (!hasResult()) 256 192 return nullptr; 257 258 if (m_imageBufferResult) 259 return m_imageBufferResult.get(); 260 261 // FIXME: Respect the Filter::renderingMode() when creating the filter ImageBuffer result. 262 // For now just pass RenderingMode::Unaccelerated. This will not be a behavior change since 263 // this is what we do for the software filter code path anyway. 264 m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), RenderingMode::Unaccelerated, 1, m_resultColorSpace, PixelFormat::BGRA8); 265 if (!m_imageBufferResult) 193 return m_filterImage->imageBuffer(); 194 } 195 196 PixelBuffer* FilterEffect::pixelBufferResult(AlphaPremultiplication alphaFormat) 197 { 198 if (!hasResult()) 266 199 return nullptr; 267 268 IntRect destinationRect(IntPoint(), m_absolutePaintRect.size()); 269 if (m_premultipliedImageResult) 270 m_imageBufferResult->putPixelBuffer(*m_premultipliedImageResult, destinationRect); 271 else 272 m_imageBufferResult->putPixelBuffer(*m_unmultipliedImageResult, destinationRect); 273 return m_imageBufferResult.get(); 274 } 275 276 RefPtr<Uint8ClampedArray> FilterEffect::unmultipliedResult(const IntRect& rect, std::optional<DestinationColorSpace> colorSpace) 277 { 278 IntSize scaledSize(rect.size()); 279 ASSERT(!ImageBuffer::sizeNeedsClamping(scaledSize)); 280 auto checkedArea = scaledSize.area<RecordOverflow>() * 4; 281 if (checkedArea.hasOverflowed()) 282 return nullptr; 283 auto pixelArray = Uint8ClampedArray::tryCreateUninitialized(checkedArea); 284 if (!pixelArray) 285 return nullptr; 286 copyUnmultipliedResult(*pixelArray, rect, colorSpace); 287 return pixelArray; 288 } 289 290 RefPtr<Uint8ClampedArray> FilterEffect::premultipliedResult(const IntRect& rect, std::optional<DestinationColorSpace> colorSpace) 291 { 292 IntSize scaledSize(rect.size()); 293 ASSERT(!ImageBuffer::sizeNeedsClamping(scaledSize)); 294 auto checkedArea = scaledSize.area<RecordOverflow>() * 4; 295 if (checkedArea.hasOverflowed()) 296 return nullptr; 297 auto pixelArray = Uint8ClampedArray::tryCreateUninitialized(checkedArea); 298 if (!pixelArray) 299 return nullptr; 300 copyPremultipliedResult(*pixelArray, rect, colorSpace); 301 return pixelArray; 302 } 303 304 void FilterEffect::copyImageBytes(const Uint8ClampedArray& source, Uint8ClampedArray& destination, const IntRect& rect) const 305 { 306 IntRect scaledRect(rect); 307 IntSize scaledPaintSize(m_absolutePaintRect.size()); 308 309 // Initialize the destination to transparent black, if not entirely covered by the source. 310 if (scaledRect.x() < 0 || scaledRect.y() < 0 || scaledRect.maxX() > scaledPaintSize.width() || scaledRect.maxY() > scaledPaintSize.height()) 311 memset(destination.data(), 0, destination.length()); 312 313 // Early return if the rect does not intersect with the source. 314 if (scaledRect.maxX() <= 0 || scaledRect.maxY() <= 0 || scaledRect.x() >= scaledPaintSize.width() || scaledRect.y() >= scaledPaintSize.height()) 200 return m_filterImage->pixelBuffer(alphaFormat); 201 } 202 203 std::optional<PixelBuffer> FilterEffect::getPixelBufferResult(AlphaPremultiplication alphaFormat, const IntRect& sourceRect, std::optional<DestinationColorSpace> colorSpace) 204 { 205 ASSERT(hasResult()); 206 return m_filterImage->getPixelBuffer(alphaFormat, sourceRect, colorSpace); 207 } 208 209 void FilterEffect::copyPixelBufferResult(PixelBuffer& destinationPixelBuffer, const IntRect& sourceRect) const 210 { 211 ASSERT(hasResult()); 212 m_filterImage->copyPixelBuffer(destinationPixelBuffer, sourceRect); 213 } 214 215 void FilterEffect::correctPremultipliedResultIfNeeded() 216 { 217 if (!hasResult() || !mayProduceInvalidPremultipliedPixels()) 315 218 return; 316 317 int xOrigin = scaledRect.x(); 318 int xDest = 0; 319 if (xOrigin < 0) { 320 xDest = -xOrigin; 321 xOrigin = 0; 322 } 323 int xEnd = scaledRect.maxX(); 324 if (xEnd > scaledPaintSize.width()) 325 xEnd = scaledPaintSize.width(); 326 327 int yOrigin = scaledRect.y(); 328 int yDest = 0; 329 if (yOrigin < 0) { 330 yDest = -yOrigin; 331 yOrigin = 0; 332 } 333 int yEnd = scaledRect.maxY(); 334 if (yEnd > scaledPaintSize.height()) 335 yEnd = scaledPaintSize.height(); 336 337 int size = (xEnd - xOrigin) * 4; 338 int destinationScanline = scaledRect.width() * 4; 339 int sourceScanline = scaledPaintSize.width() * 4; 340 uint8_t* destinationPixel = destination.data() + ((yDest * scaledRect.width()) + xDest) * 4; 341 const uint8_t* sourcePixel = source.data() + ((yOrigin * scaledPaintSize.width()) + xOrigin) * 4; 342 343 while (yOrigin < yEnd) { 344 memcpy(destinationPixel, sourcePixel, size); 345 destinationPixel += destinationScanline; 346 sourcePixel += sourceScanline; 347 ++yOrigin; 348 } 349 } 350 351 static void copyPremultiplyingAlpha(const Uint8ClampedArray& source, Uint8ClampedArray& destination, const IntSize& inputSize) 352 { 353 #if USE(ACCELERATE) 354 size_t rowBytes = inputSize.width() * 4; 355 356 vImage_Buffer src; 357 src.width = inputSize.width(); 358 src.height = inputSize.height(); 359 src.rowBytes = rowBytes; 360 src.data = reinterpret_cast<void*>(source.data()); 361 362 vImage_Buffer dest; 363 dest.width = inputSize.width(); 364 dest.height = inputSize.height(); 365 dest.rowBytes = rowBytes; 366 dest.data = reinterpret_cast<void*>(destination.data()); 367 368 vImagePremultiplyData_RGBA8888(&src, &dest, kvImageNoFlags); 369 #else 370 const uint8_t* sourceComponent = source.data(); 371 const uint8_t* end = sourceComponent + (inputSize.area() * 4).value(); 372 uint8_t* destinationComponent = destination.data(); 373 374 while (sourceComponent < end) { 375 int alpha = sourceComponent[3]; 376 destinationComponent[0] = static_cast<int>(sourceComponent[0]) * alpha / 255; 377 destinationComponent[1] = static_cast<int>(sourceComponent[1]) * alpha / 255; 378 destinationComponent[2] = static_cast<int>(sourceComponent[2]) * alpha / 255; 379 destinationComponent[3] = alpha; 380 sourceComponent += 4; 381 destinationComponent += 4; 382 } 383 #endif 384 } 385 386 static void copyUnpremultiplyingAlpha(const Uint8ClampedArray& source, Uint8ClampedArray& destination, const IntSize& inputSize) 387 { 388 #if USE(ACCELERATE) 389 size_t rowBytes = inputSize.width() * 4; 390 391 vImage_Buffer src; 392 src.width = inputSize.width(); 393 src.height = inputSize.height(); 394 src.rowBytes = rowBytes; 395 src.data = reinterpret_cast<void*>(source.data()); 396 397 vImage_Buffer dest; 398 dest.width = inputSize.width(); 399 dest.height = inputSize.height(); 400 dest.rowBytes = rowBytes; 401 dest.data = reinterpret_cast<void*>(destination.data()); 402 403 vImageUnpremultiplyData_RGBA8888(&src, &dest, kvImageNoFlags); 404 #else 405 const uint8_t* sourceComponent = source.data(); 406 const uint8_t* end = sourceComponent + (inputSize.area() * 4).value(); 407 uint8_t* destinationComponent = destination.data(); 408 while (sourceComponent < end) { 409 int alpha = sourceComponent[3]; 410 if (alpha) { 411 destinationComponent[0] = static_cast<int>(sourceComponent[0]) * 255 / alpha; 412 destinationComponent[1] = static_cast<int>(sourceComponent[1]) * 255 / alpha; 413 destinationComponent[2] = static_cast<int>(sourceComponent[2]) * 255 / alpha; 414 } else { 415 destinationComponent[0] = 0; 416 destinationComponent[1] = 0; 417 destinationComponent[2] = 0; 418 } 419 destinationComponent[3] = alpha; 420 sourceComponent += 4; 421 destinationComponent += 4; 422 } 423 #endif 424 } 425 426 std::optional<PixelBuffer> FilterEffect::convertPixelBufferToColorSpace(const DestinationColorSpace& targetColorSpace, PixelBuffer& pixelBuffer) 427 { 428 // FIXME: Using an ImageBuffer to perform the color space conversion is unnecessary. We can do it directly. 429 430 IntRect destinationRect(IntPoint(), pixelBuffer.size()); 431 FloatSize clampedSize = ImageBuffer::clampedSize(destinationRect.size()); 432 // Create an ImageBuffer to store incoming PixelBuffer 433 auto buffer = ImageBuffer::create(clampedSize, RenderingMode::Unaccelerated, 1, operatingColorSpace(), PixelFormat::BGRA8); 434 if (!buffer) 435 return std::nullopt; 436 buffer->putPixelBuffer(pixelBuffer, destinationRect); 437 return convertImageBufferToColorSpace(targetColorSpace, *buffer, destinationRect, pixelBuffer.format().alphaFormat); 438 } 439 440 std::optional<PixelBuffer> FilterEffect::convertImageBufferToColorSpace(const DestinationColorSpace& targetColorSpace, ImageBuffer& inputBuffer, const IntRect& rect, AlphaPremultiplication outputAlphaFormat) 441 { 442 // FIXME: This can be done more directly using PixelBufferConversion. 443 444 FloatSize clampedSize = ImageBuffer::clampedSize(rect.size()); 445 446 // Create an ImageBuffer with the correct color space and utilize CG to handle color space conversion 447 auto convertedBuffer = ImageBuffer::create(clampedSize, RenderingMode::Unaccelerated, 1, targetColorSpace, PixelFormat::BGRA8); 448 if (!convertedBuffer) 449 return std::nullopt; 450 451 // Color space conversion happens internally when drawing from one image buffer to another 452 convertedBuffer->context().drawImageBuffer(inputBuffer, rect); 453 454 PixelBufferFormat format { outputAlphaFormat, PixelFormat::RGBA8, targetColorSpace }; 455 return convertedBuffer->getPixelBuffer(format, rect); 456 } 457 458 void FilterEffect::copyConvertedImageBufferToDestination(Uint8ClampedArray& destination, const DestinationColorSpace& colorSpace, AlphaPremultiplication outputFormat, const IntRect& destRect) 459 { 460 // Converts the data stored in m_imageBufferResult, and save to destination 461 auto convertedPixelBuffer = convertImageBufferToColorSpace(colorSpace, *m_imageBufferResult, { IntPoint(), m_absolutePaintRect.size() }, outputFormat); 462 if (!convertedPixelBuffer) 219 m_filterImage->correctPremultipliedPixelBuffer(); 220 } 221 222 void FilterEffect::transformResultColorSpace(const DestinationColorSpace& destinationColorSpace) 223 { 224 if (!hasResult()) 463 225 return; 464 copyImageBytes(convertedPixelBuffer->data(), destination, destRect); 465 } 466 467 void FilterEffect::copyConvertedPixelBufferToDestination(Uint8ClampedArray& destination, PixelBuffer& pixelBuffer, const DestinationColorSpace& colorSpace, const IntRect& destRect) 468 { 469 // Converts the data stored in m_unmultipliedImageResult/m_premultipliedImageResult, 470 // whichever isn't null, and save to destination 471 auto convertedPixelBuffer = convertPixelBufferToColorSpace(colorSpace, pixelBuffer); 472 if (!convertedPixelBuffer) 473 return; 474 copyImageBytes(convertedPixelBuffer->data(), destination, destRect); 475 } 476 477 void FilterEffect::copyUnmultipliedResult(Uint8ClampedArray& destination, const IntRect& rect, std::optional<DestinationColorSpace> colorSpace) 478 { 479 ASSERT(hasResult()); 480 481 LOG_WITH_STREAM(Filters, stream << "FilterEffect " << filterName() << " " << this << " copyUnmultipliedResult(). Existing image buffer " << m_imageBufferResult.get() << " m_premultipliedImageResult " << m_premultipliedImageResult << " m_unmultipliedImageResult " << m_unmultipliedImageResult); 482 483 if (!m_unmultipliedImageResult) { 484 // We prefer a conversion from the image buffer. 485 if (m_imageBufferResult) { 486 if (requiresPixelBufferColorSpaceConversion(colorSpace)) { 487 copyConvertedImageBufferToDestination(destination, *colorSpace, AlphaPremultiplication::Unpremultiplied, rect); 488 return; 489 } 490 491 ASSERT(m_imageBufferResult->colorSpace() == m_resultColorSpace); 492 PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, m_resultColorSpace }; 493 m_unmultipliedImageResult = m_imageBufferResult->getPixelBuffer(format, { IntPoint(), m_absolutePaintRect.size() }); 494 if (!m_unmultipliedImageResult) 495 return; 496 } else { 497 IntSize inputSize(m_absolutePaintRect.size()); 498 ASSERT(!ImageBuffer::sizeNeedsClamping(inputSize)); 499 500 ASSERT(m_premultipliedImageResult->format().colorSpace == m_resultColorSpace); 501 PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, m_resultColorSpace }; 502 m_unmultipliedImageResult = PixelBuffer::tryCreate(format, inputSize); 503 if (!m_unmultipliedImageResult) 504 return; 505 copyUnpremultiplyingAlpha(m_premultipliedImageResult->data(), m_unmultipliedImageResult->data(), inputSize); 506 } 507 } 508 if (requiresPixelBufferColorSpaceConversion(colorSpace)) { 509 copyConvertedPixelBufferToDestination(destination, *m_unmultipliedImageResult, *colorSpace, rect); 510 return; 511 } 512 copyImageBytes(m_unmultipliedImageResult->data(), destination, rect); 513 } 514 515 void FilterEffect::copyPremultipliedResult(Uint8ClampedArray& destination, const IntRect& rect, std::optional<DestinationColorSpace> colorSpace) 516 { 517 ASSERT(hasResult()); 518 519 LOG_WITH_STREAM(Filters, stream << "FilterEffect " << filterName() << " " << this << " copyPremultipliedResult(). Existing image buffer " << m_imageBufferResult.get() << " m_premultipliedImageResult " << m_premultipliedImageResult << " m_unmultipliedImageResult " << m_unmultipliedImageResult); 520 521 if (!m_premultipliedImageResult) { 522 // We prefer a conversion from the image buffer. 523 if (m_imageBufferResult) { 524 if (requiresPixelBufferColorSpaceConversion(colorSpace)) { 525 copyConvertedImageBufferToDestination(destination, *colorSpace, AlphaPremultiplication::Premultiplied, rect); 526 return; 527 } 528 529 ASSERT(m_imageBufferResult->colorSpace() == m_resultColorSpace); 530 PixelBufferFormat format { AlphaPremultiplication::Premultiplied, PixelFormat::RGBA8, m_resultColorSpace }; 531 m_premultipliedImageResult = m_imageBufferResult->getPixelBuffer(format, { IntPoint(), m_absolutePaintRect.size() }); 532 if (!m_premultipliedImageResult) 533 return; 534 } else { 535 IntSize inputSize(m_absolutePaintRect.size()); 536 ASSERT(!ImageBuffer::sizeNeedsClamping(inputSize)); 537 538 ASSERT(m_unmultipliedImageResult->format().colorSpace == m_resultColorSpace); 539 PixelBufferFormat format { AlphaPremultiplication::Premultiplied, PixelFormat::RGBA8, m_resultColorSpace }; 540 m_premultipliedImageResult = PixelBuffer::tryCreate(format, inputSize); 541 if (!m_premultipliedImageResult) 542 return; 543 copyPremultiplyingAlpha(m_unmultipliedImageResult->data(), m_premultipliedImageResult->data(), inputSize); 544 } 545 } 546 547 if (requiresPixelBufferColorSpaceConversion(colorSpace)) { 548 copyConvertedPixelBufferToDestination(destination, *m_premultipliedImageResult, *colorSpace, rect); 549 return; 550 } 551 copyImageBytes(m_premultipliedImageResult->data(), destination, rect); 552 } 553 554 ImageBuffer* FilterEffect::createImageBufferResult() 555 { 556 LOG(Filters, "FilterEffect %s %p createImageBufferResult %dx%d", filterName().characters8(), this, m_absolutePaintRect.size().width(), m_absolutePaintRect.size().height()); 557 558 // Only one result type is allowed. 559 ASSERT(!hasResult()); 560 if (m_absolutePaintRect.isEmpty()) 561 return nullptr; 562 563 FloatSize clampedSize = ImageBuffer::clampedSize(m_absolutePaintRect.size()); 564 m_imageBufferResult = ImageBuffer::create(clampedSize, RenderingMode::Unaccelerated, 1, m_resultColorSpace, PixelFormat::BGRA8); 565 return m_imageBufferResult.get(); 566 } 567 568 std::optional<PixelBuffer>& FilterEffect::createUnmultipliedImageResult() 569 { 570 LOG(Filters, "FilterEffect %s %p createUnmultipliedImageResult", filterName().characters8(), this); 571 572 // Only one result type is allowed. 573 ASSERT(!hasResult()); 574 ASSERT(!m_unmultipliedImageResult); 575 576 if (m_absolutePaintRect.isEmpty()) 577 return m_unmultipliedImageResult; 578 579 IntSize resultSize(m_absolutePaintRect.size()); 580 ASSERT(!ImageBuffer::sizeNeedsClamping(resultSize)); 581 PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, m_resultColorSpace }; 582 m_unmultipliedImageResult = PixelBuffer::tryCreate(format, resultSize); 583 return m_unmultipliedImageResult; 584 } 585 586 std::optional<PixelBuffer>& FilterEffect::createPremultipliedImageResult() 587 { 588 LOG(Filters, "FilterEffect %s %p createPremultipliedImageResult", filterName().characters8(), this); 589 590 // Only one result type is allowed. 591 ASSERT(!hasResult()); 592 ASSERT(!m_premultipliedImageResult); 593 594 if (m_absolutePaintRect.isEmpty()) 595 return m_premultipliedImageResult; 596 597 IntSize resultSize(m_absolutePaintRect.size()); 598 ASSERT(!ImageBuffer::sizeNeedsClamping(resultSize)); 599 PixelBufferFormat format { AlphaPremultiplication::Premultiplied, PixelFormat::RGBA8, m_resultColorSpace }; 600 m_premultipliedImageResult = PixelBuffer::tryCreate(format, resultSize); 601 return m_premultipliedImageResult; 602 } 603 604 bool FilterEffect::requiresPixelBufferColorSpaceConversion(std::optional<DestinationColorSpace> destinationColorSpace) 605 { 606 #if USE(CG) 607 // This function determines whether we need the step of an extra color space conversion 608 // We only need extra color conversion when 1) color space is different in the input 609 // AND 2) the filter is manipulating raw pixels 610 return destinationColorSpace && resultColorSpace() != *destinationColorSpace; 611 #else 612 // Additional color space conversion is not needed on non-CG 613 UNUSED_PARAM(destinationColorSpace); 614 return false; 615 #endif 616 } 617 618 void FilterEffect::transformResultColorSpace(const DestinationColorSpace& destinationColorSpace) 619 { 620 #if USE(CG) 621 // CG handles color space adjustments internally. 622 UNUSED_PARAM(destinationColorSpace); 623 #else 624 if (!hasResult() || destinationColorSpace == m_resultColorSpace) 625 return; 626 627 // FIXME: We can avoid this potentially unnecessary ImageBuffer conversion by adding 628 // color space transform support for the {pre,un}multiplied arrays. 629 imageBufferResult()->transformToColorSpace(destinationColorSpace); 630 631 m_resultColorSpace = destinationColorSpace; 632 633 m_unmultipliedImageResult = std::nullopt; 634 m_premultipliedImageResult = std::nullopt; 635 #endif 226 m_filterImage->transformToColorSpace(destinationColorSpace); 636 227 } 637 228 … … 644 235 TextStream::IndentScope indentScope(ts); 645 236 ts.dumpProperty("alpha image", m_alphaImage); 646 ts.dumpProperty("operating colorspace", m_operatingColorSpace);647 ts.dumpProperty("result colorspace", m_resultColorSpace);237 ts.dumpProperty("operating colorspace", operatingColorSpace()); 238 ts.dumpProperty("result colorspace", resultColorSpace()); 648 239 ts << "\n" << indent; 649 240 } -
trunk/Source/WebCore/platform/graphics/filters/FilterEffect.h
r285916 r286129 23 23 #pragma once 24 24 25 #include "AlphaPremultiplication.h"26 25 #include "DestinationColorSpace.h" 27 26 #include "FilterEffectVector.h" 28 27 #include "FilterFunction.h" 29 #include "F loatRect.h"28 #include "FilterImage.h" 30 29 #include "IntRect.h" 31 #include "IntRectExtent.h"32 #include "PixelBuffer.h"33 #include <JavaScriptCore/Forward.h>34 #include <wtf/MathExtras.h>35 #include <wtf/RefPtr.h>36 30 #include <wtf/Vector.h> 37 31 … … 47 41 class FilterEffect : public FilterFunction { 48 42 public: 43 bool createResult(); 49 44 void clearResult() override; 50 45 void clearResultsRecursive(); 51 46 47 bool hasResult() const { return m_filterImage; } 48 52 49 ImageBuffer* imageBufferResult(); 53 RefPtr<Uint8ClampedArray> unmultipliedResult(const IntRect&, std::optional<DestinationColorSpace> = std::nullopt); 54 RefPtr<Uint8ClampedArray> premultipliedResult(const IntRect&, std::optional<DestinationColorSpace> = std::nullopt); 55 void copyUnmultipliedResult(Uint8ClampedArray& destination, const IntRect&, std::optional<DestinationColorSpace> = std::nullopt); 56 void copyPremultipliedResult(Uint8ClampedArray& destination, const IntRect&, std::optional<DestinationColorSpace> = std::nullopt); 50 PixelBuffer* pixelBufferResult(AlphaPremultiplication); 51 std::optional<PixelBuffer> getPixelBufferResult(AlphaPremultiplication, const IntRect& sourceRect, std::optional<DestinationColorSpace> = std::nullopt); 52 void copyPixelBufferResult(PixelBuffer& destinationPixelBuffer, const IntRect& sourceRect) const; 53 void correctPremultipliedResultIfNeeded(); 54 57 55 FilterEffectVector& inputEffects() { return m_inputEffects; } 58 56 FilterEffect* inputEffect(unsigned) const; 59 57 unsigned numberOfEffectInputs() const { return m_inputEffects.size(); } 60 58 61 inline bool hasResult() const62 {63 // This function needs platform specific checks, if the memory managment is not done by FilterEffect.64 return m_imageBufferResult65 || m_unmultipliedImageResult66 || m_premultipliedImageResult;67 }68 69 59 FloatRect drawingRegionOfInputImage(const IntRect&) const; 70 60 IntRect requestedRegionOfInputPixelBuffer(const IntRect&) const; … … 124 114 const DestinationColorSpace& operatingColorSpace() const { return m_operatingColorSpace; } 125 115 virtual void setOperatingColorSpace(const DestinationColorSpace& colorSpace) { m_operatingColorSpace = colorSpace; } 126 const DestinationColorSpace& resultColorSpace() const { return m_resultColorSpace; } 127 virtual void setResultColorSpace(const DestinationColorSpace& colorSpace) { m_resultColorSpace = colorSpace; }116 117 virtual const DestinationColorSpace& resultColorSpace() const { return m_operatingColorSpace; } 128 118 129 119 virtual void transformResultColorSpace(FilterEffect* in, const int) { in->transformResultColorSpace(m_operatingColorSpace); } … … 139 129 140 130 protected: 141 FilterEffect(Type); 142 143 ImageBuffer* createImageBufferResult(); 144 std::optional<PixelBuffer>& createUnmultipliedImageResult(); 145 std::optional<PixelBuffer>& createPremultipliedImageResult(); 131 using FilterFunction::FilterFunction; 146 132 147 // Return true if the filter will only operate correctly on valid RGBA values, with 148 // alpha in [0,255] and each color component in [0, alpha]. 149 virtual bool requiresValidPreMultipliedPixels() { return true; } 150 151 // If a pre-multiplied image, check every pixel for validity and correct if necessary. 152 void forceValidPreMultipliedPixels(); 133 virtual bool mayProduceInvalidPremultipliedPixels() const { return false; } 153 134 154 135 void clipAbsolutePaintRect(); … … 157 138 virtual bool platformApplySoftware(const Filter&) = 0; 158 139 159 void copyImageBytes(const Uint8ClampedArray& source, Uint8ClampedArray& destination, const IntRect&) const;160 void copyConvertedImageBufferToDestination(Uint8ClampedArray&, const DestinationColorSpace&, AlphaPremultiplication, const IntRect&);161 void copyConvertedPixelBufferToDestination(Uint8ClampedArray&, PixelBuffer&, const DestinationColorSpace&, const IntRect&);162 bool requiresPixelBufferColorSpaceConversion(std::optional<DestinationColorSpace>);163 std::optional<PixelBuffer> convertImageBufferToColorSpace(const DestinationColorSpace&, ImageBuffer&, const IntRect&, AlphaPremultiplication);164 std::optional<PixelBuffer> convertPixelBufferToColorSpace(const DestinationColorSpace&, PixelBuffer&);165 166 140 FilterEffectVector m_inputEffects; 167 141 168 RefPtr<ImageBuffer> m_imageBufferResult; 169 std::optional<PixelBuffer> m_unmultipliedImageResult; 170 std::optional<PixelBuffer> m_premultipliedImageResult; 142 RefPtr<FilterImage> m_filterImage; 171 143 172 144 IntRect m_absolutePaintRect; … … 196 168 bool m_clipsToBounds { true }; 197 169 198 #if ENABLE(DESTINATION_COLOR_SPACE_LINEAR_SRGB)199 DestinationColorSpace m_operatingColorSpace { DestinationColorSpace::LinearSRGB() };200 #else201 170 DestinationColorSpace m_operatingColorSpace { DestinationColorSpace::SRGB() }; 202 #endif203 DestinationColorSpace m_resultColorSpace { DestinationColorSpace::SRGB() };204 171 }; 205 172 -
trunk/Source/WebCore/platform/graphics/filters/SourceAlpha.cpp
r285916 r286129 48 48 bool SourceAlpha::platformApplySoftware(const Filter&) 49 49 { 50 ImageBuffer* resultImage = createImageBufferResult();50 ImageBuffer* resultImage = imageBufferResult(); 51 51 if (!resultImage) 52 52 return false; -
trunk/Source/WebCore/platform/graphics/filters/SourceGraphic.cpp
r285916 r286129 35 35 : FilterEffect(FilterEffect::Type::SourceGraphic) 36 36 { 37 setOperatingColorSpace(DestinationColorSpace::SRGB());38 37 } 39 38 … … 46 45 bool SourceGraphic::platformApplySoftware(const Filter& filter) 47 46 { 48 ImageBuffer* resultImage = createImageBufferResult();47 ImageBuffer* resultImage = imageBufferResult(); 49 48 ImageBuffer* sourceImage = filter.sourceImage(); 50 49 if (!resultImage || !sourceImage) -
trunk/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp
r285796 r286129 242 242 filterData.state = FilterData::Applying; 243 243 filterData.filter->apply(); 244 lastEffect->correct FilterResultIfNeeded();244 lastEffect->correctPremultipliedResultIfNeeded(); 245 245 lastEffect->transformResultColorSpace(DestinationColorSpace::SRGB()); 246 246 } -
trunk/Source/WebCore/svg/graphics/filters/SVGFEImage.cpp
r285916 r286129 77 77 bool FEImage::platformApplySoftware(const Filter& filter) 78 78 { 79 // FEImage results are always in DestinationColorSpace::SRGB() 80 setResultColorSpace(DestinationColorSpace::SRGB()); 81 82 ImageBuffer* resultImage = createImageBufferResult(); 79 auto resultImage = imageBufferResult(); 83 80 if (!resultImage) 84 81 return false; -
trunk/Source/WebCore/svg/graphics/filters/SVGFEImage.h
r285916 r286129 45 45 FEImage(SourceImage&&, const FloatRect& sourceImageRect, const SVGPreserveAspectRatioValue&); 46 46 47 // FEImage results are always in DestinationColorSpace::SRGB() 48 void setOperatingColorSpace(const DestinationColorSpace&) override { } 49 47 50 void determineAbsolutePaintRect(const Filter&) final; 48 51
Note:
See TracChangeset
for help on using the changeset viewer.