void FEGaussianBlur::apply(Filter* filter) { m_in->apply(filter); if (!m_in->resultImage()) return; if (!getEffectContext()) return; setIsAlphaImage(m_in->isAlphaImage()); if (m_x == 0 || m_y == 0) return; unsigned sdx = static_cast<unsigned>(floor(m_x * 3 * sqrt(2 * M_PI) / 4.f + 0.5f)); unsigned sdy = static_cast<unsigned>(floor(m_y * 3 * sqrt(2 * M_PI) / 4.f + 0.5f)); IntRect effectDrawingRect = calculateDrawingIntRect(m_in->subRegion()); RefPtr<ImageData> srcImageData(m_in->resultImage()->getPremultipliedImageData(effectDrawingRect)); CanvasPixelArray* srcPixelArray(srcImageData->data()); IntRect imageRect(IntPoint(), resultImage()->size()); RefPtr<ImageData> tmpImageData = ImageData::create(imageRect.width(), imageRect.height()); CanvasPixelArray* tmpPixelArray(tmpImageData->data()); int stride = 4 * imageRect.width(); for (int i = 0; i < 3; ++i) { boxBlur(srcPixelArray, tmpPixelArray, sdx, 4, stride, imageRect.width(), imageRect.height(), isAlphaImage()); boxBlur(tmpPixelArray, srcPixelArray, sdy, stride, 4, imageRect.height(), imageRect.width(), isAlphaImage()); } resultImage()->putPremultipliedImageData(srcImageData.get(), imageRect, IntPoint()); }
void FEGaussianBlur::platformApplySoftware() { FilterEffect* in = inputEffect(0); Uint8ClampedArray* srcPixelArray = createPremultipliedImageResult(); if (!srcPixelArray) return; setIsAlphaImage(in->isAlphaImage()); IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); in->copyPremultipliedImage(srcPixelArray, effectDrawingRect); if (!m_stdX && !m_stdY) return; unsigned kernelSizeX = 0; unsigned kernelSizeY = 0; calculateKernelSize(filter(), kernelSizeX, kernelSizeY, m_stdX, m_stdY); IntSize paintSize = absolutePaintRect().size(); RefPtr<Uint8ClampedArray> tmpImageData = Uint8ClampedArray::createUninitialized(paintSize.width() * paintSize.height() * 4); Uint8ClampedArray* tmpPixelArray = tmpImageData.get(); platformApply(srcPixelArray, tmpPixelArray, kernelSizeX, kernelSizeY, paintSize); }
void FEGaussianBlur::applySoftware() { ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; FilterEffect* in = inputEffect(0); IntRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect()); setIsAlphaImage(in->isAlphaImage()); float stdX = filter()->applyHorizontalScale(m_stdX); float stdY = filter()->applyVerticalScale(m_stdY); RefPtr<Image> image = in->asImageBuffer()->copyImage(DontCopyBackingStore); SkPaint paint; GraphicsContext* dstContext = resultImage->context(); paint.setImageFilter(SkBlurImageFilter::Create(stdX, stdY))->unref(); SkRect bounds = SkRect::MakeWH(absolutePaintRect().width(), absolutePaintRect().height()); dstContext->saveLayer(&bounds, &paint); paint.setColor(0xFFFFFFFF); dstContext->drawImage(image.get(), drawingRegion.location(), CompositeCopy); dstContext->restoreLayer(); }
void FEGaussianBlur::platformApplySkia() { ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; FilterEffect* in = inputEffect(0); IntRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect()); setIsAlphaImage(in->isAlphaImage()); float stdX = filter()->applyHorizontalScale(m_stdX); float stdY = filter()->applyVerticalScale(m_stdY); RefPtr<Image> image = in->asImageBuffer()->copyImage(DontCopyBackingStore); SkPaint paint; GraphicsContext* dstContext = resultImage->context(); SkCanvas* canvas = dstContext->platformContext()->canvas(); paint.setImageFilter(new SkBlurImageFilter(stdX, stdY))->unref(); canvas->saveLayer(0, &paint); paint.setColor(0xFFFFFFFF); dstContext->drawImage(image.get(), ColorSpaceDeviceRGB, drawingRegion.location(), CompositeCopy); canvas->restore(); return; }
void FEMorphology::applySoftware() { ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; FilterEffect* in = inputEffect(0); IntRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect()); setIsAlphaImage(in->isAlphaImage()); float radiusX = filter()->applyHorizontalScale(m_radiusX); float radiusY = filter()->applyVerticalScale(m_radiusY); RefPtr<Image> image = in->asImageBuffer()->copyImage(DontCopyBackingStore); SkPaint paint; GraphicsContext* dstContext = resultImage->context(); if (m_type == FEMORPHOLOGY_OPERATOR_DILATE) paint.setImageFilter(SkDilateImageFilter::Create(radiusX, radiusY))->unref(); else if (m_type == FEMORPHOLOGY_OPERATOR_ERODE) paint.setImageFilter(SkErodeImageFilter::Create(radiusX, radiusY))->unref(); SkRect bounds = SkRect::MakeWH(absolutePaintRect().width(), absolutePaintRect().height()); dstContext->saveLayer(&bounds, &paint); dstContext->drawImage(image.get(), drawingRegion.location(), CompositeCopy); dstContext->restoreLayer(); }
void FEGaussianBlur::platformApplySoftware() { FilterEffect* in = inputEffect(0); Uint8ClampedArray* srcPixelArray = createPremultipliedImageResult(); if (!srcPixelArray) return; setIsAlphaImage(in->isAlphaImage()); IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); in->copyPremultipliedImage(srcPixelArray, effectDrawingRect); if (!m_stdX && !m_stdY) return; IntSize kernelSize = calculateKernelSize(filter(), FloatPoint(m_stdX, m_stdY)); kernelSize.scale(filter().filterScale()); IntSize paintSize = absolutePaintRect().size(); paintSize.scale(filter().filterScale()); RefPtr<Uint8ClampedArray> tmpImageData = Uint8ClampedArray::createUninitialized((paintSize.area() * 4).unsafeGet()); if (!tmpImageData) { WTFLogAlways("FEGaussianBlur::platformApplySoftware Unable to create buffer. Requested size was %d x %d\n", paintSize.width(), paintSize.height()); return; } platformApply(srcPixelArray, tmpImageData.get(), kernelSize.width(), kernelSize.height(), paintSize); }
bool FELighting::applySkia() { // For now, only use the skia implementation for accelerated rendering. if (!filter()->isAccelerated()) return false; ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return false; FilterEffect* in = inputEffect(0); IntRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect()); setIsAlphaImage(in->isAlphaImage()); RefPtr<Image> image = in->asImageBuffer()->copyImage(DontCopyBackingStore); RefPtr<NativeImageSkia> nativeImage = image->nativeImageForCurrentFrame(); if (!nativeImage) return false; GraphicsContext* dstContext = resultImage->context(); SkPaint paint; RefPtr<SkImageFilter> filter = createImageFilter(0); paint.setImageFilter(filter.get()); dstContext->drawBitmap(nativeImage->bitmap(), drawingRegion.location().x(), drawingRegion.location().y(), &paint); return true; }
void FEOffset::apply(Filter* filter) { m_in->apply(filter); if (!m_in->resultImage()) return; GraphicsContext* filterContext = getEffectContext(); if (!filterContext) return; setIsAlphaImage(m_in->isAlphaImage()); FloatRect sourceImageRect = filter->sourceImageRect(); sourceImageRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); if (filter->effectBoundingBoxMode()) { m_dx *= sourceImageRect.width(); m_dy *= sourceImageRect.height(); } m_dx *= filter->filterResolution().width(); m_dy *= filter->filterResolution().height(); FloatRect dstRect = FloatRect(m_dx + m_in->scaledSubRegion().x() - scaledSubRegion().x(), m_dy + m_in->scaledSubRegion().y() - scaledSubRegion().y(), m_in->scaledSubRegion().width(), m_in->scaledSubRegion().height()); filterContext->drawImageBuffer(m_in->resultImage(), DeviceColorSpace, dstRect); }
void FEColorMatrix::platformApplySoftware() { FilterEffect* in = inputEffect(0); ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; resultImage->context()->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); IntRect imageRect(IntPoint(), absolutePaintRect().size()); RefPtr<Uint8ClampedArray> pixelArray = resultImage->getUnmultipliedImageData(imageRect); switch (m_type) { case FECOLORMATRIX_TYPE_UNKNOWN: break; case FECOLORMATRIX_TYPE_MATRIX: effectType<FECOLORMATRIX_TYPE_MATRIX>(pixelArray.get(), m_values); break; case FECOLORMATRIX_TYPE_SATURATE: effectType<FECOLORMATRIX_TYPE_SATURATE>(pixelArray.get(), m_values); break; case FECOLORMATRIX_TYPE_HUEROTATE: effectType<FECOLORMATRIX_TYPE_HUEROTATE>(pixelArray.get(), m_values); break; case FECOLORMATRIX_TYPE_LUMINANCETOALPHA: effectType<FECOLORMATRIX_TYPE_LUMINANCETOALPHA>(pixelArray.get(), m_values); setIsAlphaImage(true); break; } resultImage->putByteArray(Unmultiplied, pixelArray.get(), imageRect.size(), imageRect, IntPoint()); }
void FEMorphology::platformApplySoftware() { FilterEffect* in = inputEffect(0); Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult(); if (!dstPixelArray) return; setIsAlphaImage(in->isAlphaImage()); if (m_radiusX <= 0 || m_radiusY <= 0) { dstPixelArray->zeroFill(); return; } Filter& filter = this->filter(); int radiusX = static_cast<int>(floorf(filter.applyHorizontalScale(m_radiusX))); int radiusY = static_cast<int>(floorf(filter.applyVerticalScale(m_radiusY))); IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<Uint8ClampedArray> srcPixelArray = in->asPremultipliedImage(effectDrawingRect); PaintingData paintingData; paintingData.srcPixelArray = srcPixelArray.get(); paintingData.dstPixelArray = dstPixelArray; paintingData.width = effectDrawingRect.width(); paintingData.height = effectDrawingRect.height(); paintingData.radiusX = std::min(effectDrawingRect.width() - 1, radiusX); paintingData.radiusY = std::min(effectDrawingRect.height() - 1, radiusY); platformApply(&paintingData); }
void FECustomFilter::clearShaderResult() { clearResult(); Uint8ClampedArray* dstPixelArray = createUnmultipliedImageResult(); if (!dstPixelArray) return; FilterEffect* in = inputEffect(0); setIsAlphaImage(in->isAlphaImage()); IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); in->copyUnmultipliedImage(dstPixelArray, effectDrawingRect); }
void SourceAlpha::platformApplySoftware() { ImageBuffer* resultImage = createImageBufferResult(); Filter* filter = this->filter(); if (!resultImage || !filter->sourceImage()) return; setIsAlphaImage(true); FloatRect imageRect(FloatPoint(), absolutePaintRect().size()); GraphicsContext* filterContext = resultImage->context(); filterContext->fillRect(imageRect, Color::black, ColorSpaceDeviceRGB); filterContext->drawImageBuffer(filter->sourceImage(), ColorSpaceDeviceRGB, IntPoint(), CompositeDestinationIn); }
void SourceAlpha::apply(Filter* filter) { GraphicsContext* filterContext = getEffectContext(); if (!filterContext) return; setIsAlphaImage(true); FloatRect imageRect(FloatPoint(), filter->sourceImage()->size()); filterContext->save(); filterContext->clipToImageBuffer(filter->sourceImage(), imageRect); filterContext->fillRect(imageRect, Color::black, DeviceColorSpace); filterContext->restore(); }
void SourceAlpha::apply() { GraphicsContext* filterContext = effectContext(); Filter* filter = this->filter(); if (!filterContext || !filter->sourceImage()) return; setIsAlphaImage(true); FloatRect imageRect(FloatPoint(), absolutePaintRect().size()); filterContext->save(); filterContext->clipToImageBuffer(filter->sourceImage(), imageRect); filterContext->fillRect(imageRect, Color::black, ColorSpaceDeviceRGB); filterContext->restore(); }
void FEOffset::applySoftware() { FilterEffect* in = inputEffect(0); ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; setIsAlphaImage(in->isAlphaImage()); FloatRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect()); Filter* filter = this->filter(); drawingRegion.move(filter->applyHorizontalScale(m_dx), filter->applyVerticalScale(m_dy)); resultImage->context()->drawImageBuffer(in->asImageBuffer(), drawingRegion); }
void FEOffset::apply() { FilterEffect* in = inputEffect(0); in->apply(); if (!in->resultImage()) return; GraphicsContext* filterContext = effectContext(); if (!filterContext) return; setIsAlphaImage(in->isAlphaImage()); FloatRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect()); Filter* filter = this->filter(); drawingRegion.move(filter->applyHorizontalScale(m_dx), filter->applyVerticalScale(m_dy)); filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegion); }
void FETile::platformApplySoftware() { // 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->asImageBuffer(); if (!resultImage || !inBuffer) return; setIsAlphaImage(in->isAlphaImage()); // Source input needs more attention. It has the size of the filterRegion but gives the // size of the cutted sourceImage back. This is part of the specification and optimization. FloatRect tileRect = in->maxEffectRect(); FloatPoint inMaxEffectLocation = tileRect.location(); FloatPoint maxEffectLocation = maxEffectRect().location(); if (in->filterEffectType() == FilterEffectTypeSourceInput) { Filter& filter = this->filter(); tileRect = filter.filterRegion(); tileRect.scale(filter.filterResolution().width(), filter.filterResolution().height()); } auto tileImage = SVGRenderingContext::createImageBuffer(tileRect, tileRect, ColorSpaceSRGB, filter().renderingMode()); if (!tileImage) return; GraphicsContext& tileImageContext = tileImage->context(); tileImageContext.translate(-inMaxEffectLocation.x(), -inMaxEffectLocation.y()); tileImageContext.drawImageBuffer(*inBuffer, in->absolutePaintRect().location()); auto tileImageCopy = ImageBuffer::sinkIntoImage(WTFMove(tileImage)); if (!tileImageCopy) return; auto pattern = Pattern::create(WTFMove(tileImageCopy), true, true); AffineTransform patternTransform; patternTransform.translate(inMaxEffectLocation.x() - maxEffectLocation.x(), inMaxEffectLocation.y() - maxEffectLocation.y()); pattern.get().setPatternSpaceTransform(patternTransform); GraphicsContext& filterContext = resultImage->context(); filterContext.setFillPattern(WTFMove(pattern)); filterContext.fillRect(FloatRect(FloatPoint(), absolutePaintRect().size())); }
void FETile::apply() { // FIXME: See bug 47315. This is a hack to work around a compile failure, but is incorrect behavior otherwise. #if ENABLE(SVG) FilterEffect* in = inputEffect(0); in->apply(); if (!in->resultImage()) return; GraphicsContext* filterContext = effectContext(); if (!filterContext) return; setIsAlphaImage(in->isAlphaImage()); // Source input needs more attention. It has the size of the filterRegion but gives the // size of the cutted sourceImage back. This is part of the specification and optimization. FloatRect tileRect = in->maxEffectRect(); FloatPoint inMaxEffectLocation = tileRect.location(); FloatPoint maxEffectLocation = maxEffectRect().location(); if (in->filterEffectType() == FilterEffectTypeSourceInput) { Filter* filter = this->filter(); tileRect = filter->filterRegion(); tileRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); } OwnPtr<ImageBuffer> tileImage; if (!SVGImageBufferTools::createImageBuffer(tileRect, tileRect, tileImage, ColorSpaceDeviceRGB)) return; GraphicsContext* tileImageContext = tileImage->context(); tileImageContext->translate(-inMaxEffectLocation.x(), -inMaxEffectLocation.y()); tileImageContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, in->absolutePaintRect().location()); RefPtr<Pattern> pattern = Pattern::create(tileImage->copyImage(), true, true); AffineTransform patternTransform; patternTransform.translate(inMaxEffectLocation.x() - maxEffectLocation.x(), inMaxEffectLocation.y() - maxEffectLocation.y()); pattern->setPatternSpaceTransform(patternTransform); filterContext->setFillPattern(pattern); filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size())); #endif }
void SourceAlpha::applySoftware() { ImageBuffer* resultImage = createImageBufferResult(); Filter* filter = this->filter(); if (!resultImage || !filter->sourceImage()) return; setIsAlphaImage(true); FloatRect imageRect(FloatPoint(), absolutePaintRect().size()); GraphicsContext* filterContext = resultImage->context(); filterContext->fillRect(imageRect, Color::black); IntRect srcRect = filter->sourceImageRect(); if (ImageBuffer* sourceImageBuffer = filter->sourceImage()) { filterContext->drawImageBuffer(sourceImageBuffer, FloatRect(IntPoint(srcRect.location() - absolutePaintRect().location()), sourceImageBuffer->size()), 0, CompositeDestinationIn); } }
void FETile::applySoftware() { FilterEffect* in = inputEffect(0); ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; setIsAlphaImage(in->isAlphaImage()); // Source input needs more attention. It has the size of the filterRegion but gives the // size of the cutted sourceImage back. This is part of the specification and optimization. FloatRect tileRect = in->maxEffectRect(); FloatPoint inMaxEffectLocation = tileRect.location(); FloatPoint maxEffectLocation = maxEffectRect().location(); if (in->filterEffectType() == FilterEffectTypeSourceInput) { Filter* filter = this->filter(); tileRect = filter->absoluteFilterRegion(); } OwnPtr<ImageBufferSurface> surface; IntSize intTileSize = roundedIntSize(tileRect.size()); surface = adoptPtr(new UnacceleratedImageBufferSurface(intTileSize)); OwnPtr<ImageBuffer> tileImage = ImageBuffer::create(surface.release()); if (!tileImage) return; GraphicsContext* tileImageContext = tileImage->context(); tileImageContext->scale(FloatSize(intTileSize.width() / tileRect.width(), intTileSize.height() / tileRect.height())); tileImageContext->translate(-inMaxEffectLocation.x(), -inMaxEffectLocation.y()); tileImageContext->drawImageBuffer(in->asImageBuffer(), in->absolutePaintRect().location()); RefPtr<Pattern> pattern = Pattern::create(tileImage->copyImage(CopyBackingStore), true, true); AffineTransform patternTransform; patternTransform.translate(inMaxEffectLocation.x() - maxEffectLocation.x(), inMaxEffectLocation.y() - maxEffectLocation.y()); pattern->setPatternSpaceTransform(patternTransform); GraphicsContext* filterContext = resultImage->context(); filterContext->setFillPattern(pattern); filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size())); }
void FELighting::applySoftware() { FilterEffect* in = inputEffect(0); Uint8ClampedArray* srcPixelArray = createPremultipliedImageResult(); if (!srcPixelArray) return; setIsAlphaImage(false); IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); in->copyPremultipliedImage(srcPixelArray, 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. // Anyway, feConvolveMatrix should also use the implementation IntSize absolutePaintSize = absolutePaintRect().size(); drawLighting(srcPixelArray, absolutePaintSize.width(), absolutePaintSize.height()); }
void FETile::applySoftware() { FilterEffect* in = inputEffect(0); ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; setIsAlphaImage(in->isAlphaImage()); // Source input needs more attention. It has the size of the filterRegion but gives the // size of the cutted sourceImage back. This is part of the specification and optimization. FloatRect tileRect = in->maxEffectRect(); FloatPoint inMaxEffectLocation = tileRect.location(); FloatPoint maxEffectLocation = maxEffectRect().location(); if (in->filterEffectType() == FilterEffectTypeSourceInput) { Filter* filter = this->filter(); tileRect = filter->absoluteFilterRegion(); tileRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); } OwnPtr<ImageBuffer> tileImage; if (!SVGRenderingContext::createImageBufferForPattern(tileRect, tileRect, tileImage, ColorSpaceDeviceRGB, filter()->renderingMode())) return; GraphicsContext* tileImageContext = tileImage->context(); tileImageContext->translate(-inMaxEffectLocation.x(), -inMaxEffectLocation.y()); tileImageContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, in->absolutePaintRect().location()); RefPtr<Pattern> pattern = Pattern::create(tileImage->copyImage(CopyBackingStore), true, true); AffineTransform patternTransform; patternTransform.translate(inMaxEffectLocation.x() - maxEffectLocation.x(), inMaxEffectLocation.y() - maxEffectLocation.y()); pattern->setPatternSpaceTransform(patternTransform); GraphicsContext* filterContext = resultImage->context(); filterContext->setFillPattern(pattern); filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size())); }
void FELighting::apply(Filter* filter) { m_in->apply(filter); if (!m_in->resultImage()) return; if (!getEffectContext()) return; setIsAlphaImage(false); IntRect effectDrawingRect = calculateDrawingIntRect(m_in->scaledSubRegion()); RefPtr<ImageData> srcImageData(m_in->resultImage()->getUnmultipliedImageData(effectDrawingRect)); CanvasPixelArray* srcPixelArray(srcImageData->data()); // 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. // Anyway, feConvolveMatrix should also use the implementation if (drawLighting(srcPixelArray, effectDrawingRect.width(), effectDrawingRect.height())) resultImage()->putUnmultipliedImageData(srcImageData.get(), IntRect(IntPoint(), resultImage()->size()), IntPoint()); }
void FEColorMatrix::apply() { FilterEffect* in = inputEffect(0); in->apply(); if (!in->resultImage()) return; GraphicsContext* filterContext = effectContext(); if (!filterContext) return; filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); IntRect imageRect(IntPoint(), resultImage()->size()); RefPtr<ImageData> imageData = resultImage()->getUnmultipliedImageData(imageRect); ByteArray* pixelArray = imageData->data()->data(); switch (m_type) { case FECOLORMATRIX_TYPE_UNKNOWN: break; case FECOLORMATRIX_TYPE_MATRIX: effectType<FECOLORMATRIX_TYPE_MATRIX>(pixelArray, m_values); break; case FECOLORMATRIX_TYPE_SATURATE: effectType<FECOLORMATRIX_TYPE_SATURATE>(pixelArray, m_values); break; case FECOLORMATRIX_TYPE_HUEROTATE: effectType<FECOLORMATRIX_TYPE_HUEROTATE>(pixelArray, m_values); break; case FECOLORMATRIX_TYPE_LUMINANCETOALPHA: effectType<FECOLORMATRIX_TYPE_LUMINANCETOALPHA>(pixelArray, m_values); setIsAlphaImage(true); break; } resultImage()->putUnmultipliedImageData(imageData.get(), imageRect, IntPoint()); }
void FEMorphology::apply(Filter* filter) { m_in->apply(filter); if (!m_in->resultImage()) return; if (!getEffectContext()) return; setIsAlphaImage(m_in->isAlphaImage()); int radiusX = static_cast<int>(m_radiusX * filter->filterResolution().width()); int radiusY = static_cast<int>(m_radiusY * filter->filterResolution().height()); if (radiusX <= 0 || radiusY <= 0) return; IntRect imageRect(IntPoint(), resultImage()->size()); IntRect effectDrawingRect = calculateDrawingIntRect(m_in->scaledSubRegion()); RefPtr<CanvasPixelArray> srcPixelArray(m_in->resultImage()->getPremultipliedImageData(effectDrawingRect)->data()); RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height()); int effectWidth = effectDrawingRect.width() * 4; // Limit the radius size to effect dimensions radiusX = min(effectDrawingRect.width() - 1, radiusX); radiusY = min(effectDrawingRect.height() - 1, radiusY); Vector<unsigned char> extrema; for (int y = 0; y < effectDrawingRect.height(); ++y) { int startY = max(0, y - radiusY); int endY = min(effectDrawingRect.height() - 1, y + radiusY); for (unsigned channel = 0; channel < 4; ++channel) { // Fill the kernel extrema.clear(); for (int j = 0; j <= radiusX; ++j) { unsigned char columnExtrema = srcPixelArray->get(startY * effectWidth + 4 * j + channel); for (int i = startY; i <= endY; ++i) { unsigned char pixel = srcPixelArray->get(i * effectWidth + 4 * j + channel); if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema) || (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema)) columnExtrema = pixel; } extrema.append(columnExtrema); } // Kernel is filled, get extrema of next column for (int x = 0; x < effectDrawingRect.width(); ++x) { unsigned endX = min(x + radiusX, effectDrawingRect.width() - 1); unsigned char columnExtrema = srcPixelArray->get(startY * effectWidth + endX * 4 + channel); for (int i = startY; i <= endY; ++i) { unsigned char pixel = srcPixelArray->get(i * effectWidth + endX * 4 + channel); if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema) || (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema)) columnExtrema = pixel; } if (x - radiusX >= 0) extrema.remove(0); if (x + radiusX <= effectDrawingRect.width()) extrema.append(columnExtrema); unsigned char entireExtrema = extrema[0]; for (unsigned kernelIndex = 0; kernelIndex < extrema.size(); ++kernelIndex) { if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && extrema[kernelIndex] <= entireExtrema) || (m_type == FEMORPHOLOGY_OPERATOR_DILATE && extrema[kernelIndex] >= entireExtrema)) entireExtrema = extrema[kernelIndex]; } imageData->data()->set(y * effectWidth + 4 * x + channel, entireExtrema); } } } resultImage()->putPremultipliedImageData(imageData.get(), imageRect, IntPoint()); }