inline void FEGaussianBlur::platformApplyGeneric(Uint8ClampedArray* srcPixelArray, Uint8ClampedArray* tmpPixelArray, unsigned kernelSizeX, unsigned kernelSizeY, IntSize& paintSize) { int stride = 4 * paintSize.width(); int dxLeft = 0; int dxRight = 0; int dyLeft = 0; int dyRight = 0; Uint8ClampedArray* src = srcPixelArray; Uint8ClampedArray* dst = tmpPixelArray; for (int i = 0; i < 3; ++i) { if (kernelSizeX) { kernelPosition(i, kernelSizeX, dxLeft, dxRight); boxBlur(src, dst, kernelSizeX, dxLeft, dxRight, 4, stride, paintSize.width(), paintSize.height(), isAlphaImage()); swap(src, dst); } if (kernelSizeY) { kernelPosition(i, kernelSizeY, dyLeft, dyRight); boxBlur(src, dst, kernelSizeY, dyLeft, dyRight, stride, 4, paintSize.height(), paintSize.width(), isAlphaImage()); swap(src, dst); } } // The final result should be stored in srcPixelArray. if (dst == srcPixelArray) { ASSERT(src->length() == dst->length()); memcpy(dst->data(), src->data(), src->length()); } }
void FilterEffect::forceValidPreMultipliedPixels() { // Must operate on pre-multiplied results; other formats cannot have invalid pixels. if (!m_premultipliedImageResult) return; Uint8ClampedArray* imageArray = m_premultipliedImageResult.get(); unsigned char* pixelData = imageArray->data(); int pixelArrayLength = imageArray->length(); // We must have four bytes per pixel, and complete pixels ASSERT(!(pixelArrayLength % 4)); #if HAVE(ARM_NEON_INTRINSICS) if (pixelArrayLength >= 64) { unsigned char* lastPixel = pixelData + (pixelArrayLength & ~0x3f); do { // Increments pixelData by 64. uint8x16x4_t sixteenPixels = vld4q_u8(pixelData); sixteenPixels.val[0] = vminq_u8(sixteenPixels.val[0], sixteenPixels.val[3]); sixteenPixels.val[1] = vminq_u8(sixteenPixels.val[1], sixteenPixels.val[3]); sixteenPixels.val[2] = vminq_u8(sixteenPixels.val[2], sixteenPixels.val[3]); vst4q_u8(pixelData, sixteenPixels); pixelData += 64; } while (pixelData < lastPixel); pixelArrayLength &= 0x3f; if (!pixelArrayLength) return; } #endif int numPixels = pixelArrayLength / 4; // Iterate over each pixel, checking alpha and adjusting color components if necessary while (--numPixels >= 0) { // Alpha is the 4th byte in a pixel unsigned char a = *(pixelData + 3); // Clamp each component to alpha, and increment the pixel location for (int i = 0; i < 3; ++i) { if (*pixelData > a) *pixelData = a; ++pixelData; } // Increment for alpha ++pixelData; } }
void 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]); } } }
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; }
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 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()); }