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::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(); }
bool FEColorMatrix::platformApplyOpenCL() { FilterContextOpenCL* context = FilterContextOpenCL::context(); if (!context) return false; if (!context->compileFEColorMatrix()) return true; FilterEffect* in = inputEffect(0); OpenCLHandle source = in->openCLImage(); OpenCLHandle destination = createOpenCLImageResult(); IntPoint relativeSourceLocation( absolutePaintRect().x() - in->absolutePaintRect().location().x(), absolutePaintRect().y() - in->absolutePaintRect().location().y()); float components[9]; if (FECOLORMATRIX_TYPE_SATURATE == m_type) calculateSaturateComponents(components, m_values[0]); else if (FECOLORMATRIX_TYPE_HUEROTATE == m_type) calculateHueRotateComponents(components, m_values[0]); context->applyFEColorMatrix(destination, absolutePaintRect().size(), source, relativeSourceLocation, (FECOLORMATRIX_TYPE_MATRIX == m_type) ? m_values.data() : components, m_type); return true; }
void FEColorMatrix::applySoftware() { ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; FilterEffect* in = inputEffect(0); IntRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect()); SkAutoTUnref<SkColorFilter> filter(createColorFilter(m_type, m_values.data())); RefPtr<Image> image = in->asImageBuffer()->copyImage(DontCopyBackingStore); RefPtr<NativeImageSkia> nativeImage = image->nativeImageForCurrentFrame(); if (!nativeImage) return; SkPaint paint; paint.setColorFilter(filter); paint.setXfermodeMode(SkXfermode::kSrc_Mode); resultImage->context()->drawBitmap(nativeImage->bitmap(), drawingRegion.x(), drawingRegion.y(), &paint); if (affectsTransparentPixels()) { IntRect fullRect = IntRect(IntPoint(), absolutePaintRect().size()); resultImage->context()->clipOut(drawingRegion); resultImage->context()->fillRect(fullRect, Color(m_values[4], m_values[9], m_values[14], m_values[19])); } return; }
void FEComponentTransfer::applySoftware() { FilterEffect* in = inputEffect(0); ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; RefPtr<Image> image = in->asImageBuffer()->copyImage(DontCopyBackingStore); RefPtr<NativeImageSkia> nativeImage = image->nativeImageForCurrentFrame(); if (!nativeImage) return; unsigned char rValues[256], gValues[256], bValues[256], aValues[256]; getValues(rValues, gValues, bValues, aValues); IntRect destRect = drawingRegionOfInputImage(in->absolutePaintRect()); SkPaint paint; paint.setColorFilter(SkTableColorFilter::CreateARGB(aValues, rValues, gValues, bValues))->unref(); paint.setXfermodeMode(SkXfermode::kSrc_Mode); resultImage->context()->drawBitmap(nativeImage->bitmap(), destRect.x(), destRect.y(), &paint); if (affectsTransparentPixels()) { IntRect fullRect = IntRect(IntPoint(), absolutePaintRect().size()); resultImage->context()->clipOut(destRect); resultImage->context()->fillRect(fullRect, Color(rValues[0], gValues[0], bValues[0], aValues[0])); } }
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 FilterEffect::transformResultColorSpace(ColorSpace dstColorSpace) { #if USE(CG) // CG handles color space adjustments internally. UNUSED_PARAM(dstColorSpace); #else if (!hasResult() || dstColorSpace == m_resultColorSpace) return; #if ENABLE(OPENCL) if (openCLImage()) { if (m_imageBufferResult) m_imageBufferResult.clear(); FilterContextOpenCL* context = FilterContextOpenCL::context(); ASSERT(context); context->openCLTransformColorSpace(m_openCLImageResult, absolutePaintRect(), m_resultColorSpace, dstColorSpace); } else { #endif // FIXME: We can avoid this potentially unnecessary ImageBuffer conversion by adding // color space transform support for the {pre,un}multiplied arrays. asImageBuffer()->transformColorSpace(m_resultColorSpace, dstColorSpace); #if ENABLE(OPENCL) } #endif m_resultColorSpace = dstColorSpace; if (m_unmultipliedImageResult) m_unmultipliedImageResult.clear(); if (m_premultipliedImageResult) m_premultipliedImageResult.clear(); #endif }
FloatRect FilterEffect::determineAbsolutePaintRect(const FloatRect& originalRequestedRect) { FloatRect requestedRect = originalRequestedRect; // Filters in SVG clip to primitive subregion, while CSS doesn't. if (m_clipsToBounds) requestedRect.intersect(maxEffectRect()); // We may be called multiple times if result is used more than once. Return // quickly if if nothing new is required. if (absolutePaintRect().contains(enclosingIntRect(requestedRect))) return requestedRect; FloatRect inputRect = mapPaintRect(requestedRect, false); FloatRect inputUnion; unsigned size = m_inputEffects.size(); for (unsigned i = 0; i < size; ++i) inputUnion.unite(m_inputEffects.at(i)->determineAbsolutePaintRect(inputRect)); inputUnion = mapPaintRect(inputUnion, true); if (affectsTransparentPixels() || !size) { inputUnion = requestedRect; } else { // Rect may have inflated. Re-intersect with request. inputUnion.intersect(requestedRect); } addAbsolutePaintRect(inputUnion); return inputUnion; }
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); }
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 FEFlood::platformApplySoftware() { ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; Color color = colorWithOverrideAlpha(floodColor().rgb(), floodOpacity()); resultImage->context()->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size()), color, ColorSpaceDeviceRGB); }
void FEFlood::apply(Filter* filter) { GraphicsContext* filterContext = effectContext(filter); if (!filterContext) return; Color color = colorWithOverrideAlpha(floodColor().rgb(), floodOpacity()); filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size()), color, DeviceColorSpace); }
FloatRect FEComposite::determineAbsolutePaintRect(const FloatRect& originalRequestedRect) { FloatRect requestedRect = originalRequestedRect; if (clipsToBounds()) requestedRect.intersect(maxEffectRect()); // We may be called multiple times if result is used more than once. Return // quickly if nothing new is required. if (absolutePaintRect().contains(enclosingIntRect(requestedRect))) return requestedRect; // No mapPaintRect required for FEComposite. FloatRect input1Rect = inputEffect(1)->determineAbsolutePaintRect(requestedRect); FloatRect affectedRect; switch (m_type) { case FECOMPOSITE_OPERATOR_IN: // 'in' has output only in the intersection of both inputs. affectedRect = intersection(input1Rect, inputEffect(0)->determineAbsolutePaintRect(input1Rect)); break; case FECOMPOSITE_OPERATOR_ATOP: // 'atop' has output only in the extents of the second input. // Make sure first input knows where it needs to produce output. inputEffect(0)->determineAbsolutePaintRect(input1Rect); affectedRect = input1Rect; break; case FECOMPOSITE_OPERATOR_ARITHMETIC: if (k4() > 0) { // Make sure first input knows where it needs to produce output. inputEffect(0)->determineAbsolutePaintRect(requestedRect); // Arithmetic with non-zero k4 may influnce the complete filter primitive // region. So we can't optimize the paint region here. affectedRect = requestedRect; break; } if (k2() <= 0) { // Input 0 does not appear where input 1 is not present. FloatRect input0Rect = inputEffect(0)->determineAbsolutePaintRect(input1Rect); if (k3() > 0) { affectedRect = input1Rect; } else { // Just k1 is positive. Use intersection. affectedRect = intersection(input1Rect, input0Rect); } break; } // else fall through to use union default: // Take the union of both input effects. affectedRect = unionRect(input1Rect, inputEffect(0)->determineAbsolutePaintRect(requestedRect)); break; } affectedRect.intersect(requestedRect); addAbsolutePaintRect(affectedRect); return affectedRect; }
void FEFlood::applySoftware() { ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; Color color = floodColor().combineWithAlpha(floodOpacity()); resultImage->context()->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size()), color); FilterEffect::setResultColorSpace(ColorSpaceDeviceRGB); }
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 FELighting::getTransform(FloatPoint3D* scale, FloatSize* offset) const { FloatRect initialEffectRect = effectBoundaries(); FloatRect absoluteEffectRect = filter()->mapLocalRectToAbsoluteRect(initialEffectRect); FloatPoint absoluteLocation(absolutePaintRect().location()); FloatSize positionOffset(absoluteLocation - absoluteEffectRect.location()); offset->setWidth(positionOffset.width()); offset->setHeight(positionOffset.height()); scale->setX(initialEffectRect.width() > 0.0f && initialEffectRect.width() > 0.0f ? absoluteEffectRect.width() / initialEffectRect.width() : 1.0f); scale->setY(initialEffectRect.height() > 0.0f && initialEffectRect.height() > 0.0f ? absoluteEffectRect.height() / initialEffectRect.height() : 1.0f); // X and Y scale should be the same, but, if not, do a best effort by averaging the 2 for Z scale scale->setZ(0.5f * (scale->x() + scale->y())); }
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 = effectContext(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, DeviceColorSpace); filterContext->restore(); }
void FEDisplacementMap::apply() { if (hasResult()) return; FilterEffect* in = inputEffect(0); FilterEffect* in2 = inputEffect(1); in->apply(); in2->apply(); if (!in->hasResult() || !in2->hasResult()) return; if (m_xChannelSelector == CHANNEL_UNKNOWN || m_yChannelSelector == CHANNEL_UNKNOWN) return; ByteArray* dstPixelArray = createPremultipliedImageResult(); if (!dstPixelArray) return; IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<ByteArray> srcPixelArrayA = in->asPremultipliedImage(effectADrawingRect); IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); RefPtr<ByteArray> srcPixelArrayB = in2->asUnmultipliedImage(effectBDrawingRect); ASSERT(srcPixelArrayA->length() == srcPixelArrayB->length()); Filter* filter = this->filter(); IntSize paintSize = absolutePaintRect().size(); float scaleX = filter->applyHorizontalScale(m_scale / 255); float scaleY = filter->applyVerticalScale(m_scale / 255); float scaleAdjustmentX = filter->applyHorizontalScale(0.5f - 0.5f * m_scale); float scaleAdjustmentY = filter->applyVerticalScale(0.5f - 0.5f * m_scale); int stride = paintSize.width() * 4; for (int y = 0; y < paintSize.height(); ++y) { int line = y * stride; for (int x = 0; x < paintSize.width(); ++x) { int dstIndex = line + x * 4; int srcX = x + static_cast<int>(scaleX * srcPixelArrayB->get(dstIndex + m_xChannelSelector - 1) + scaleAdjustmentX); int srcY = y + static_cast<int>(scaleY * srcPixelArrayB->get(dstIndex + m_yChannelSelector - 1) + scaleAdjustmentY); for (unsigned channel = 0; channel < 4; ++channel) { if (srcX < 0 || srcX >= paintSize.width() || srcY < 0 || srcY >= paintSize.height()) dstPixelArray->set(dstIndex + channel, static_cast<unsigned char>(0)); else { unsigned char pixelValue = srcPixelArrayA->get(srcY * stride + srcX * 4 + channel); dstPixelArray->set(dstIndex + channel, pixelValue); } } } } }
void FEImage::platformApplySoftware() { RenderObject* renderer = referencedRenderer(); if (!m_image && !renderer) return; ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; SVGFilter* svgFilter = static_cast<SVGFilter*>(filter()); FloatRect destRect = svgFilter->absoluteTransform().mapRect(filterPrimitiveSubregion()); FloatRect srcRect; if (renderer) srcRect = svgFilter->absoluteTransform().mapRect(renderer->repaintRectInLocalCoordinates()); else { srcRect = FloatRect(FloatPoint(), m_image->size()); m_preserveAspectRatio.transformRect(destRect, srcRect); } IntPoint paintLocation = absolutePaintRect().location(); destRect.move(-paintLocation.x(), -paintLocation.y()); // FEImage results are always in ColorSpaceDeviceRGB setResultColorSpace(ColorSpaceDeviceRGB); if (renderer) { const AffineTransform& absoluteTransform = svgFilter->absoluteTransform(); resultImage->context()->concatCTM(absoluteTransform); SVGElement* contextNode = static_cast<SVGElement*>(renderer->node()); if (contextNode->isStyled() && static_cast<SVGStyledElement*>(contextNode)->hasRelativeLengths()) { SVGLengthContext lengthContext(contextNode); float width = 0; float height = 0; // If we're referencing an element with percentage units, eg. <rect with="30%"> those values were resolved against the viewport. // Build up a transformation that maps from the viewport space to the filter primitive subregion. if (lengthContext.determineViewport(width, height)) resultImage->context()->concatCTM(makeMapBetweenRects(FloatRect(0, 0, width, height), destRect)); } AffineTransform contentTransformation; SVGRenderingContext::renderSubtreeToImageBuffer(resultImage, renderer, contentTransformation); return; } resultImage->context()->drawImage(m_image.get(), ColorSpaceDeviceRGB, destRect, srcRect); }
inline void FETurbulence::fillRegion(ByteArray* pixelArray, PaintingData& paintingData, int startY, int endY) { IntRect filterRegion = absolutePaintRect(); IntPoint point(0, filterRegion.y() + startY); int indexOfPixelChannel = startY * (filterRegion.width() << 2); int channel; for (int y = startY; y < endY; ++y) { point.setY(point.y() + 1); point.setX(filterRegion.x()); for (int x = 0; x < filterRegion.width(); ++x) { point.setX(point.x() + 1); for (channel = 0; channel < 4; ++channel, ++indexOfPixelChannel) pixelArray->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(channel, paintingData, filter()->mapAbsolutePointToLocalPoint(point))); } } }
FloatRect FEDisplacementMap::determineAbsolutePaintRect(const FloatRect& requestedRect) { FloatRect rect = requestedRect; if (clipsToBounds()) rect.intersect(maxEffectRect()); if (absolutePaintRect().contains(enclosingIntRect(rect))) return rect; rect = mapPaintRect(rect, false); rect = inputEffect(0)->determineAbsolutePaintRect(rect); rect = mapPaintRect(rect, true); rect.intersect(requestedRect); addAbsolutePaintRect(rect); return rect; }
void FEDisplacementMap::applySoftware() { FilterEffect* in = inputEffect(0); FilterEffect* in2 = inputEffect(1); ASSERT(m_xChannelSelector != CHANNEL_UNKNOWN); ASSERT(m_yChannelSelector != CHANNEL_UNKNOWN); Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult(); if (!dstPixelArray) return; IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<Uint8ClampedArray> srcPixelArrayA = in->asPremultipliedImage(effectADrawingRect); IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); RefPtr<Uint8ClampedArray> srcPixelArrayB = in2->asUnmultipliedImage(effectBDrawingRect); ASSERT(srcPixelArrayA->length() == srcPixelArrayB->length()); Filter* filter = this->filter(); IntSize paintSize = absolutePaintRect().size(); float scaleX = filter->applyHorizontalScale(m_scale); float scaleY = filter->applyVerticalScale(m_scale); float scaleForColorX = scaleX / 255.0; float scaleForColorY = scaleY / 255.0; float scaledOffsetX = 0.5 - scaleX * 0.5; float scaledOffsetY = 0.5 - scaleY * 0.5; int stride = paintSize.width() * 4; for (int y = 0; y < paintSize.height(); ++y) { int line = y * stride; for (int x = 0; x < paintSize.width(); ++x) { int dstIndex = line + x * 4; int srcX = x + static_cast<int>(scaleForColorX * srcPixelArrayB->item(dstIndex + m_xChannelSelector - 1) + scaledOffsetX); int srcY = y + static_cast<int>(scaleForColorY * srcPixelArrayB->item(dstIndex + m_yChannelSelector - 1) + scaledOffsetY); for (unsigned channel = 0; channel < 4; ++channel) { if (srcX < 0 || srcX >= paintSize.width() || srcY < 0 || srcY >= paintSize.height()) { dstPixelArray->set(dstIndex + channel, static_cast<unsigned char>(0)); } else { unsigned char pixelValue = srcPixelArrayA->item(srcY * stride + srcX * 4 + channel); dstPixelArray->set(dstIndex + channel, pixelValue); } } } } }
void FEImage::apply(Filter* filter) { if (!m_image.get()) return; GraphicsContext* filterContext = effectContext(filter); if (!filterContext) return; FloatRect srcRect(FloatPoint(), m_image->size()); FloatRect destRect(m_absoluteSubregion); m_preserveAspectRatio.transformRect(destRect, srcRect); IntPoint paintLocation = absolutePaintRect().location(); destRect.move(-paintLocation.x(), -paintLocation.y()); filterContext->drawImage(m_image.get(), DeviceColorSpace, destRect, srcRect); }
void FEImage::platformApplySoftware() { if (!m_image.get()) return; ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; FloatRect srcRect(FloatPoint(), m_image->size()); FloatRect destRect(m_absoluteSubregion); m_preserveAspectRatio.transformRect(destRect, srcRect); IntPoint paintLocation = absolutePaintRect().location(); destRect.move(-paintLocation.x(), -paintLocation.y()); resultImage->context()->drawImage(m_image.get(), ColorSpaceDeviceRGB, destRect, srcRect); }
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 FEImage::applySoftware() { RenderObject* renderer = referencedRenderer(); if (!m_image && !renderer) return; ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; IntPoint paintLocation = absolutePaintRect().location(); resultImage->context()->translate(-paintLocation.x(), -paintLocation.y()); // FEImage results are always in ColorSpaceDeviceRGB setResultColorSpace(ColorSpaceDeviceRGB); FloatRect destRect = filter()->mapLocalRectToAbsoluteRect(filterPrimitiveSubregion()); FloatRect srcRect; if (!renderer) { srcRect = FloatRect(FloatPoint(), m_image->size()); m_preserveAspectRatio->transformRect(destRect, srcRect); resultImage->context()->drawImage(m_image.get(), destRect, srcRect); return; } SVGElement* contextNode = toSVGElement(renderer->node()); if (contextNode->hasRelativeLengths()) { // FIXME: This fixes relative lengths but breaks non-relative ones (see crbug/260709). SVGLengthContext lengthContext(contextNode); FloatSize viewportSize; // If we're referencing an element with percentage units, eg. <rect with="30%"> those values were resolved against the viewport. // Build up a transformation that maps from the viewport space to the filter primitive subregion. if (lengthContext.determineViewport(viewportSize)) resultImage->context()->concatCTM(makeMapBetweenRects(FloatRect(FloatPoint(), viewportSize), destRect)); } else { resultImage->context()->translate(destRect.x(), destRect.y()); resultImage->context()->concatCTM(filter()->absoluteTransform()); } AffineTransform contentTransformation; SVGRenderingContext::renderSubtree(resultImage->context(), renderer, contentTransformation); }
void FETurbulence::apply() { if (hasResult()) return; ByteArray* pixelArray = createUnmultipliedImageResult(); if (!pixelArray) return; if (absolutePaintRect().isEmpty()) return; PaintingData paintingData(m_seed, roundedIntSize(filterPrimitiveSubregion().size())); initPaint(paintingData); #if ENABLE(PARALLEL_JOBS) int optimalThreadNumber = (absolutePaintRect().width() * absolutePaintRect().height()) / s_minimalRectDimension; if (optimalThreadNumber > 1) { // Initialize parallel jobs ParallelJobs<FillRegionParameters> parallelJobs(&WebCore::FETurbulence::fillRegionWorker, optimalThreadNumber); // Fill the parameter array int i = parallelJobs.numberOfJobs(); if (i > 1) { int startY = 0; int stepY = absolutePaintRect().height() / i; for (; i > 0; --i) { FillRegionParameters& params = parallelJobs.parameter(i-1); params.filter = this; params.pixelArray = pixelArray; params.paintingData = &paintingData; params.startY = startY; if (i != 1) { params.endY = startY + stepY; startY = startY + stepY; } else params.endY = absolutePaintRect().height(); } // Execute parallel jobs parallelJobs.execute(); return; } } // Fallback to sequential mode if there is no room for a new thread or the paint area is too small #endif // ENABLE(PARALLEL_JOBS) fillRegion(pixelArray, paintingData, 0, absolutePaintRect().height()); }
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 FEDropShadow::platformApplySoftware() { FilterEffect* in = inputEffect(0); ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; Filter& filter = this->filter(); FloatSize blurRadius(2 * filter.applyHorizontalScale(m_stdX), 2 * filter.applyVerticalScale(m_stdY)); blurRadius.scale(filter.filterScale()); FloatSize offset(filter.applyHorizontalScale(m_dx), filter.applyVerticalScale(m_dy)); FloatRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect()); FloatRect drawingRegionWithOffset(drawingRegion); drawingRegionWithOffset.move(offset); ImageBuffer* sourceImage = in->asImageBuffer(); if (!sourceImage) return; GraphicsContext& resultContext = resultImage->context(); resultContext.setAlpha(m_shadowOpacity); resultContext.drawImageBuffer(*sourceImage, drawingRegionWithOffset); resultContext.setAlpha(1); ShadowBlur contextShadow(blurRadius, offset, m_shadowColor); // TODO: Direct pixel access to ImageBuffer would avoid copying the ImageData. IntRect shadowArea(IntPoint(), resultImage->internalSize()); RefPtr<Uint8ClampedArray> srcPixelArray = resultImage->getPremultipliedImageData(shadowArea, ImageBuffer::BackingStoreCoordinateSystem); contextShadow.blurLayerImage(srcPixelArray->data(), shadowArea.size(), 4 * shadowArea.size().width()); resultImage->putByteArray(Premultiplied, srcPixelArray.get(), shadowArea.size(), shadowArea, IntPoint(), ImageBuffer::BackingStoreCoordinateSystem); resultContext.setCompositeOperation(CompositeSourceIn); resultContext.fillRect(FloatRect(FloatPoint(), absolutePaintRect().size()), m_shadowColor); resultContext.setCompositeOperation(CompositeDestinationOver); resultImage->context().drawImageBuffer(*sourceImage, drawingRegion); }