void FEBlend::platformApplySoftware() { FilterEffect* in = inputEffect(0); FilterEffect* in2 = inputEffect(1); ASSERT(m_mode > FEBLEND_MODE_UNKNOWN); ASSERT(m_mode <= FEBLEND_MODE_LIGHTEN); 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->asPremultipliedImage(effectBDrawingRect); unsigned pixelArrayLength = srcPixelArrayA->length(); ASSERT(pixelArrayLength == srcPixelArrayB->length()); for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) { unsigned char alphaA = srcPixelArrayA->item(pixelOffset + 3); unsigned char alphaB = srcPixelArrayB->item(pixelOffset + 3); for (unsigned channel = 0; channel < 3; ++channel) { unsigned char colorA = srcPixelArrayA->item(pixelOffset + channel); unsigned char colorB = srcPixelArrayB->item(pixelOffset + channel); unsigned char result; switch (m_mode) { case FEBLEND_MODE_NORMAL: result = normal(colorA, colorB, alphaA, alphaB); break; case FEBLEND_MODE_MULTIPLY: result = multiply(colorA, colorB, alphaA, alphaB); break; case FEBLEND_MODE_SCREEN: result = screen(colorA, colorB, alphaA, alphaB); break; case FEBLEND_MODE_DARKEN: result = darken(colorA, colorB, alphaA, alphaB); break; case FEBLEND_MODE_LIGHTEN: result = lighten(colorA, colorB, alphaA, alphaB); break; case FEBLEND_MODE_UNKNOWN: default: result = 0; break; } dstPixelArray->set(pixelOffset + channel, result); } unsigned char alphaR = 255 - ((255 - alphaA) * (255 - alphaB)) / 255; dstPixelArray->set(pixelOffset + 3, alphaR); } }
void FEComposite::platformApplySoftware() { FilterEffect* in = inputEffect(0); FilterEffect* in2 = inputEffect(1); if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC) { ByteArray* dstPixelArray = createPremultipliedImageResult(); if (!dstPixelArray) return; IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<ByteArray> srcPixelArray = in->asPremultipliedImage(effectADrawingRect); IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); in2->copyPremultipliedImage(dstPixelArray, effectBDrawingRect); arithmetic(srcPixelArray.get(), dstPixelArray, m_k1, m_k2, m_k3, m_k4); return; } ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; GraphicsContext* filterContext = resultImage->context(); FloatRect srcRect = FloatRect(0, 0, -1, -1); switch (m_type) { case FECOMPOSITE_OPERATOR_OVER: filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect())); filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); break; case FECOMPOSITE_OPERATOR_IN: { GraphicsContextStateSaver stateSaver(*filterContext); filterContext->clipToImageBuffer(in2->asImageBuffer(), drawingRegionOfInputImage(in2->absolutePaintRect())); filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); break; } case FECOMPOSITE_OPERATOR_OUT: filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()), srcRect, CompositeDestinationOut); break; case FECOMPOSITE_OPERATOR_ATOP: filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect())); filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeSourceAtop); break; case FECOMPOSITE_OPERATOR_XOR: filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect())); filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeXOR); break; default: break; } }
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 FEComponentTransfer::platformApplySoftware() { FilterEffect* in = inputEffect(0); ByteArray* pixelArray = createUnmultipliedImageResult(); if (!pixelArray) return; unsigned char rValues[256], gValues[256], bValues[256], aValues[256]; for (unsigned i = 0; i < 256; ++i) rValues[i] = gValues[i] = bValues[i] = aValues[i] = i; unsigned char* tables[] = { rValues, gValues, bValues, aValues }; ComponentTransferFunction transferFunction[] = {m_redFunc, m_greenFunc, m_blueFunc, m_alphaFunc}; TransferType callEffect[] = {identity, identity, table, discrete, linear, gamma}; for (unsigned channel = 0; channel < 4; channel++) { ASSERT(static_cast<size_t>(transferFunction[channel].type) < WTF_ARRAY_LENGTH(callEffect)); (*callEffect[transferFunction[channel].type])(tables[channel], transferFunction[channel]); } IntRect drawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); in->copyUnmultipliedImage(pixelArray, drawingRect); unsigned pixelArrayLength = pixelArray->length(); for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) { for (unsigned channel = 0; channel < 4; ++channel) { unsigned char c = pixelArray->get(pixelOffset + channel); pixelArray->set(pixelOffset + channel, tables[channel][c]); } } }
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); }
bool FECustomFilter::applyShader() { Uint8ClampedArray* dstPixelArray = m_customFilterRenderer->premultipliedAlpha() ? createPremultipliedImageResult() : createUnmultipliedImageResult(); if (!dstPixelArray) return false; if (!prepareForDrawing()) return false; FilterEffect* in = inputEffect(0); IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); IntSize newContextSize(effectDrawingRect.size()); if (!resizeContextIfNeeded(newContextSize)) return false; bool needsInputTexture = m_customFilterRenderer->programNeedsInputTexture(); if (needsInputTexture) { RefPtr<Uint8ClampedArray> srcPixelArray = in->asUnmultipliedImage(effectDrawingRect); uploadInputTexture(srcPixelArray.get()); } drawFilterMesh(needsInputTexture ? m_inputTexture : 0); ASSERT(static_cast<size_t>(newContextSize.width() * newContextSize.height() * 4) == dstPixelArray->length()); m_context->readPixels(0, 0, newContextSize.width(), newContextSize.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, dstPixelArray->data()); return true; }
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 FEComponentTransfer::apply() { FilterEffect* in = inputEffect(0); in->apply(); if (!in->resultImage()) return; if (!effectContext()) return; unsigned char rValues[256], gValues[256], bValues[256], aValues[256]; for (unsigned i = 0; i < 256; ++i) rValues[i] = gValues[i] = bValues[i] = aValues[i] = i; unsigned char* tables[] = { rValues, gValues, bValues, aValues }; ComponentTransferFunction transferFunction[] = {m_redFunc, m_greenFunc, m_blueFunc, m_alphaFunc}; TransferType callEffect[] = {identity, identity, table, discrete, linear, gamma}; for (unsigned channel = 0; channel < 4; channel++) (*callEffect[transferFunction[channel].type])(tables[channel], transferFunction[channel]); IntRect drawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<ImageData> imageData = in->resultImage()->getUnmultipliedImageData(drawingRect); ByteArray* pixelArray = imageData->data()->data(); unsigned pixelArrayLength = pixelArray->length(); for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) { for (unsigned channel = 0; channel < 4; ++channel) { unsigned char c = pixelArray->get(pixelOffset + channel); pixelArray->set(pixelOffset + channel, tables[channel][c]); } } resultImage()->putUnmultipliedImageData(imageData.get(), IntRect(IntPoint(), resultImage()->size()), IntPoint()); }
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 FEBlend::apply(Filter* filter) { FilterEffect* in = inputEffect(0); FilterEffect* in2 = inputEffect(1); in->apply(filter); in2->apply(filter); if (!in->resultImage() || !in2->resultImage()) return; if (m_mode == FEBLEND_MODE_UNKNOWN) return; if (!effectContext(filter)) return; IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<CanvasPixelArray> srcPixelArrayA(in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data()); IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); RefPtr<CanvasPixelArray> srcPixelArrayB(in2->resultImage()->getPremultipliedImageData(effectBDrawingRect)->data()); IntRect imageRect(IntPoint(), resultImage()->size()); RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height()); // Keep synchronized with BlendModeType static const BlendType callEffect[] = {unknown, normal, multiply, screen, darken, lighten}; ASSERT(srcPixelArrayA->length() == srcPixelArrayB->length()); for (unsigned pixelOffset = 0; pixelOffset < srcPixelArrayA->length(); pixelOffset += 4) { unsigned char alphaA = srcPixelArrayA->get(pixelOffset + 3); unsigned char alphaB = srcPixelArrayB->get(pixelOffset + 3); for (unsigned channel = 0; channel < 3; ++channel) { unsigned char colorA = srcPixelArrayA->get(pixelOffset + channel); unsigned char colorB = srcPixelArrayB->get(pixelOffset + channel); unsigned char result = (*callEffect[m_mode])(colorA, colorB, alphaA, alphaB); imageData->data()->set(pixelOffset + channel, result); } unsigned char alphaR = 255 - ((255 - alphaA) * (255 - alphaB)) / 255; imageData->data()->set(pixelOffset + 3, alphaR); } resultImage()->putPremultipliedImageData(imageData.get(), imageRect, IntPoint()); }
void FEBlend::apply() { if (hasResult()) return; FilterEffect* in = inputEffect(0); FilterEffect* in2 = inputEffect(1); in->apply(); in2->apply(); if (!in->hasResult() || !in2->hasResult()) return; ASSERT(m_mode > FEBLEND_MODE_UNKNOWN); ASSERT(m_mode <= FEBLEND_MODE_LIGHTEN); 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->asPremultipliedImage(effectBDrawingRect); // Keep synchronized with BlendModeType static const BlendType callEffect[] = {unknown, normal, multiply, screen, darken, lighten}; unsigned pixelArrayLength = srcPixelArrayA->length(); ASSERT(pixelArrayLength == srcPixelArrayB->length()); for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) { unsigned char alphaA = srcPixelArrayA->get(pixelOffset + 3); unsigned char alphaB = srcPixelArrayB->get(pixelOffset + 3); for (unsigned channel = 0; channel < 3; ++channel) { unsigned char colorA = srcPixelArrayA->get(pixelOffset + channel); unsigned char colorB = srcPixelArrayB->get(pixelOffset + channel); unsigned char result = (*callEffect[m_mode])(colorA, colorB, alphaA, alphaB); dstPixelArray->set(pixelOffset + channel, result); } unsigned char alphaR = 255 - ((255 - alphaA) * (255 - alphaB)) / 255; dstPixelArray->set(pixelOffset + 3, alphaR); } }
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); }
bool FEBlend::applySoftwareNEON() { if (m_mode != WebBlendModeNormal && m_mode != WebBlendModeMultiply && m_mode != WebBlendModeScreen && m_mode != WebBlendModeDarken && m_mode != WebBlendModeLighten) return false; Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult(); if (!dstPixelArray) return true; FilterEffect* in = inputEffect(0); FilterEffect* in2 = inputEffect(1); IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<Uint8ClampedArray> srcPixelArrayA = in->asPremultipliedImage(effectADrawingRect); IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); RefPtr<Uint8ClampedArray> srcPixelArrayB = in2->asPremultipliedImage(effectBDrawingRect); unsigned pixelArrayLength = srcPixelArrayA->length(); ASSERT(pixelArrayLength == srcPixelArrayB->length()); if (pixelArrayLength >= 8) { platformApplyNEON(srcPixelArrayA->data(), srcPixelArrayB->data(), dstPixelArray->data(), pixelArrayLength); } else { // If there is just one pixel we expand it to two. ASSERT(pixelArrayLength > 0); uint32_t sourceA[2] = {0, 0}; uint32_t sourceBAndDest[2] = {0, 0}; sourceA[0] = reinterpret_cast<uint32_t*>(srcPixelArrayA->data())[0]; sourceBAndDest[0] = reinterpret_cast<uint32_t*>(srcPixelArrayB->data())[0]; platformApplyNEON(reinterpret_cast<uint8_t*>(sourceA), reinterpret_cast<uint8_t*>(sourceBAndDest), reinterpret_cast<uint8_t*>(sourceBAndDest), 8); reinterpret_cast<uint32_t*>(dstPixelArray->data())[0] = sourceBAndDest[0]; } return true; }
void FEBlend::platformApplySoftware() { FilterEffect* in = inputEffect(0); FilterEffect* in2 = inputEffect(1); ASSERT(m_mode > FEBLEND_MODE_UNKNOWN); ASSERT(m_mode <= FEBLEND_MODE_LIGHTEN); 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->asPremultipliedImage(effectBDrawingRect); unsigned pixelArrayLength = srcPixelArrayA->length(); ASSERT(pixelArrayLength == srcPixelArrayB->length()); #if HAVE(ARM_NEON_INTRINSICS) if (pixelArrayLength >= 8) platformApplyNEON(srcPixelArrayA->data(), srcPixelArrayB->data(), dstPixelArray->data(), pixelArrayLength); else { // If there is just one pixel we expand it to two. ASSERT(pixelArrayLength > 0); uint32_t sourceA[2] = {0, 0}; uint32_t sourceBAndDest[2] = {0, 0}; sourceA[0] = reinterpret_cast<uint32_t*>(srcPixelArrayA->data())[0]; sourceBAndDest[0] = reinterpret_cast<uint32_t*>(srcPixelArrayB->data())[0]; platformApplyNEON(reinterpret_cast<uint8_t*>(sourceA), reinterpret_cast<uint8_t*>(sourceBAndDest), reinterpret_cast<uint8_t*>(sourceBAndDest), 8); reinterpret_cast<uint32_t*>(dstPixelArray->data())[0] = sourceBAndDest[0]; } #else platformApplyGeneric(srcPixelArrayA->data(), srcPixelArrayB->data(), dstPixelArray->data(), pixelArrayLength); #endif }
bool FECustomFilter::applyShader() { Uint8ClampedArray* dstPixelArray = createUnmultipliedImageResult(); if (!dstPixelArray) return false; FilterEffect* in = inputEffect(0); IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<Uint8ClampedArray> srcPixelArray = in->asUnmultipliedImage(effectDrawingRect); IntSize newContextSize(effectDrawingRect.size()); bool hadContext = m_context; if (!m_context && !initializeContext()) return false; m_context->makeContextCurrent(); if (!hadContext || m_contextSize != newContextSize) resizeContext(newContextSize); #if !PLATFORM(BLACKBERRY) // BlackBerry defines its own Texture class. // Do not draw the filter if the input image cannot fit inside a single GPU texture. if (m_inputTexture->tiles().numTilesX() != 1 || m_inputTexture->tiles().numTilesY() != 1) return false; #endif // The shader had compiler errors. We cannot draw anything. if (!m_compiledProgram->isInitialized()) return false; m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_frameBuffer); m_context->viewport(0, 0, newContextSize.width(), newContextSize.height()); m_context->clearColor(0, 0, 0, 0); m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT); bindProgramAndBuffers(srcPixelArray.get()); m_context->drawElements(GraphicsContext3D::TRIANGLES, m_mesh->indicesCount(), GraphicsContext3D::UNSIGNED_SHORT, 0); unbindVertexAttributes(); ASSERT(static_cast<size_t>(newContextSize.width() * newContextSize.height() * 4) == dstPixelArray->length()); m_context->readPixels(0, 0, newContextSize.width(), newContextSize.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, dstPixelArray->data()); return true; }
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 FECustomFilter::platformApplySoftware() { ByteArray* dstPixelArray = createPremultipliedImageResult(); if (!dstPixelArray) return; FilterEffect* in = inputEffect(0); IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<ByteArray> srcPixelArray = in->asPremultipliedImage(effectDrawingRect); IntSize newContextSize(effectDrawingRect.size()); bool hadContext = m_context; if (!m_context) initializeContext(newContextSize); if (!hadContext || m_contextSize != newContextSize) resizeContext(newContextSize); // Do not draw the filter if the input image cannot fit inside a single GPU texture. if (m_inputTexture->tiles().numTilesX() != 1 || m_inputTexture->tiles().numTilesY() != 1) return; // The shader had compiler errors. We cannot draw anything. if (!m_shader->isInitialized()) return; m_context->clearColor(0, 0, 0, 0); m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT); bindProgramAndBuffers(srcPixelArray.get()); m_context->drawElements(GraphicsContext3D::TRIANGLES, m_mesh->indicesCount(), GraphicsContext3D::UNSIGNED_SHORT, 0); m_drawingBuffer->commit(); RefPtr<ImageData> imageData = m_context->paintRenderingResultsToImageData(m_drawingBuffer.get()); ByteArray* gpuResult = imageData->data()->data(); ASSERT(gpuResult->length() == dstPixelArray->length()); memcpy(dstPixelArray->data(), gpuResult->data(), gpuResult->length()); }
void FECustomFilter::platformApplySoftware() { Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult(); if (!dstPixelArray) return; FilterEffect* in = inputEffect(0); IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<Uint8ClampedArray> srcPixelArray = in->asPremultipliedImage(effectDrawingRect); IntSize newContextSize(effectDrawingRect.size()); bool hadContext = m_context; if (!m_context) initializeContext(); if (!hadContext || m_contextSize != newContextSize) resizeContext(newContextSize); // Do not draw the filter if the input image cannot fit inside a single GPU texture. if (m_inputTexture->tiles().numTilesX() != 1 || m_inputTexture->tiles().numTilesY() != 1) return; // The shader had compiler errors. We cannot draw anything. if (!m_shader->isInitialized()) return; m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_frameBuffer); m_context->viewport(0, 0, newContextSize.width(), newContextSize.height()); m_context->clearColor(0, 0, 0, 0); m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT); bindProgramAndBuffers(srcPixelArray.get()); m_context->drawElements(GraphicsContext3D::TRIANGLES, m_mesh->indicesCount(), GraphicsContext3D::UNSIGNED_SHORT, 0); ASSERT(static_cast<size_t>(newContextSize.width() * newContextSize.height() * 4) == dstPixelArray->length()); m_context->readPixels(0, 0, newContextSize.width(), newContextSize.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, dstPixelArray->data()); }
void FEComponentTransfer::platformApplySoftware() { FilterEffect* in = inputEffect(0); Uint8ClampedArray* pixelArray = createUnmultipliedImageResult(); if (!pixelArray) return; unsigned char rValues[256], gValues[256], bValues[256], aValues[256]; getValues(rValues, gValues, bValues, aValues); unsigned char* tables[] = { rValues, gValues, bValues, aValues }; IntRect drawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); in->copyUnmultipliedImage(pixelArray, drawingRect); unsigned pixelArrayLength = pixelArray->length(); for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) { for (unsigned channel = 0; channel < 4; ++channel) { unsigned char c = pixelArray->item(pixelOffset + channel); pixelArray->set(pixelOffset + channel, tables[channel][c]); } } }
void FEConvolveMatrix::platformApplySoftware() { FilterEffect* in = inputEffect(0); Uint8ClampedArray* resultImage; if (m_preserveAlpha) resultImage = createUnmultipliedImageResult(); else resultImage = createPremultipliedImageResult(); if (!resultImage) return; IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<Uint8ClampedArray> srcPixelArray; if (m_preserveAlpha) srcPixelArray = in->asUnmultipliedImage(effectDrawingRect); else srcPixelArray = in->asPremultipliedImage(effectDrawingRect); IntSize paintSize = absolutePaintRect().size(); PaintingData paintingData; paintingData.srcPixelArray = srcPixelArray.get(); paintingData.dstPixelArray = resultImage; paintingData.width = paintSize.width(); paintingData.height = paintSize.height(); paintingData.bias = m_bias * 255; // Drawing fully covered pixels int clipRight = paintSize.width() - m_kernelSize.width(); int clipBottom = paintSize.height() - m_kernelSize.height(); if (clipRight >= 0 && clipBottom >= 0) { int optimalThreadNumber = (absolutePaintRect().width() * absolutePaintRect().height()) / s_minimalRectDimension; if (optimalThreadNumber > 1) { WTF::ParallelJobs<InteriorPixelParameters> parallelJobs(&WebCore::FEConvolveMatrix::setInteriorPixelsWorker, optimalThreadNumber); const int numOfThreads = parallelJobs.numberOfJobs(); // Split the job into "heightPerThread" jobs but there a few jobs that need to be slightly larger since // heightPerThread * jobs < total size. These extras are handled by the remainder "jobsWithExtra". const int heightPerThread = clipBottom / numOfThreads; const int jobsWithExtra = clipBottom % numOfThreads; int startY = 0; for (int job = 0; job < numOfThreads; ++job) { InteriorPixelParameters& param = parallelJobs.parameter(job); param.filter = this; param.paintingData = &paintingData; param.clipRight = clipRight; param.clipBottom = clipBottom; param.yStart = startY; startY += job < jobsWithExtra ? heightPerThread + 1 : heightPerThread; param.yEnd = startY; } parallelJobs.execute(); } else { // Fallback to single threaded mode. setInteriorPixels(paintingData, clipRight, clipBottom, 0, clipBottom); } clipRight += m_targetOffset.x() + 1; clipBottom += m_targetOffset.y() + 1; if (m_targetOffset.y() > 0) setOuterPixels(paintingData, 0, 0, paintSize.width(), m_targetOffset.y()); if (clipBottom < paintSize.height()) setOuterPixels(paintingData, 0, clipBottom, paintSize.width(), paintSize.height()); if (m_targetOffset.x() > 0) setOuterPixels(paintingData, 0, m_targetOffset.y(), m_targetOffset.x(), clipBottom); if (clipRight < paintSize.width()) setOuterPixels(paintingData, clipRight, m_targetOffset.y(), paintSize.width(), clipBottom); } else { // Rare situation, not optimizied for speed setOuterPixels(paintingData, 0, 0, paintSize.width(), paintSize.height()); } }
void FEConvolveMatrix::platformApplySoftware() { FilterEffect* in = inputEffect(0); Uint8ClampedArray* resultImage; if (m_preserveAlpha) resultImage = createUnmultipliedImageResult(); else resultImage = createPremultipliedImageResult(); if (!resultImage) return; IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<Uint8ClampedArray> srcPixelArray; if (m_preserveAlpha) srcPixelArray = in->asUnmultipliedImage(effectDrawingRect); else srcPixelArray = in->asPremultipliedImage(effectDrawingRect); IntSize paintSize = absolutePaintRect().size(); PaintingData paintingData; paintingData.srcPixelArray = srcPixelArray.get(); paintingData.dstPixelArray = resultImage; paintingData.width = paintSize.width(); paintingData.height = paintSize.height(); paintingData.bias = m_bias * 255; // Drawing fully covered pixels int clipRight = paintSize.width() - m_kernelSize.width(); int clipBottom = paintSize.height() - m_kernelSize.height(); if (clipRight < 0 || clipBottom < 0) { // Rare situation, not optimizied for speed setOuterPixels(paintingData, 0, 0, paintSize.width(), paintSize.height()); return; } int iterations = (absolutePaintRect().width() * absolutePaintRect().height()) / s_minimalRectDimension; if (!iterations) { setInteriorPixels(paintingData, clipRight, clipBottom, 0, clipBottom); return; } int stride = clipBottom / iterations; int chunkCount = (clipBottom + stride - 1) / stride; WorkQueue::concurrentApply(chunkCount, [&](size_t index) { int yStart = (stride * index); int yEnd = std::min<int>(stride * (index + 1), clipBottom); setInteriorPixels(paintingData, clipRight, clipBottom, yStart, yEnd); }); clipRight += m_targetOffset.x() + 1; clipBottom += m_targetOffset.y() + 1; if (m_targetOffset.y() > 0) setOuterPixels(paintingData, 0, 0, paintSize.width(), m_targetOffset.y()); if (clipBottom < paintSize.height()) setOuterPixels(paintingData, 0, clipBottom, paintSize.width(), paintSize.height()); if (m_targetOffset.x() > 0) setOuterPixels(paintingData, 0, m_targetOffset.y(), m_targetOffset.x(), clipBottom); if (clipRight < paintSize.width()) setOuterPixels(paintingData, clipRight, m_targetOffset.y(), paintSize.width(), clipBottom); }
void FEConvolveMatrix::apply() { if (hasResult()) return; FilterEffect* in = inputEffect(0); in->apply(); if (!in->hasResult()) return; ByteArray* resultImage; if (m_preserveAlpha) resultImage = createUnmultipliedImageResult(); else resultImage = createPremultipliedImageResult(); if (!resultImage) return; IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<ByteArray> srcPixelArray; if (m_preserveAlpha) srcPixelArray = in->asUnmultipliedImage(effectDrawingRect); else srcPixelArray = in->asPremultipliedImage(effectDrawingRect); IntSize paintSize = absolutePaintRect().size(); PaintingData paintingData; paintingData.srcPixelArray = srcPixelArray.get(); paintingData.dstPixelArray = resultImage; paintingData.width = paintSize.width(); paintingData.height = paintSize.height(); paintingData.bias = m_bias * 255; // Drawing fully covered pixels int clipRight = paintSize.width() - m_kernelSize.width(); int clipBottom = paintSize.height() - m_kernelSize.height(); if (clipRight >= 0 && clipBottom >= 0) { #if ENABLE(PARALLEL_JOBS) int optimalThreadNumber = (absolutePaintRect().width() * absolutePaintRect().height()) / s_minimalRectDimension; if (optimalThreadNumber > 1) { ParallelJobs<InteriorPixelParameters> parallelJobs(&WebCore::FEConvolveMatrix::setInteriorPixelsWorker, optimalThreadNumber); const int numOfThreads = parallelJobs.numberOfJobs(); const int heightPerThread = clipBottom / numOfThreads; int startY = 0; for (int job = 0; job < numOfThreads; ++job) { InteriorPixelParameters& param = parallelJobs.parameter(job); param.filter = this; param.paintingData = &paintingData; param.clipRight = clipRight; param.clipBottom = clipBottom; param.yStart = startY; if (job < numOfThreads - 1) { startY += heightPerThread; param.yEnd = startY - 1; } else param.yEnd = clipBottom; } parallelJobs.execute(); } else // Fallback to the default setInteriorPixels call. #endif setInteriorPixels(paintingData, clipRight, clipBottom, 0, clipBottom); clipRight += m_targetOffset.x() + 1; clipBottom += m_targetOffset.y() + 1; if (m_targetOffset.y() > 0) setOuterPixels(paintingData, 0, 0, paintSize.width(), m_targetOffset.y()); if (clipBottom < paintSize.height()) setOuterPixels(paintingData, 0, clipBottom, paintSize.width(), paintSize.height()); if (m_targetOffset.x() > 0) setOuterPixels(paintingData, 0, m_targetOffset.y(), m_targetOffset.x(), clipBottom); if (clipRight < paintSize.width()) setOuterPixels(paintingData, clipRight, m_targetOffset.y(), paintSize.width(), clipBottom); } else { // Rare situation, not optimizied for speed setOuterPixels(paintingData, 0, 0, paintSize.width(), paintSize.height()); } }
void FEComposite::applySoftware() { FilterEffect* in = inputEffect(0); FilterEffect* in2 = inputEffect(1); if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC) { Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult(); if (!dstPixelArray) return; IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<Uint8ClampedArray> srcPixelArray = in->asPremultipliedImage(effectADrawingRect); IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); in2->copyPremultipliedImage(dstPixelArray, effectBDrawingRect); platformArithmeticSoftware(srcPixelArray.get(), dstPixelArray, m_k1, m_k2, m_k3, m_k4); return; } ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; GraphicsContext* filterContext = resultImage->context(); ImageBuffer* imageBuffer = in->asImageBuffer(); ImageBuffer* imageBuffer2 = in2->asImageBuffer(); ASSERT(imageBuffer); ASSERT(imageBuffer2); switch (m_type) { case FECOMPOSITE_OPERATOR_OVER: filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect())); filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect())); break; case FECOMPOSITE_OPERATOR_IN: { // Applies only to the intersected region. IntRect destinationRect = in->absolutePaintRect(); destinationRect.intersect(in2->absolutePaintRect()); destinationRect.intersect(absolutePaintRect()); if (destinationRect.isEmpty()) break; FloatRect sourceRect(IntPoint(destinationRect.x() - in->absolutePaintRect().x(), destinationRect.y() - in->absolutePaintRect().y()), destinationRect.size()); FloatRect source2Rect(IntPoint(destinationRect.x() - in2->absolutePaintRect().x(), destinationRect.y() - in2->absolutePaintRect().y()), destinationRect.size()); destinationRect.move(-absolutePaintRect().x(), -absolutePaintRect().y()); filterContext->drawImageBuffer(imageBuffer2, destinationRect, &source2Rect); filterContext->drawImageBuffer(imageBuffer, destinationRect, &sourceRect, CompositeSourceIn); break; } case FECOMPOSITE_OPERATOR_OUT: filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect())); filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()), 0, CompositeDestinationOut); break; case FECOMPOSITE_OPERATOR_ATOP: filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect())); filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()), 0, CompositeSourceAtop); break; case FECOMPOSITE_OPERATOR_XOR: filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect())); filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()), 0, CompositeXOR); break; default: break; } }