diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
commit | 40736c5763bf61337c8c14e16d8587db021a87d4 (patch) | |
tree | b17a9c00042ad89cb1308e2484491799aa14e9f8 /Source/WebCore/platform/graphics/filters | |
download | qtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz |
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
Diffstat (limited to 'Source/WebCore/platform/graphics/filters')
66 files changed, 10032 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/filters/CustomFilterMesh.cpp b/Source/WebCore/platform/graphics/filters/CustomFilterMesh.cpp new file mode 100644 index 000000000..40ec330d4 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/CustomFilterMesh.cpp @@ -0,0 +1,266 @@ +/* + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(CSS_SHADERS) && ENABLE(WEBGL) +#include "CustomFilterMesh.h" +#include "GraphicsContext3D.h" + +namespace WebCore { + +#ifndef NDEBUG +// Use "call 'WebCore::s_dumpCustomFilterMeshBuffers' = 1" in GDB to activate printing of the mesh buffers. +static bool s_dumpCustomFilterMeshBuffers = false; +#endif + +class MeshGenerator { +public: + // Lines and columns are the values passed in CSS. The result is vertex mesh that has 'rows' numbers of rows + // and 'columns' number of columns with a total of 'rows + 1' * 'columns + 1' vertices. + // MeshBox is the filtered area calculated defined using the border-box, padding-box, content-box or filter-box + // attributes. A value of (0, 0, 1, 1) will cover the entire output surface. + MeshGenerator(unsigned columns, unsigned rows, const FloatRect& meshBox, CustomFilterOperation::MeshType meshType) + : m_meshType(meshType) + , m_points(columns + 1, rows + 1) + , m_tiles(columns, rows) + , m_tileSizeInPixels(meshBox.width() / m_tiles.width(), meshBox.height() / m_tiles.height()) + , m_tileSizeInDeviceSpace(1.0f / m_tiles.width(), 1.0f / m_tiles.height()) + , m_meshBox(meshBox) + { + // Build the two buffers needed to draw triangles: + // * m_vertices has a number of float attributes that will be passed to the vertex shader + // for each computed vertex. This number is calculated in floatsPerVertex() based on the meshType. + // * m_indices is a buffer that will have 3 indices per triangle. Each index will point inside + // the m_vertices buffer. + m_vertices.reserveCapacity(verticesCount() * floatsPerVertex()); + m_indices.reserveCapacity(indicesCount()); + + // Based on the meshType there can be two types of meshes. + // * attached: each triangle uses vertices from the neighbor triangles. This is useful to save some GPU memory + // when there's no need to explode the tiles. + // * detached: each triangle has its own vertices. This means each triangle can be moved independently and a vec3 + // attribute is passed, so that each vertex can be uniquely identified. + if (m_meshType == CustomFilterOperation::ATTACHED) + generateAttachedMesh(); + else + generateDetachedMesh(); + +#ifndef NDEBUG + if (s_dumpCustomFilterMeshBuffers) + dumpBuffers(); +#endif + } + + const Vector<float>& vertices() const { return m_vertices; } + const Vector<uint16_t>& indices() const { return m_indices; } + + const IntSize& points() const { return m_points; } + unsigned pointsCount() const { return m_points.width() * m_points.height(); } + + const IntSize& tiles() const { return m_tiles; } + unsigned tilesCount() const { return m_tiles.width() * m_tiles.height(); } + + unsigned indicesCount() const + { + const unsigned trianglesPerTile = 2; + const unsigned indicesPerTriangle = 3; + return tilesCount() * trianglesPerTile * indicesPerTriangle; + } + + unsigned floatsPerVertex() const + { + static const unsigned AttachedMeshVertexSize = 4 + // vec4 a_position + 2 + // vec2 a_texCoord + 2; // vec2 a_meshCoord + + static const unsigned DetachedMeshVertexSize = AttachedMeshVertexSize + + 3; // vec3 a_triangleCoord + + return m_meshType == CustomFilterOperation::ATTACHED ? AttachedMeshVertexSize : DetachedMeshVertexSize; + } + + unsigned verticesCount() const + { + return m_meshType == CustomFilterOperation::ATTACHED ? pointsCount() : indicesCount(); + } + +private: + typedef void (MeshGenerator::*AddTriangleVertexFunction)(int quadX, int quadY, int triangleX, int triangleY, int triangle); + + template <AddTriangleVertexFunction addTriangleVertex> + void addTile(int quadX, int quadY) + { + ((*this).*(addTriangleVertex))(quadX, quadY, 0, 0, 1); + ((*this).*(addTriangleVertex))(quadX, quadY, 1, 0, 2); + ((*this).*(addTriangleVertex))(quadX, quadY, 1, 1, 3); + ((*this).*(addTriangleVertex))(quadX, quadY, 0, 0, 4); + ((*this).*(addTriangleVertex))(quadX, quadY, 1, 1, 5); + ((*this).*(addTriangleVertex))(quadX, quadY, 0, 1, 6); + } + + void addAttachedMeshIndex(int quadX, int quadY, int triangleX, int triangleY, int triangle) + { + UNUSED_PARAM(triangle); + m_indices.append((quadY + triangleY) * m_points.width() + (quadX + triangleX)); + } + + void generateAttachedMesh() + { + for (int j = 0; j < m_points.height(); ++j) { + for (int i = 0; i < m_points.width(); ++i) + addAttachedMeshVertexAttributes(i, j); + } + + for (int j = 0; j < m_tiles.height(); ++j) { + for (int i = 0; i < m_tiles.width(); ++i) + addTile<&MeshGenerator::addAttachedMeshIndex>(i, j); + } + } + + void addDetachedMeshVertexAndIndex(int quadX, int quadY, int triangleX, int triangleY, int triangle) + { + addDetachedMeshVertexAttributes(quadX, quadY, triangleX, triangleY, triangle); + m_indices.append(m_indices.size()); + } + + void generateDetachedMesh() + { + for (int j = 0; j < m_tiles.height(); ++j) { + for (int i = 0; i < m_tiles.width(); ++i) + addTile<&MeshGenerator::addDetachedMeshVertexAndIndex>(i, j); + } + } + + void addPositionAttribute(int quadX, int quadY) + { + // vec4 a_position + m_vertices.append(m_tileSizeInPixels.width() * quadX - 0.5f + m_meshBox.x()); + m_vertices.append(m_tileSizeInPixels.height() * quadY - 0.5f + m_meshBox.y()); + m_vertices.append(0.0f); // z + m_vertices.append(1.0f); + } + + void addTexCoordAttribute(int quadX, int quadY) + { + // vec2 a_texCoord + m_vertices.append(m_tileSizeInPixels.width() * quadX + m_meshBox.x()); + m_vertices.append(m_tileSizeInPixels.height() * quadY + m_meshBox.y()); + } + + void addMeshCoordAttribute(int quadX, int quadY) + { + // vec2 a_meshCoord + m_vertices.append(m_tileSizeInDeviceSpace.width() * quadX); + m_vertices.append(m_tileSizeInDeviceSpace.height() * quadY); + } + + void addTriangleCoordAttribute(int quadX, int quadY, int triangle) + { + // vec3 a_triangleCoord + m_vertices.append(quadX); + m_vertices.append(quadY); + m_vertices.append(triangle); + } + + void addAttachedMeshVertexAttributes(int quadX, int quadY) + { + addPositionAttribute(quadX, quadY); + addTexCoordAttribute(quadX, quadY); + addMeshCoordAttribute(quadX, quadY); + } + + void addDetachedMeshVertexAttributes(int quadX, int quadY, int triangleX, int triangleY, int triangle) + { + addAttachedMeshVertexAttributes(quadX + triangleX, quadY + triangleY); + addTriangleCoordAttribute(quadX, quadY, triangle); + } + +#ifndef NDEBUG + void dumpBuffers() const + { + printf("Mesh buffers: Points.width(): %d, Points.height(): %d meshBox: %f, %f, %f, %f, type: %s\n", + m_points.width(), m_points.height(), m_meshBox.x(), m_meshBox.y(), m_meshBox.width(), m_meshBox.height(), + (m_meshType == CustomFilterOperation::ATTACHED) ? "Attached" : "Detached"); + printf("---Vertex:\n\t"); + for (unsigned i = 0; i < m_vertices.size(); ++i) { + printf("%f ", m_vertices.at(i)); + if (!((i + 1) % floatsPerVertex())) + printf("\n\t"); + } + printf("\n---Indices: "); + for (unsigned i = 0; i < m_indices.size(); ++i) + printf("%d ", m_indices.at(i)); + printf("\n"); + } +#endif + +private: + Vector<float> m_vertices; + Vector<uint16_t> m_indices; + + CustomFilterOperation::MeshType m_meshType; + IntSize m_points; + IntSize m_tiles; + FloatSize m_tileSizeInPixels; + FloatSize m_tileSizeInDeviceSpace; + FloatRect m_meshBox; +}; + +CustomFilterMesh::CustomFilterMesh(GraphicsContext3D* context, unsigned columns, unsigned rows, + const FloatRect& meshBox, CustomFilterOperation::MeshType meshType) + : m_context(context) + , m_verticesBufferObject(0) + , m_elementsBufferObject(0) + , m_meshBox(meshBox) + , m_meshType(meshType) +{ + MeshGenerator generator(columns, rows, meshBox, meshType); + m_indicesCount = generator.indicesCount(); + m_bytesPerVertex = generator.floatsPerVertex() * sizeof(float); + + m_verticesBufferObject = m_context->createBuffer(); + m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_verticesBufferObject); + m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, generator.vertices().size() * sizeof(float), generator.vertices().data(), GraphicsContext3D::STATIC_DRAW); + + m_elementsBufferObject = m_context->createBuffer(); + m_context->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, m_elementsBufferObject); + m_context->bufferData(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, generator.indices().size() * sizeof(uint16_t), generator.indices().data(), GraphicsContext3D::STATIC_DRAW); +} + +CustomFilterMesh::~CustomFilterMesh() +{ + m_context->deleteBuffer(m_verticesBufferObject); + m_context->deleteBuffer(m_elementsBufferObject); +} + +} // namespace WebCore + +#endif // ENABLE(CSS_SHADERS) && ENABLE(WEBGL) + diff --git a/Source/WebCore/platform/graphics/filters/CustomFilterMesh.h b/Source/WebCore/platform/graphics/filters/CustomFilterMesh.h new file mode 100644 index 000000000..b557d3eaf --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/CustomFilterMesh.h @@ -0,0 +1,80 @@ +/* + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CustomFilterMesh_h +#define CustomFilterMesh_h + +#if ENABLE(CSS_SHADERS) && ENABLE(WEBGL) + +#include "CustomFilterOperation.h" +#include "FloatRect.h" +#include "GraphicsTypes3D.h" +#include <wtf/RefCounted.h> + +namespace WebCore { + +class GraphicsContext3D; + +class CustomFilterMesh : public RefCounted<CustomFilterMesh> { +public: + static PassRefPtr<CustomFilterMesh> create(GraphicsContext3D* context, unsigned cols, unsigned rows, const FloatRect& meshBox, CustomFilterOperation::MeshType meshType) + { + return adoptRef(new CustomFilterMesh(context, cols, rows, meshBox, meshType)); + } + ~CustomFilterMesh(); + + Platform3DObject verticesBufferObject() const { return m_verticesBufferObject; } + unsigned bytesPerVertex() const { return m_bytesPerVertex; } + + Platform3DObject elementsBufferObject() const { return m_elementsBufferObject; } + unsigned indicesCount() const { return m_indicesCount; } + + const FloatRect& meshBox() const { return m_meshBox; } + CustomFilterOperation::MeshType meshType() const { return m_meshType; } + +private: + CustomFilterMesh(GraphicsContext3D*, unsigned cols, unsigned rows, const FloatRect& meshBox, CustomFilterOperation::MeshType); + + GraphicsContext3D* m_context; + + Platform3DObject m_verticesBufferObject; + unsigned m_bytesPerVertex; + + Platform3DObject m_elementsBufferObject; + unsigned m_indicesCount; + + FloatRect m_meshBox; + CustomFilterOperation::MeshType m_meshType; +}; + +} // namespace WebCore + +#endif // ENABLE(CSS_SHADERS) && ENABLE(WEBGL) + +#endif // CustomFilterMesh_h diff --git a/Source/WebCore/platform/graphics/filters/CustomFilterShader.cpp b/Source/WebCore/platform/graphics/filters/CustomFilterShader.cpp new file mode 100644 index 000000000..6df78de97 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/CustomFilterShader.cpp @@ -0,0 +1,171 @@ +/* + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(CSS_SHADERS) && ENABLE(WEBGL) +#include "CustomFilterShader.h" +#include "GraphicsContext3D.h" + +namespace WebCore { + +#define SHADER(Src) (#Src) + +String CustomFilterShader::defaultVertexShaderString() +{ + DEFINE_STATIC_LOCAL(String, vertexShaderString, SHADER( + precision mediump float; + attribute vec4 a_position; + attribute vec2 a_texCoord; + uniform mat4 u_projectionMatrix; + varying vec2 v_texCoord; + void main() + { + gl_Position = u_projectionMatrix * a_position; + v_texCoord = a_texCoord; + } + )); + return vertexShaderString; +} + +String CustomFilterShader::defaultFragmentShaderString() +{ + DEFINE_STATIC_LOCAL(String, fragmentShaderString, SHADER( + precision mediump float; + varying vec2 v_texCoord; + uniform sampler2D s_texture; + void main() + { + gl_FragColor = texture2D(s_texture, v_texCoord); + } + )); + return fragmentShaderString; +} + +CustomFilterShader::CustomFilterShader(GraphicsContext3D* context, const String& vertexShaderString, const String& fragmentShaderString) + : m_context(context) + , m_vertexShaderString(!vertexShaderString.isNull() ? vertexShaderString : defaultVertexShaderString()) + , m_fragmentShaderString(!fragmentShaderString.isNull() ? fragmentShaderString : defaultFragmentShaderString()) + , m_program(0) + , m_positionAttribLocation(-1) + , m_texAttribLocation(-1) + , m_meshAttribLocation(-1) + , m_triangleAttribLocation(-1) + , m_meshBoxLocation(-1) + , m_projectionMatrixLocation(-1) + , m_tileSizeLocation(-1) + , m_meshSizeLocation(-1) + , m_samplerLocation(-1) + , m_samplerSizeLocation(-1) + , m_contentSamplerLocation(-1) + , m_isInitialized(false) +{ + Platform3DObject vertexShader = compileShader(GraphicsContext3D::VERTEX_SHADER, m_vertexShaderString); + if (!vertexShader) + return; + + Platform3DObject fragmentShader = compileShader(GraphicsContext3D::FRAGMENT_SHADER, m_fragmentShaderString); + if (!fragmentShader) { + m_context->deleteShader(vertexShader); + return; + } + + m_program = linkProgram(vertexShader, fragmentShader); + + m_context->deleteShader(vertexShader); + m_context->deleteShader(fragmentShader); + + if (!m_program) + return; + + initializeParameterLocations(); + + m_isInitialized = true; +} + +Platform3DObject CustomFilterShader::compileShader(GC3Denum shaderType, const String& shaderString) +{ + Platform3DObject shader = m_context->createShader(shaderType); + m_context->shaderSource(shader, shaderString); + m_context->compileShader(shader); + + int compiled = 0; + m_context->getShaderiv(shader, GraphicsContext3D::COMPILE_STATUS, &compiled); + if (!compiled) { + // FIXME: This is an invalid shader. Throw some errors. + // https://bugs.webkit.org/show_bug.cgi?id=74416 + m_context->deleteShader(shader); + return 0; + } + + return shader; +} + +Platform3DObject CustomFilterShader::linkProgram(Platform3DObject vertexShader, Platform3DObject fragmentShader) +{ + Platform3DObject program = m_context->createProgram(); + m_context->attachShader(program, vertexShader); + m_context->attachShader(program, fragmentShader); + m_context->linkProgram(program); + + int linked = 0; + m_context->getProgramiv(program, GraphicsContext3D::LINK_STATUS, &linked); + if (!linked) { + // FIXME: Invalid vertex/fragment shader combination. Throw some errors here. + // https://bugs.webkit.org/show_bug.cgi?id=74416 + m_context->deleteProgram(program); + return 0; + } + + return program; +} + +void CustomFilterShader::initializeParameterLocations() +{ + m_positionAttribLocation = m_context->getAttribLocation(m_program, "a_position"); + m_texAttribLocation = m_context->getAttribLocation(m_program, "a_texCoord"); + m_meshAttribLocation = m_context->getAttribLocation(m_program, "a_meshCoord"); + m_triangleAttribLocation = m_context->getAttribLocation(m_program, "a_triangleCoord"); + m_meshBoxLocation = m_context->getUniformLocation(m_program, "u_meshBox"); + m_tileSizeLocation = m_context->getUniformLocation(m_program, "u_tileSize"); + m_meshSizeLocation = m_context->getUniformLocation(m_program, "u_meshSize"); + m_projectionMatrixLocation = m_context->getUniformLocation(m_program, "u_projectionMatrix"); + m_samplerLocation = m_context->getUniformLocation(m_program, "s_texture"); + m_samplerSizeLocation = m_context->getUniformLocation(m_program, "s_textureSize"); + m_contentSamplerLocation = m_context->getUniformLocation(m_program, "s_contentTexture"); +} + +CustomFilterShader::~CustomFilterShader() +{ + if (m_program) + m_context->deleteProgram(m_program); +} + +} // namespace WebCore +#endif // ENABLE(CSS_SHADERS) && ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/filters/CustomFilterShader.h b/Source/WebCore/platform/graphics/filters/CustomFilterShader.h new file mode 100644 index 000000000..90602cb1e --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/CustomFilterShader.h @@ -0,0 +1,107 @@ +/* + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CustomFilterShader_h +#define CustomFilterShader_h + +#if ENABLE(CSS_SHADERS) && ENABLE(WEBGL) + +#include "GraphicsTypes3D.h" +#include <wtf/RefCounted.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class GraphicsContext3D; + +class CustomFilterShader: public RefCounted<CustomFilterShader> { +public: + static PassRefPtr<CustomFilterShader> create(GraphicsContext3D* context, const String& vertexShader, const String& fragmentShader) + { + return adoptRef(new CustomFilterShader(context, vertexShader, fragmentShader)); + } + + ~CustomFilterShader(); + + String vertexShaderString() const { return m_vertexShaderString; } + String fragmentShaderString() const { return m_fragmentShaderString; } + + int positionAttribLocation() const { return m_positionAttribLocation; } + int texAttribLocation() const { return m_texAttribLocation; } + int meshAttribLocation() const { return m_meshAttribLocation; } + int triangleAttribLocation() const { return m_triangleAttribLocation; } + int meshBoxLocation() const { return m_meshBoxLocation; } + int projectionMatrixLocation() const { return m_projectionMatrixLocation; } + int tileSizeLocation() const { return m_tileSizeLocation; } + int meshSizeLocation() const { return m_meshSizeLocation; } + int samplerLocation() const { return m_samplerLocation; } + int contentSamplerLocation() const { return m_contentSamplerLocation; } + int samplerSizeLocation() const { return m_samplerSizeLocation; } + + bool isInitialized() const { return m_isInitialized; } + + Platform3DObject program() const { return m_program; } + +private: + CustomFilterShader(GraphicsContext3D*, const String& vertexShader, const String& fragmentShader); + + Platform3DObject compileShader(GC3Denum shaderType, const String& shaderString); + Platform3DObject linkProgram(Platform3DObject vertexShader, Platform3DObject fragmentShader); + void initializeParameterLocations(); + + static String defaultVertexShaderString(); + static String defaultFragmentShaderString(); + + RefPtr<GraphicsContext3D> m_context; + + String m_vertexShaderString; + String m_fragmentShaderString; + + Platform3DObject m_program; + + int m_positionAttribLocation; + int m_texAttribLocation; + int m_meshAttribLocation; + int m_triangleAttribLocation; + int m_meshBoxLocation; + int m_projectionMatrixLocation; + int m_tileSizeLocation; + int m_meshSizeLocation; + int m_samplerLocation; + int m_samplerSizeLocation; + int m_contentSamplerLocation; + + bool m_isInitialized; +}; + +} + +#endif // ENABLE(CSS_SHADERS) && ENABLE(WEBGL) + +#endif diff --git a/Source/WebCore/platform/graphics/filters/DistantLightSource.cpp b/Source/WebCore/platform/graphics/filters/DistantLightSource.cpp new file mode 100644 index 000000000..4c3b49b3b --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/DistantLightSource.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2010 Zoltan Herczeg <zherczeg@webkit.org> + * Copyright (C) 2011 University of Szeged + * Copyright (C) 2011 Renata Hodovan <reni@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "DistantLightSource.h" + +#include "RenderTreeAsText.h" + +namespace WebCore { + +void DistantLightSource::initPaintingData(PaintingData& paintingData) +{ + float azimuth = deg2rad(m_azimuth); + float elevation = deg2rad(m_elevation); + paintingData.lightVector.setX(cosf(azimuth) * cosf(elevation)); + paintingData.lightVector.setY(sinf(azimuth) * cosf(elevation)); + paintingData.lightVector.setZ(sinf(elevation)); + paintingData.lightVectorLength = 1; +} + +void DistantLightSource::updatePaintingData(PaintingData&, int, int, float) +{ +} + +bool DistantLightSource::setAzimuth(float azimuth) +{ + if (m_azimuth == azimuth) + return false; + m_azimuth = azimuth; + return true; +} + +bool DistantLightSource::setElevation(float elevation) +{ + if (m_elevation == elevation) + return false; + m_elevation = elevation; + return true; +} + +TextStream& DistantLightSource::externalRepresentation(TextStream& ts) const +{ + ts << "[type=DISTANT-LIGHT] "; + ts << "[azimuth=\"" << azimuth() << "\"]"; + ts << "[elevation=\"" << elevation() << "\"]"; + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/DistantLightSource.h b/Source/WebCore/platform/graphics/filters/DistantLightSource.h new file mode 100644 index 000000000..1e19c62bd --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/DistantLightSource.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef DistantLightSource_h +#define DistantLightSource_h + +#if ENABLE(FILTERS) +#include "LightSource.h" + +namespace WebCore { + +class DistantLightSource : public LightSource { +public: + static PassRefPtr<DistantLightSource> create(float azimuth, float elevation) + { + return adoptRef(new DistantLightSource(azimuth, elevation)); + } + + float azimuth() const { return m_azimuth; } + bool setAzimuth(float); + float elevation() const { return m_elevation; } + bool setElevation(float); + + virtual void initPaintingData(PaintingData&); + virtual void updatePaintingData(PaintingData&, int x, int y, float z); + + virtual TextStream& externalRepresentation(TextStream&) const; + +private: + DistantLightSource(float azimuth, float elevation) + : LightSource(LS_DISTANT) + , m_azimuth(azimuth) + , m_elevation(elevation) + { + } + + float m_azimuth; + float m_elevation; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // DistantLightSource_h diff --git a/Source/WebCore/platform/graphics/filters/FEBlend.cpp b/Source/WebCore/platform/graphics/filters/FEBlend.cpp new file mode 100644 index 000000000..530636da9 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEBlend.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEBlend.h" + +#include "Filter.h" +#include "FloatPoint.h" +#include "GraphicsContext.h" +#include "RenderTreeAsText.h" +#include "TextStream.h" + +#include <wtf/ByteArray.h> + +typedef unsigned char (*BlendType)(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB); + +namespace WebCore { + +FEBlend::FEBlend(Filter* filter, BlendModeType mode) + : FilterEffect(filter) + , m_mode(mode) +{ +} + +PassRefPtr<FEBlend> FEBlend::create(Filter* filter, BlendModeType mode) +{ + return adoptRef(new FEBlend(filter, mode)); +} + +BlendModeType FEBlend::blendMode() const +{ + return m_mode; +} + +bool FEBlend::setBlendMode(BlendModeType mode) +{ + if (m_mode == mode) + return false; + m_mode = mode; + return true; +} + +static inline unsigned char normal(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char) +{ + return (((255 - alphaA) * colorB + colorA * 255) / 255); +} + +static inline unsigned char multiply(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB) +{ + return (((255 - alphaA) * colorB + (255 - alphaB + colorB) * colorA) / 255); +} + +static inline unsigned char screen(unsigned char colorA, unsigned char colorB, unsigned char, unsigned char) +{ + return (((colorB + colorA) * 255 - colorA * colorB) / 255); +} + +static inline unsigned char darken(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB) +{ + return ((std::min((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)) / 255); +} + +static inline unsigned char lighten(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB) +{ + return ((std::max((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)) / 255); +} + +void FEBlend::platformApplySoftware() +{ + FilterEffect* in = inputEffect(0); + FilterEffect* in2 = inputEffect(1); + + 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); + + 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; + + 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 FEBlend::dump() +{ +} + +static TextStream& operator<<(TextStream& ts, const BlendModeType& type) +{ + switch (type) { + case FEBLEND_MODE_UNKNOWN: + ts << "UNKNOWN"; + break; + case FEBLEND_MODE_NORMAL: + ts << "NORMAL"; + break; + case FEBLEND_MODE_MULTIPLY: + ts << "MULTIPLY"; + break; + case FEBLEND_MODE_SCREEN: + ts << "SCREEN"; + break; + case FEBLEND_MODE_DARKEN: + ts << "DARKEN"; + break; + case FEBLEND_MODE_LIGHTEN: + ts << "LIGHTEN"; + break; + } + return ts; +} + +TextStream& FEBlend::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feBlend"; + FilterEffect::externalRepresentation(ts); + ts << " mode=\"" << m_mode << "\"]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + inputEffect(1)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FEBlend.h b/Source/WebCore/platform/graphics/filters/FEBlend.h new file mode 100644 index 000000000..68cd1d37a --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEBlend.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEBlend_h +#define FEBlend_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" + +#include "Filter.h" + +namespace WebCore { + +enum BlendModeType { + FEBLEND_MODE_UNKNOWN = 0, + FEBLEND_MODE_NORMAL = 1, + FEBLEND_MODE_MULTIPLY = 2, + FEBLEND_MODE_SCREEN = 3, + FEBLEND_MODE_DARKEN = 4, + FEBLEND_MODE_LIGHTEN = 5 +}; + +class FEBlend : public FilterEffect { +public: + static PassRefPtr<FEBlend> create(Filter*, BlendModeType); + + BlendModeType blendMode() const; + bool setBlendMode(BlendModeType); + + virtual void platformApplySoftware(); + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEBlend(Filter*, BlendModeType); + + BlendModeType m_mode; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEBlend_h diff --git a/Source/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/Source/WebCore/platform/graphics/filters/FEColorMatrix.cpp new file mode 100644 index 000000000..ed6cb90dc --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEColorMatrix.cpp @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEColorMatrix.h" + +#include "Filter.h" +#include "GraphicsContext.h" +#include "RenderTreeAsText.h" +#include "TextStream.h" + +#include <wtf/ByteArray.h> +#include <wtf/MathExtras.h> + +namespace WebCore { + +FEColorMatrix::FEColorMatrix(Filter* filter, ColorMatrixType type, const Vector<float>& values) + : FilterEffect(filter) + , m_type(type) + , m_values(values) +{ +} + +PassRefPtr<FEColorMatrix> FEColorMatrix::create(Filter* filter, ColorMatrixType type, const Vector<float>& values) +{ + return adoptRef(new FEColorMatrix(filter, type, values)); +} + +ColorMatrixType FEColorMatrix::type() const +{ + return m_type; +} + +bool FEColorMatrix::setType(ColorMatrixType type) +{ + if (m_type == type) + return false; + m_type = type; + return true; +} + +const Vector<float>& FEColorMatrix::values() const +{ + return m_values; +} + +bool FEColorMatrix::setValues(const Vector<float> &values) +{ + if (m_values == values) + return false; + m_values = values; + return true; +} + +inline void matrix(double& red, double& green, double& blue, double& alpha, const Vector<float>& values) +{ + double r = values[0] * red + values[1] * green + values[2] * blue + values[3] * alpha + values[4] * 255; + double g = values[5] * red + values[6] * green + values[7] * blue + values[8] * alpha + values[9] * 255; + double b = values[10] * red + values[11] * green + values[12] * blue + values[13] * alpha + values[14] * 255; + double a = values[15] * red + values[16] * green + values[17] * blue + values[18] * alpha + values[19] * 255; + + red = r; + green = g; + blue = b; + alpha = a; +} + +inline void saturate(double& red, double& green, double& blue, const float& s) +{ + double r = (0.213 + 0.787 * s) * red + (0.715 - 0.715 * s) * green + (0.072 - 0.072 * s) * blue; + double g = (0.213 - 0.213 * s) * red + (0.715 + 0.285 * s) * green + (0.072 - 0.072 * s) * blue; + double b = (0.213 - 0.213 * s) * red + (0.715 - 0.715 * s) * green + (0.072 + 0.928 * s) * blue; + + red = r; + green = g; + blue = b; +} + +inline void huerotate(double& red, double& green, double& blue, const float& hue) +{ + double cosHue = cos(hue * piDouble / 180); + double sinHue = sin(hue * piDouble / 180); + double r = red * (0.213 + cosHue * 0.787 - sinHue * 0.213) + + green * (0.715 - cosHue * 0.715 - sinHue * 0.715) + + blue * (0.072 - cosHue * 0.072 + sinHue * 0.928); + double g = red * (0.213 - cosHue * 0.213 + sinHue * 0.143) + + green * (0.715 + cosHue * 0.285 + sinHue * 0.140) + + blue * (0.072 - cosHue * 0.072 - sinHue * 0.283); + double b = red * (0.213 - cosHue * 0.213 - sinHue * 0.787) + + green * (0.715 - cosHue * 0.715 + sinHue * 0.715) + + blue * (0.072 + cosHue * 0.928 + sinHue * 0.072); + + red = r; + green = g; + blue = b; +} + +inline void luminance(double& red, double& green, double& blue, double& alpha) +{ + alpha = 0.2125 * red + 0.7154 * green + 0.0721 * blue; + red = 0; + green = 0; + blue = 0; +} + +template<ColorMatrixType filterType> +void effectType(ByteArray* pixelArray, const Vector<float>& values) +{ + unsigned pixelArrayLength = pixelArray->length(); + for (unsigned pixelByteOffset = 0; pixelByteOffset < pixelArrayLength; pixelByteOffset += 4) { + double red = pixelArray->get(pixelByteOffset); + double green = pixelArray->get(pixelByteOffset + 1); + double blue = pixelArray->get(pixelByteOffset + 2); + double alpha = pixelArray->get(pixelByteOffset + 3); + + switch (filterType) { + case FECOLORMATRIX_TYPE_MATRIX: + matrix(red, green, blue, alpha, values); + break; + case FECOLORMATRIX_TYPE_SATURATE: + saturate(red, green, blue, values[0]); + break; + case FECOLORMATRIX_TYPE_HUEROTATE: + huerotate(red, green, blue, values[0]); + break; + case FECOLORMATRIX_TYPE_LUMINANCETOALPHA: + luminance(red, green, blue, alpha); + break; + } + + pixelArray->set(pixelByteOffset, red); + pixelArray->set(pixelByteOffset + 1, green); + pixelArray->set(pixelByteOffset + 2, blue); + pixelArray->set(pixelByteOffset + 3, alpha); + } +} + +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<ByteArray> 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->putUnmultipliedImageData(pixelArray.get(), imageRect.size(), imageRect, IntPoint()); +} + +void FEColorMatrix::dump() +{ +} + +static TextStream& operator<<(TextStream& ts, const ColorMatrixType& type) +{ + switch (type) { + case FECOLORMATRIX_TYPE_UNKNOWN: + ts << "UNKNOWN"; + break; + case FECOLORMATRIX_TYPE_MATRIX: + ts << "MATRIX"; + break; + case FECOLORMATRIX_TYPE_SATURATE: + ts << "SATURATE"; + break; + case FECOLORMATRIX_TYPE_HUEROTATE: + ts << "HUEROTATE"; + break; + case FECOLORMATRIX_TYPE_LUMINANCETOALPHA: + ts << "LUMINANCETOALPHA"; + break; + } + return ts; +} + +TextStream& FEColorMatrix::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feColorMatrix"; + FilterEffect::externalRepresentation(ts); + ts << " type=\"" << m_type << "\""; + if (!m_values.isEmpty()) { + ts << " values=\""; + Vector<float>::const_iterator ptr = m_values.begin(); + const Vector<float>::const_iterator end = m_values.end(); + while (ptr < end) { + ts << *ptr; + ++ptr; + if (ptr < end) + ts << " "; + } + ts << "\""; + } + ts << "]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FEColorMatrix.h b/Source/WebCore/platform/graphics/filters/FEColorMatrix.h new file mode 100644 index 000000000..d03b6d376 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEColorMatrix.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEColorMatrix_h +#define FEColorMatrix_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" + +#include "Filter.h" +#include <wtf/Vector.h> + +namespace WebCore { + +enum ColorMatrixType { + FECOLORMATRIX_TYPE_UNKNOWN = 0, + FECOLORMATRIX_TYPE_MATRIX = 1, + FECOLORMATRIX_TYPE_SATURATE = 2, + FECOLORMATRIX_TYPE_HUEROTATE = 3, + FECOLORMATRIX_TYPE_LUMINANCETOALPHA = 4 +}; + +class FEColorMatrix : public FilterEffect { +public: + static PassRefPtr<FEColorMatrix> create(Filter*, ColorMatrixType, const Vector<float>&); + + ColorMatrixType type() const; + bool setType(ColorMatrixType); + + const Vector<float>& values() const; + bool setValues(const Vector<float>&); + + virtual void platformApplySoftware(); + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEColorMatrix(Filter*, ColorMatrixType, const Vector<float>&); + + ColorMatrixType m_type; + Vector<float> m_values; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEColorMatrix_h diff --git a/Source/WebCore/platform/graphics/filters/FEComponentTransfer.cpp b/Source/WebCore/platform/graphics/filters/FEComponentTransfer.cpp new file mode 100644 index 000000000..8db62dc4d --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEComponentTransfer.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEComponentTransfer.h" + +#include "Filter.h" +#include "GraphicsContext.h" +#include "RenderTreeAsText.h" +#include "TextStream.h" + +#include <wtf/ByteArray.h> +#include <wtf/MathExtras.h> +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +typedef void (*TransferType)(unsigned char*, const ComponentTransferFunction&); + +FEComponentTransfer::FEComponentTransfer(Filter* filter, const ComponentTransferFunction& redFunc, const ComponentTransferFunction& greenFunc, + const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc) + : FilterEffect(filter) + , m_redFunc(redFunc) + , m_greenFunc(greenFunc) + , m_blueFunc(blueFunc) + , m_alphaFunc(alphaFunc) +{ +} + +PassRefPtr<FEComponentTransfer> FEComponentTransfer::create(Filter* filter, const ComponentTransferFunction& redFunc, + const ComponentTransferFunction& greenFunc, const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc) +{ + return adoptRef(new FEComponentTransfer(filter, redFunc, greenFunc, blueFunc, alphaFunc)); +} + +ComponentTransferFunction FEComponentTransfer::redFunction() const +{ + return m_redFunc; +} + +void FEComponentTransfer::setRedFunction(const ComponentTransferFunction& func) +{ + m_redFunc = func; +} + +ComponentTransferFunction FEComponentTransfer::greenFunction() const +{ + return m_greenFunc; +} + +void FEComponentTransfer::setGreenFunction(const ComponentTransferFunction& func) +{ + m_greenFunc = func; +} + +ComponentTransferFunction FEComponentTransfer::blueFunction() const +{ + return m_blueFunc; +} + +void FEComponentTransfer::setBlueFunction(const ComponentTransferFunction& func) +{ + m_blueFunc = func; +} + +ComponentTransferFunction FEComponentTransfer::alphaFunction() const +{ + return m_alphaFunc; +} + +void FEComponentTransfer::setAlphaFunction(const ComponentTransferFunction& func) +{ + m_alphaFunc = func; +} + +static void identity(unsigned char*, const ComponentTransferFunction&) +{ +} + +static void table(unsigned char* values, const ComponentTransferFunction& transferFunction) +{ + const Vector<float>& tableValues = transferFunction.tableValues; + unsigned n = tableValues.size(); + if (n < 1) + return; + for (unsigned i = 0; i < 256; ++i) { + double c = i / 255.0; + unsigned k = static_cast<unsigned>(c * (n - 1)); + double v1 = tableValues[k]; + double v2 = tableValues[std::min((k + 1), (n - 1))]; + double val = 255.0 * (v1 + (c * (n - 1) - k) * (v2 - v1)); + val = std::max(0.0, std::min(255.0, val)); + values[i] = static_cast<unsigned char>(val); + } +} + +static void discrete(unsigned char* values, const ComponentTransferFunction& transferFunction) +{ + const Vector<float>& tableValues = transferFunction.tableValues; + unsigned n = tableValues.size(); + if (n < 1) + return; + for (unsigned i = 0; i < 256; ++i) { + unsigned k = static_cast<unsigned>((i * n) / 255.0); + k = std::min(k, n - 1); + double val = 255 * tableValues[k]; + val = std::max(0.0, std::min(255.0, val)); + values[i] = static_cast<unsigned char>(val); + } +} + +static void linear(unsigned char* values, const ComponentTransferFunction& transferFunction) +{ + for (unsigned i = 0; i < 256; ++i) { + double val = transferFunction.slope * i + 255 * transferFunction.intercept; + val = std::max(0.0, std::min(255.0, val)); + values[i] = static_cast<unsigned char>(val); + } +} + +static void gamma(unsigned char* values, const ComponentTransferFunction& transferFunction) +{ + for (unsigned i = 0; i < 256; ++i) { + double exponent = transferFunction.exponent; // RCVT doesn't like passing a double and a float to pow, so promote this to double + double val = 255.0 * (transferFunction.amplitude * pow((i / 255.0), exponent) + transferFunction.offset); + val = std::max(0.0, std::min(255.0, val)); + values[i] = static_cast<unsigned char>(val); + } +} + +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 FEComponentTransfer::dump() +{ +} + +static TextStream& operator<<(TextStream& ts, const ComponentTransferType& type) +{ + switch (type) { + case FECOMPONENTTRANSFER_TYPE_UNKNOWN: + ts << "UNKNOWN"; + break; + case FECOMPONENTTRANSFER_TYPE_IDENTITY: + ts << "IDENTITY"; + break; + case FECOMPONENTTRANSFER_TYPE_TABLE: + ts << "TABLE"; + break; + case FECOMPONENTTRANSFER_TYPE_DISCRETE: + ts << "DISCRETE"; + break; + case FECOMPONENTTRANSFER_TYPE_LINEAR: + ts << "LINEAR"; + break; + case FECOMPONENTTRANSFER_TYPE_GAMMA: + ts << "GAMMA"; + break; + } + return ts; +} + +static TextStream& operator<<(TextStream& ts, const ComponentTransferFunction& function) +{ + ts << "type=\"" << function.type + << "\" slope=\"" << function.slope + << "\" intercept=\"" << function.intercept + << "\" amplitude=\"" << function.amplitude + << "\" exponent=\"" << function.exponent + << "\" offset=\"" << function.offset << "\""; + return ts; +} + +TextStream& FEComponentTransfer::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feComponentTransfer"; + FilterEffect::externalRepresentation(ts); + ts << " \n"; + writeIndent(ts, indent + 2); + ts << "{red: " << m_redFunc << "}\n"; + writeIndent(ts, indent + 2); + ts << "{green: " << m_greenFunc << "}\n"; + writeIndent(ts, indent + 2); + ts << "{blue: " << m_blueFunc << "}\n"; + writeIndent(ts, indent + 2); + ts << "{alpha: " << m_alphaFunc << "}]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FEComponentTransfer.h b/Source/WebCore/platform/graphics/filters/FEComponentTransfer.h new file mode 100644 index 000000000..d461deff0 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEComponentTransfer.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEComponentTransfer_h +#define FEComponentTransfer_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" + +#include "Filter.h" +#include <wtf/Vector.h> + +namespace WebCore { + +enum ComponentTransferType { + FECOMPONENTTRANSFER_TYPE_UNKNOWN = 0, + FECOMPONENTTRANSFER_TYPE_IDENTITY = 1, + FECOMPONENTTRANSFER_TYPE_TABLE = 2, + FECOMPONENTTRANSFER_TYPE_DISCRETE = 3, + FECOMPONENTTRANSFER_TYPE_LINEAR = 4, + FECOMPONENTTRANSFER_TYPE_GAMMA = 5 +}; + +struct ComponentTransferFunction { + ComponentTransferFunction() + : type(FECOMPONENTTRANSFER_TYPE_UNKNOWN) + , slope(0) + , intercept(0) + , amplitude(0) + , exponent(0) + , offset(0) + { + } + + ComponentTransferType type; + + float slope; + float intercept; + float amplitude; + float exponent; + float offset; + + Vector<float> tableValues; +}; + +class FEComponentTransfer : public FilterEffect { +public: + static PassRefPtr<FEComponentTransfer> create(Filter*, const ComponentTransferFunction& redFunc, const ComponentTransferFunction& greenFunc, + const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc); + + ComponentTransferFunction redFunction() const; + void setRedFunction(const ComponentTransferFunction&); + + ComponentTransferFunction greenFunction() const; + void setGreenFunction(const ComponentTransferFunction&); + + ComponentTransferFunction blueFunction() const; + void setBlueFunction(const ComponentTransferFunction&); + + ComponentTransferFunction alphaFunction() const; + void setAlphaFunction(const ComponentTransferFunction&); + + virtual void platformApplySoftware(); + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEComponentTransfer(Filter*, const ComponentTransferFunction& redFunc, const ComponentTransferFunction& greenFunc, + const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc); + + ComponentTransferFunction m_redFunc; + ComponentTransferFunction m_greenFunc; + ComponentTransferFunction m_blueFunc; + ComponentTransferFunction m_alphaFunc; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEComponentTransfer_h diff --git a/Source/WebCore/platform/graphics/filters/FEComposite.cpp b/Source/WebCore/platform/graphics/filters/FEComposite.cpp new file mode 100644 index 000000000..c64d02c8a --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEComposite.cpp @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEComposite.h" + +#include "FECompositeArithmeticNEON.h" +#include "Filter.h" +#include "GraphicsContext.h" +#include "RenderTreeAsText.h" +#include "TextStream.h" + +#include <wtf/ByteArray.h> + +namespace WebCore { + +FEComposite::FEComposite(Filter* filter, const CompositeOperationType& type, float k1, float k2, float k3, float k4) + : FilterEffect(filter) + , m_type(type) + , m_k1(k1) + , m_k2(k2) + , m_k3(k3) + , m_k4(k4) +{ +} + +PassRefPtr<FEComposite> FEComposite::create(Filter* filter, const CompositeOperationType& type, float k1, float k2, float k3, float k4) +{ + return adoptRef(new FEComposite(filter, type, k1, k2, k3, k4)); +} + +CompositeOperationType FEComposite::operation() const +{ + return m_type; +} + +bool FEComposite::setOperation(CompositeOperationType type) +{ + if (m_type == type) + return false; + m_type = type; + return true; +} + +float FEComposite::k1() const +{ + return m_k1; +} + +bool FEComposite::setK1(float k1) +{ + if (m_k1 == k1) + return false; + m_k1 = k1; + return true; +} + +float FEComposite::k2() const +{ + return m_k2; +} + +bool FEComposite::setK2(float k2) +{ + if (m_k2 == k2) + return false; + m_k2 = k2; + return true; +} + +float FEComposite::k3() const +{ + return m_k3; +} + +bool FEComposite::setK3(float k3) +{ + if (m_k3 == k3) + return false; + m_k3 = k3; + return true; +} + +float FEComposite::k4() const +{ + return m_k4; +} + +bool FEComposite::setK4(float k4) +{ + if (m_k4 == k4) + return false; + m_k4 = k4; + return true; +} + +template <int b1, int b2, int b3, int b4> +static inline void computeArithmeticPixels(unsigned char* source, unsigned char* destination, int pixelArrayLength, + float k1, float k2, float k3, float k4) +{ + float scaledK1; + float scaledK4; + if (b1) + scaledK1 = k1 / 255.f; + if (b4) + scaledK4 = k4 * 255.f; + + while (--pixelArrayLength >= 0) { + unsigned char i1 = *source; + unsigned char i2 = *destination; + float result = 0; + if (b1) + result += scaledK1 * i1 * i2; + if (b2) + result += k2 * i1; + if (b3) + result += k3 * i2; + if (b4) + result += scaledK4; + + if (result <= 0) + *destination = 0; + else if (result >= 255) + *destination = 255; + else + *destination = result; + ++source; + ++destination; + } +} + +static inline void arithmeticSoftware(unsigned char* source, unsigned char* destination, int pixelArrayLength, + float k1, float k2, float k3, float k4) +{ + if (!k4) { + if (!k1) { + computeArithmeticPixels<0, 1, 1, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4); + return; + } + + computeArithmeticPixels<1, 1, 1, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4); + return; + } + + if (!k1) { + computeArithmeticPixels<0, 1, 1, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4); + return; + } + computeArithmeticPixels<1, 1, 1, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4); +} + +inline void FEComposite::platformArithmeticSoftware(ByteArray* source, ByteArray* destination, + float k1, float k2, float k3, float k4) +{ + int length = source->length(); + ASSERT(length == static_cast<int>(destination->length())); + // The selection here eventually should happen dynamically. +#if CPU(ARM_NEON) && COMPILER(GCC) + ASSERT(!(length & 0x3)); + float coefficients[4] = { k1, k2, k3, k4 }; + platformArithmeticNeon(source->data(), destination->data(), length, coefficients); +#else + arithmeticSoftware(source->data(), destination->data(), length, k1, k2, k3, k4); +#endif +} + +void FEComposite::determineAbsolutePaintRect() +{ + switch (m_type) { + case FECOMPOSITE_OPERATOR_IN: + case FECOMPOSITE_OPERATOR_ATOP: + // For In and Atop the first effect just influences the result of + // the second effect. So just use the absolute paint rect of the second effect here. + setAbsolutePaintRect(inputEffect(1)->absolutePaintRect()); + return; + case FECOMPOSITE_OPERATOR_ARITHMETIC: + // Arithmetic may influnce the compele filter primitive region. So we can't + // optimize the paint region here. + setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); + return; + default: + // Take the union of both input effects. + FilterEffect::determineAbsolutePaintRect(); + return; + } +} + +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); + + platformArithmeticSoftware(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 FEComposite::dump() +{ +} + +static TextStream& operator<<(TextStream& ts, const CompositeOperationType& type) +{ + switch (type) { + case FECOMPOSITE_OPERATOR_UNKNOWN: + ts << "UNKNOWN"; + break; + case FECOMPOSITE_OPERATOR_OVER: + ts << "OVER"; + break; + case FECOMPOSITE_OPERATOR_IN: + ts << "IN"; + break; + case FECOMPOSITE_OPERATOR_OUT: + ts << "OUT"; + break; + case FECOMPOSITE_OPERATOR_ATOP: + ts << "ATOP"; + break; + case FECOMPOSITE_OPERATOR_XOR: + ts << "XOR"; + break; + case FECOMPOSITE_OPERATOR_ARITHMETIC: + ts << "ARITHMETIC"; + break; + } + return ts; +} + +TextStream& FEComposite::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feComposite"; + FilterEffect::externalRepresentation(ts); + ts << " operation=\"" << m_type << "\""; + if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC) + ts << " k1=\"" << m_k1 << "\" k2=\"" << m_k2 << "\" k3=\"" << m_k3 << "\" k4=\"" << m_k4 << "\""; + ts << "]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + inputEffect(1)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FEComposite.h b/Source/WebCore/platform/graphics/filters/FEComposite.h new file mode 100644 index 000000000..35f2505e3 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEComposite.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEComposite_h +#define FEComposite_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" + +#include "PlatformString.h" +#include "Filter.h" + +namespace WebCore { + +enum CompositeOperationType { + FECOMPOSITE_OPERATOR_UNKNOWN = 0, + FECOMPOSITE_OPERATOR_OVER = 1, + FECOMPOSITE_OPERATOR_IN = 2, + FECOMPOSITE_OPERATOR_OUT = 3, + FECOMPOSITE_OPERATOR_ATOP = 4, + FECOMPOSITE_OPERATOR_XOR = 5, + FECOMPOSITE_OPERATOR_ARITHMETIC = 6 +}; + +class FEComposite : public FilterEffect { +public: + static PassRefPtr<FEComposite> create(Filter*, const CompositeOperationType&, float, float, float, float); + + CompositeOperationType operation() const; + bool setOperation(CompositeOperationType); + + float k1() const; + bool setK1(float); + + float k2() const; + bool setK2(float); + + float k3() const; + bool setK3(float); + + float k4() const; + bool setK4(float); + + virtual void platformApplySoftware(); + virtual void dump(); + + virtual void determineAbsolutePaintRect(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEComposite(Filter*, const CompositeOperationType&, float, float, float, float); + + inline void platformArithmeticSoftware(ByteArray* source, ByteArray* destination, float k1, float k2, float k3, float k4); + inline void platformArithmeticNeon(unsigned char* source, unsigned char* destination, unsigned pixelArrayLength, float* kArray); + + CompositeOperationType m_type; + float m_k1; + float m_k2; + float m_k3; + float m_k4; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEComposite_h diff --git a/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp b/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp new file mode 100644 index 000000000..cda5f193e --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp @@ -0,0 +1,521 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2010 Zoltan Herczeg <zherczeg@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEConvolveMatrix.h" + +#include "Filter.h" +#include "RenderTreeAsText.h" +#include "TextStream.h" + +#include <wtf/ByteArray.h> +#include <wtf/ParallelJobs.h> + +namespace WebCore { + +FEConvolveMatrix::FEConvolveMatrix(Filter* filter, const IntSize& kernelSize, + float divisor, float bias, const IntPoint& targetOffset, EdgeModeType edgeMode, + const FloatPoint& kernelUnitLength, bool preserveAlpha, const Vector<float>& kernelMatrix) + : FilterEffect(filter) + , m_kernelSize(kernelSize) + , m_divisor(divisor) + , m_bias(bias) + , m_targetOffset(targetOffset) + , m_edgeMode(edgeMode) + , m_kernelUnitLength(kernelUnitLength) + , m_preserveAlpha(preserveAlpha) + , m_kernelMatrix(kernelMatrix) +{ +} + +PassRefPtr<FEConvolveMatrix> FEConvolveMatrix::create(Filter* filter, const IntSize& kernelSize, + float divisor, float bias, const IntPoint& targetOffset, EdgeModeType edgeMode, + const FloatPoint& kernelUnitLength, bool preserveAlpha, const Vector<float>& kernelMatrix) +{ + return adoptRef(new FEConvolveMatrix(filter, kernelSize, divisor, bias, targetOffset, edgeMode, kernelUnitLength, + preserveAlpha, kernelMatrix)); +} + + +IntSize FEConvolveMatrix::kernelSize() const +{ + return m_kernelSize; +} + +void FEConvolveMatrix::setKernelSize(const IntSize& kernelSize) +{ + m_kernelSize = kernelSize; +} + +const Vector<float>& FEConvolveMatrix::kernel() const +{ + return m_kernelMatrix; +} + +void FEConvolveMatrix::setKernel(const Vector<float>& kernel) +{ + m_kernelMatrix = kernel; +} + +float FEConvolveMatrix::divisor() const +{ + return m_divisor; +} + +bool FEConvolveMatrix::setDivisor(float divisor) +{ + if (m_divisor == divisor) + return false; + m_divisor = divisor; + return true; +} + +float FEConvolveMatrix::bias() const +{ + return m_bias; +} + +bool FEConvolveMatrix::setBias(float bias) +{ + if (m_bias == bias) + return false; + m_bias = bias; + return true; +} + +IntPoint FEConvolveMatrix::targetOffset() const +{ + return m_targetOffset; +} + +bool FEConvolveMatrix::setTargetOffset(const IntPoint& targetOffset) +{ + if (m_targetOffset == targetOffset) + return false; + m_targetOffset = targetOffset; + return true; +} + +EdgeModeType FEConvolveMatrix::edgeMode() const +{ + return m_edgeMode; +} + +bool FEConvolveMatrix::setEdgeMode(EdgeModeType edgeMode) +{ + if (m_edgeMode == edgeMode) + return false; + m_edgeMode = edgeMode; + return true; +} + +FloatPoint FEConvolveMatrix::kernelUnitLength() const +{ + return m_kernelUnitLength; +} + +bool FEConvolveMatrix::setKernelUnitLength(const FloatPoint& kernelUnitLength) +{ + if (m_kernelUnitLength == kernelUnitLength) + return false; + m_kernelUnitLength = kernelUnitLength; + return true; +} + +bool FEConvolveMatrix::preserveAlpha() const +{ + return m_preserveAlpha; +} + +bool FEConvolveMatrix::setPreserveAlpha(bool preserveAlpha) +{ + if (m_preserveAlpha == preserveAlpha) + return false; + m_preserveAlpha = preserveAlpha; + return true; +} + +/* + ----------------------------------- + ConvolveMatrix implementation + ----------------------------------- + + The image rectangle is split in the following way: + + +---------------------+ + | A | + +---------------------+ + | | | | + | B | C | D | + | | | | + +---------------------+ + | E | + +---------------------+ + + Where region C contains those pixels, whose values + can be calculated without crossing the edge of the rectangle. + + Example: + Image size: width: 10, height: 10 + + Order (kernel matrix size): width: 3, height 4 + Target: x:1, y:3 + + The following figure shows the target inside the kernel matrix: + + ... + ... + ... + .X. + + The regions in this case are the following: + Note: (x1, y1) top-left and (x2, y2) is the bottom-right corner + Note: row x2 and column y2 is not part of the region + only those (x, y) pixels, where x1 <= x < x2 and y1 <= y < y2 + + Region A: x1: 0, y1: 0, x2: 10, y2: 3 + Region B: x1: 0, y1: 3, x2: 1, y2: 10 + Region C: x1: 1, y1: 3, x2: 9, y2: 10 + Region D: x1: 9, y1: 3, x2: 10, y2: 10 + Region E: x1: 0, y1: 10, x2: 10, y2: 10 (empty region) + + Since region C (often) contains most of the pixels, we implemented + a fast algoritm to calculate these values, called fastSetInteriorPixels. + For other regions, fastSetOuterPixels is used, which calls getPixelValue, + to handle pixels outside of the image. In a rare situations, when + kernel matrix is bigger than the image, all pixels are calculated by this + function. + + Although these two functions have lot in common, I decided not to make + common a template for them, since there are key differences as well, + and would make it really hard to understand. +*/ + +static ALWAYS_INLINE unsigned char clampRGBAValue(float channel, unsigned char max = 255) +{ + if (channel <= 0) + return 0; + if (channel >= max) + return max; + return channel; +} + +template<bool preserveAlphaValues> +ALWAYS_INLINE void setDestinationPixels(ByteArray* image, int& pixel, float* totals, float divisor, float bias, ByteArray* src) +{ + unsigned char maxAlpha = preserveAlphaValues ? 255 : clampRGBAValue(totals[3] / divisor + bias); + for (int i = 0; i < 3; ++i) + image->set(pixel++, clampRGBAValue(totals[i] / divisor + bias, maxAlpha)); + + if (preserveAlphaValues) { + image->set(pixel, src->get(pixel)); + ++pixel; + } else + image->set(pixel++, maxAlpha); +} + +// Only for region C +template<bool preserveAlphaValues> +ALWAYS_INLINE void FEConvolveMatrix::fastSetInteriorPixels(PaintingData& paintingData, int clipRight, int clipBottom, int yStart, int yEnd) +{ + // edge mode does not affect these pixels + int pixel = (m_targetOffset.y() * paintingData.width + m_targetOffset.x()) * 4; + int kernelIncrease = clipRight * 4; + int xIncrease = (m_kernelSize.width() - 1) * 4; + // Contains the sum of rgb(a) components + float totals[3 + (preserveAlphaValues ? 0 : 1)]; + + // m_divisor cannot be 0, SVGFEConvolveMatrixElement ensures this + ASSERT(m_divisor); + + // Skip the first '(clipBottom - yEnd)' lines + pixel += (clipBottom - yEnd) * (xIncrease + (clipRight + 1) * 4); + int startKernelPixel = (clipBottom - yEnd) * (xIncrease + (clipRight + 1) * 4); + + for (int y = yEnd + 1; y > yStart; --y) { + for (int x = clipRight + 1; x > 0; --x) { + int kernelValue = m_kernelMatrix.size() - 1; + int kernelPixel = startKernelPixel; + int width = m_kernelSize.width(); + + totals[0] = 0; + totals[1] = 0; + totals[2] = 0; + if (!preserveAlphaValues) + totals[3] = 0; + + while (kernelValue >= 0) { + totals[0] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(kernelPixel++)); + totals[1] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(kernelPixel++)); + totals[2] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(kernelPixel++)); + if (!preserveAlphaValues) + totals[3] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(kernelPixel)); + ++kernelPixel; + --kernelValue; + if (!--width) { + kernelPixel += kernelIncrease; + width = m_kernelSize.width(); + } + } + + setDestinationPixels<preserveAlphaValues>(paintingData.dstPixelArray, pixel, totals, m_divisor, paintingData.bias, paintingData.srcPixelArray); + startKernelPixel += 4; + } + pixel += xIncrease; + startKernelPixel += xIncrease; + } +} + +ALWAYS_INLINE int FEConvolveMatrix::getPixelValue(PaintingData& paintingData, int x, int y) +{ + if (x >= 0 && x < paintingData.width && y >= 0 && y < paintingData.height) + return (y * paintingData.width + x) << 2; + + switch (m_edgeMode) { + default: // EDGEMODE_NONE + return -1; + case EDGEMODE_DUPLICATE: + if (x < 0) + x = 0; + else if (x >= paintingData.width) + x = paintingData.width - 1; + if (y < 0) + y = 0; + else if (y >= paintingData.height) + y = paintingData.height - 1; + return (y * paintingData.width + x) << 2; + case EDGEMODE_WRAP: + while (x < 0) + x += paintingData.width; + x %= paintingData.width; + while (y < 0) + y += paintingData.height; + y %= paintingData.height; + return (y * paintingData.width + x) << 2; + } +} + +// For other regions than C +template<bool preserveAlphaValues> +void FEConvolveMatrix::fastSetOuterPixels(PaintingData& paintingData, int x1, int y1, int x2, int y2) +{ + int pixel = (y1 * paintingData.width + x1) * 4; + int height = y2 - y1; + int width = x2 - x1; + int beginKernelPixelX = x1 - m_targetOffset.x(); + int startKernelPixelX = beginKernelPixelX; + int startKernelPixelY = y1 - m_targetOffset.y(); + int xIncrease = (paintingData.width - width) * 4; + // Contains the sum of rgb(a) components + float totals[3 + (preserveAlphaValues ? 0 : 1)]; + + // m_divisor cannot be 0, SVGFEConvolveMatrixElement ensures this + ASSERT(m_divisor); + + for (int y = height; y > 0; --y) { + for (int x = width; x > 0; --x) { + int kernelValue = m_kernelMatrix.size() - 1; + int kernelPixelX = startKernelPixelX; + int kernelPixelY = startKernelPixelY; + int width = m_kernelSize.width(); + + totals[0] = 0; + totals[1] = 0; + totals[2] = 0; + if (!preserveAlphaValues) + totals[3] = 0; + + while (kernelValue >= 0) { + int pixelIndex = getPixelValue(paintingData, kernelPixelX, kernelPixelY); + if (pixelIndex >= 0) { + totals[0] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(pixelIndex)); + totals[1] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(pixelIndex + 1)); + totals[2] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(pixelIndex + 2)); + } + if (!preserveAlphaValues && pixelIndex >= 0) + totals[3] += m_kernelMatrix[kernelValue] * static_cast<float>(paintingData.srcPixelArray->get(pixelIndex + 3)); + ++kernelPixelX; + --kernelValue; + if (!--width) { + kernelPixelX = startKernelPixelX; + ++kernelPixelY; + width = m_kernelSize.width(); + } + } + + setDestinationPixels<preserveAlphaValues>(paintingData.dstPixelArray, pixel, totals, m_divisor, paintingData.bias, paintingData.srcPixelArray); + ++startKernelPixelX; + } + pixel += xIncrease; + startKernelPixelX = beginKernelPixelX; + ++startKernelPixelY; + } +} + +ALWAYS_INLINE void FEConvolveMatrix::setInteriorPixels(PaintingData& paintingData, int clipRight, int clipBottom, int yStart, int yEnd) +{ + // Must be implemented here, since it refers another ALWAYS_INLINE + // function, which defined in this C++ source file as well + if (m_preserveAlpha) + fastSetInteriorPixels<true>(paintingData, clipRight, clipBottom, yStart, yEnd); + else + fastSetInteriorPixels<false>(paintingData, clipRight, clipBottom, yStart, yEnd); +} + +ALWAYS_INLINE void FEConvolveMatrix::setOuterPixels(PaintingData& paintingData, int x1, int y1, int x2, int y2) +{ + // Although this function can be moved to the header, it is implemented here + // because setInteriorPixels is also implemented here + if (m_preserveAlpha) + fastSetOuterPixels<true>(paintingData, x1, y1, x2, y2); + else + fastSetOuterPixels<false>(paintingData, x1, y1, x2, y2); +} + +void FEConvolveMatrix::setInteriorPixelsWorker(InteriorPixelParameters* param) +{ + param->filter->setInteriorPixels(*param->paintingData, param->clipRight, param->clipBottom, param->yStart, param->yEnd); +} + +void FEConvolveMatrix::platformApplySoftware() +{ + FilterEffect* in = inputEffect(0); + + 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) { + + int optimalThreadNumber = (absolutePaintRect().width() * absolutePaintRect().height()) / s_minimalRectDimension; + if (optimalThreadNumber > 1) { + WTF::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 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::dump() +{ +} + +static TextStream& operator<<(TextStream& ts, const EdgeModeType& type) +{ + switch (type) { + case EDGEMODE_UNKNOWN: + ts << "UNKNOWN"; + break; + case EDGEMODE_DUPLICATE: + ts << "DUPLICATE"; + break; + case EDGEMODE_WRAP: + ts << "WRAP"; + break; + case EDGEMODE_NONE: + ts << "NONE"; + break; + } + return ts; +} + +TextStream& FEConvolveMatrix::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feConvolveMatrix"; + FilterEffect::externalRepresentation(ts); + ts << " order=\"" << m_kernelSize << "\" " + << "kernelMatrix=\"" << m_kernelMatrix << "\" " + << "divisor=\"" << m_divisor << "\" " + << "bias=\"" << m_bias << "\" " + << "target=\"" << m_targetOffset << "\" " + << "edgeMode=\"" << m_edgeMode << "\" " + << "kernelUnitLength=\"" << m_kernelUnitLength << "\" " + << "preserveAlpha=\"" << m_preserveAlpha << "\"]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + return ts; +} + +}; // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.h b/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.h new file mode 100644 index 000000000..34baf6f17 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEConvolveMatrix.h @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2010 Zoltan Herczeg <zherczeg@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEConvolveMatrix_h +#define FEConvolveMatrix_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" +#include "FloatPoint.h" +#include "FloatSize.h" +#include "Filter.h" +#include <wtf/AlwaysInline.h> +#include <wtf/Vector.h> + +namespace WebCore { + +enum EdgeModeType { + EDGEMODE_UNKNOWN = 0, + EDGEMODE_DUPLICATE = 1, + EDGEMODE_WRAP = 2, + EDGEMODE_NONE = 3 +}; + +class CanvasPixelArray; + +class FEConvolveMatrix : public FilterEffect { +public: + static PassRefPtr<FEConvolveMatrix> create(Filter*, const IntSize&, + float, float, const IntPoint&, EdgeModeType, const FloatPoint&, + bool, const Vector<float>&); + + IntSize kernelSize() const; + void setKernelSize(const IntSize&); + + const Vector<float>& kernel() const; + void setKernel(const Vector<float>&); + + float divisor() const; + bool setDivisor(float); + + float bias() const; + bool setBias(float); + + IntPoint targetOffset() const; + bool setTargetOffset(const IntPoint&); + + EdgeModeType edgeMode() const; + bool setEdgeMode(EdgeModeType); + + FloatPoint kernelUnitLength() const; + bool setKernelUnitLength(const FloatPoint&); + + bool preserveAlpha() const; + bool setPreserveAlpha(bool); + + virtual void platformApplySoftware(); + virtual void dump(); + + virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); } + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + + struct PaintingData { + ByteArray* srcPixelArray; + ByteArray* dstPixelArray; + int width; + int height; + float bias; + }; + + FEConvolveMatrix(Filter*, const IntSize&, float, float, + const IntPoint&, EdgeModeType, const FloatPoint&, bool, const Vector<float>&); + + template<bool preserveAlphaValues> + ALWAYS_INLINE void fastSetInteriorPixels(PaintingData&, int clipRight, int clipBottom, int yStart, int yEnd); + + ALWAYS_INLINE int getPixelValue(PaintingData&, int x, int y); + + template<bool preserveAlphaValues> + void fastSetOuterPixels(PaintingData&, int x1, int y1, int x2, int y2); + + // Wrapper functions + ALWAYS_INLINE void setInteriorPixels(PaintingData&, int clipRight, int clipBottom, int yStart, int yEnd); + ALWAYS_INLINE void setOuterPixels(PaintingData&, int x1, int y1, int x2, int y2); + + // Parallelization parts + static const int s_minimalRectDimension = (100 * 100); // Empirical data limit for parallel jobs + + template<typename Type> + friend class ParallelJobs; + + struct InteriorPixelParameters { + FEConvolveMatrix* filter; + PaintingData* paintingData; + int clipBottom; + int clipRight; + int yStart; + int yEnd; + }; + + static void setInteriorPixelsWorker(InteriorPixelParameters*); + + IntSize m_kernelSize; + float m_divisor; + float m_bias; + IntPoint m_targetOffset; + EdgeModeType m_edgeMode; + FloatPoint m_kernelUnitLength; + bool m_preserveAlpha; + Vector<float> m_kernelMatrix; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEConvolveMatrix_h diff --git a/Source/WebCore/platform/graphics/filters/FECustomFilter.cpp b/Source/WebCore/platform/graphics/filters/FECustomFilter.cpp new file mode 100644 index 000000000..fb4270e47 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FECustomFilter.cpp @@ -0,0 +1,214 @@ +/* + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(CSS_SHADERS) && ENABLE(WEBGL) +#include "FECustomFilter.h" + +#include "CachedShader.h" +#include "CustomFilterMesh.h" +#include "CustomFilterShader.h" +#include "Document.h" +#include "DrawingBuffer.h" +#include "FrameView.h" +#include "GraphicsContext3D.h" +#include "ImageData.h" +#include "RenderTreeAsText.h" +#include "StyleCachedShader.h" +#include "TextStream.h" +#include "Texture.h" +#include "TilingData.h" +#include "TransformationMatrix.h" + +#include <wtf/ByteArray.h> + +namespace WebCore { + +static void orthogonalProjectionMatrix(TransformationMatrix& matrix, float left, float right, float bottom, float top) +{ + ASSERT(matrix.isIdentity()); + + float deltaX = right - left; + float deltaY = top - bottom; + if (!deltaX || !deltaY) + return; + matrix.setM11(2.0f / deltaX); + matrix.setM41(-(right + left) / deltaX); + matrix.setM22(2.0f / deltaY); + matrix.setM42(-(top + bottom) / deltaY); + + // Use big enough near/far values, so that simple rotations of rather large objects will not + // get clipped. 10000 should cover most of the screen resolutions. + const float farValue = 10000; + const float nearValue = -10000; + matrix.setM33(-2.0f / (farValue - nearValue)); + matrix.setM43(- (farValue + nearValue) / (farValue - nearValue)); + matrix.setM44(1.0f); +} + +FECustomFilter::FECustomFilter(Filter* filter, Document* document, const String& vertexShader, const String& fragmentShader, + unsigned meshRows, unsigned meshColumns, CustomFilterOperation::MeshBoxType meshBoxType, + CustomFilterOperation::MeshType meshType) + : FilterEffect(filter) + , m_document(document) + , m_vertexShader(vertexShader) + , m_fragmentShader(fragmentShader) + , m_meshRows(meshRows) + , m_meshColumns(meshColumns) + , m_meshBoxType(meshBoxType) + , m_meshType(meshType) +{ +} + +PassRefPtr<FECustomFilter> FECustomFilter::create(Filter* filter, Document* document, const String& vertexShader, const String& fragmentShader, + unsigned meshRows, unsigned meshColumns, CustomFilterOperation::MeshBoxType meshBoxType, + CustomFilterOperation::MeshType meshType) +{ + return adoptRef(new FECustomFilter(filter, document, vertexShader, fragmentShader, meshRows, meshColumns, meshBoxType, meshType)); +} + +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().numTiles() != 1) + 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::initializeContext(const IntSize& contextSize) +{ + GraphicsContext3D::Attributes attributes; + attributes.preserveDrawingBuffer = true; + attributes.premultipliedAlpha = false; + + m_context = GraphicsContext3D::create(attributes, m_document->view()->root()->hostWindow(), GraphicsContext3D::RenderOffscreen); + m_drawingBuffer = DrawingBuffer::create(m_context.get(), contextSize, !attributes.preserveDrawingBuffer); + + m_shader = CustomFilterShader::create(m_context.get(), m_vertexShader, m_fragmentShader); + m_mesh = CustomFilterMesh::create(m_context.get(), m_meshColumns, m_meshRows, + FloatRect(0, 0, 1, 1), + m_meshType); +} + +void FECustomFilter::resizeContext(const IntSize& newContextSize) +{ + m_inputTexture = 0; + m_drawingBuffer->reset(newContextSize); + m_context->reshape(newContextSize.width(), newContextSize.height()); + m_context->viewport(0, 0, newContextSize.width(), newContextSize.height()); + m_inputTexture = Texture::create(m_context.get(), Texture::RGBA8, newContextSize.width(), newContextSize.height()); + m_contextSize = newContextSize; +} + +void FECustomFilter::bindVertexAttribute(int attributeLocation, unsigned size, unsigned& offset) +{ + if (attributeLocation != -1) { + m_context->vertexAttribPointer(attributeLocation, 4, GraphicsContext3D::FLOAT, false, m_mesh->bytesPerVertex(), offset); + m_context->enableVertexAttribArray(attributeLocation); + } + offset += size * sizeof(float); +} + +void FECustomFilter::bindProgramAndBuffers(ByteArray* srcPixelArray) +{ + m_context->useProgram(m_shader->program()); + + if (m_shader->samplerLocation() != -1) { + m_context->activeTexture(GraphicsContext3D::TEXTURE0); + m_context->uniform1i(m_shader->samplerLocation(), 0); + m_inputTexture->load(srcPixelArray->data()); + m_inputTexture->bindTile(0); + } + + if (m_shader->projectionMatrixLocation() != -1) { + TransformationMatrix projectionMatrix; + orthogonalProjectionMatrix(projectionMatrix, -0.5, 0.5, -0.5, 0.5); + float glProjectionMatrix[16]; + projectionMatrix.toColumnMajorFloatArray(glProjectionMatrix); + m_context->uniformMatrix4fv(m_shader->projectionMatrixLocation(), false, &glProjectionMatrix[0], 1); + } + + m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_mesh->verticesBufferObject()); + m_context->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, m_mesh->elementsBufferObject()); + + unsigned offset = 0; + bindVertexAttribute(m_shader->positionAttribLocation(), 4, offset); + bindVertexAttribute(m_shader->texAttribLocation(), 2, offset); + bindVertexAttribute(m_shader->meshAttribLocation(), 2, offset); + if (m_meshType == CustomFilterOperation::DETACHED) + bindVertexAttribute(m_shader->triangleAttribLocation(), 3, offset); +} + +void FECustomFilter::dump() +{ +} + +TextStream& FECustomFilter::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feCustomFilter"; + FilterEffect::externalRepresentation(ts); + ts << "]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(CSS_SHADERS) && ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/filters/FECustomFilter.h b/Source/WebCore/platform/graphics/filters/FECustomFilter.h new file mode 100644 index 000000000..2aaabf6ba --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FECustomFilter.h @@ -0,0 +1,98 @@ +/* + * Copyright 2011 Adobe Systems Incorporated. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef FECustomFilter_h +#define FECustomFilter_h + +#if ENABLE(CSS_SHADERS) && ENABLE(WEBGL) + +#include "CustomFilterOperation.h" +#include "Filter.h" +#include "FilterEffect.h" +#include <wtf/RefPtr.h> + +namespace JSC { +class ByteArray; +} + +namespace WebCore { + +class CachedShader; +class CustomFilterMesh; +class CustomFilterShader; +class Document; +class DrawingBuffer; +class GraphicsContext3D; +class IntSize; +class Texture; + +class FECustomFilter : public FilterEffect { +public: + static PassRefPtr<FECustomFilter> create(Filter*, Document*, const String& vertexShader, const String& fragmentShader, + unsigned meshRows, unsigned meshColumns, CustomFilterOperation::MeshBoxType, + CustomFilterOperation::MeshType); + + virtual void platformApplySoftware(); + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FECustomFilter(Filter*, Document*, const String& vertexShader, const String& fragmentShader, + unsigned meshRows, unsigned meshColumns, CustomFilterOperation::MeshBoxType, + CustomFilterOperation::MeshType); + + void initializeContext(const IntSize& contextSize); + void resizeContext(const IntSize& newContextSize); + void bindVertexAttribute(int attributeLocation, unsigned size, unsigned& offset); + void bindProgramAndBuffers(ByteArray* srcPixelArray); + + Document* m_document; + + RefPtr<GraphicsContext3D> m_context; + RefPtr<DrawingBuffer> m_drawingBuffer; + RefPtr<Texture> m_inputTexture; + RefPtr<CustomFilterShader> m_shader; + RefPtr<CustomFilterMesh> m_mesh; + IntSize m_contextSize; + + String m_vertexShader; + String m_fragmentShader; + + unsigned m_meshRows; + unsigned m_meshColumns; + CustomFilterOperation::MeshBoxType m_meshBoxType; + CustomFilterOperation::MeshType m_meshType; +}; + +} // namespace WebCore + +#endif // ENABLE(CSS_SHADERS) && ENABLE(WEBGL) + +#endif // FECustomFilter_h diff --git a/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.cpp b/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.cpp new file mode 100644 index 000000000..5f9d049ef --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEDiffuseLighting.h" + +#include "LightSource.h" +#include "RenderTreeAsText.h" +#include "TextStream.h" + +namespace WebCore { + +FEDiffuseLighting::FEDiffuseLighting(Filter* filter, const Color& lightingColor, float surfaceScale, + float diffuseConstant, float kernelUnitLengthX, float kernelUnitLengthY, PassRefPtr<LightSource> lightSource) + : FELighting(filter, DiffuseLighting, lightingColor, surfaceScale, diffuseConstant, 0, 0, kernelUnitLengthX, kernelUnitLengthY, lightSource) +{ +} + +PassRefPtr<FEDiffuseLighting> FEDiffuseLighting::create(Filter* filter, const Color& lightingColor, + float surfaceScale, float diffuseConstant, float kernelUnitLengthX, + float kernelUnitLengthY, PassRefPtr<LightSource> lightSource) +{ + return adoptRef(new FEDiffuseLighting(filter, lightingColor, surfaceScale, diffuseConstant, kernelUnitLengthX, kernelUnitLengthY, lightSource)); +} + +FEDiffuseLighting::~FEDiffuseLighting() +{ +} + +Color FEDiffuseLighting::lightingColor() const +{ + return m_lightingColor; +} + +bool FEDiffuseLighting::setLightingColor(const Color& lightingColor) +{ + if (m_lightingColor == lightingColor) + return false; + m_lightingColor = lightingColor; + return true; +} + +float FEDiffuseLighting::surfaceScale() const +{ + return m_surfaceScale; +} + +bool FEDiffuseLighting::setSurfaceScale(float surfaceScale) +{ + if (m_surfaceScale == surfaceScale) + return false; + m_surfaceScale = surfaceScale; + return true; +} + +float FEDiffuseLighting::diffuseConstant() const +{ + return m_diffuseConstant; +} + +bool FEDiffuseLighting::setDiffuseConstant(float diffuseConstant) +{ + if (m_diffuseConstant == diffuseConstant) + return false; + m_diffuseConstant = diffuseConstant; + return true; +} + +float FEDiffuseLighting::kernelUnitLengthX() const +{ + return m_kernelUnitLengthX; +} + +bool FEDiffuseLighting::setKernelUnitLengthX(float kernelUnitLengthX) +{ + if (m_kernelUnitLengthX == kernelUnitLengthX) + return false; + m_kernelUnitLengthX = kernelUnitLengthX; + return true; +} + +float FEDiffuseLighting::kernelUnitLengthY() const +{ + return m_kernelUnitLengthY; +} + +bool FEDiffuseLighting::setKernelUnitLengthY(float kernelUnitLengthY) +{ + if (m_kernelUnitLengthY == kernelUnitLengthY) + return false; + m_kernelUnitLengthY = kernelUnitLengthY; + return true; +} + +const LightSource* FEDiffuseLighting::lightSource() const +{ + return m_lightSource.get(); +} + +void FEDiffuseLighting::setLightSource(PassRefPtr<LightSource> lightSource) +{ + m_lightSource = lightSource; +} + +void FEDiffuseLighting::dump() +{ +} + +TextStream& FEDiffuseLighting::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feDiffuseLighting"; + FilterEffect::externalRepresentation(ts); + ts << " surfaceScale=\"" << m_surfaceScale << "\" " + << "diffuseConstant=\"" << m_diffuseConstant << "\" " + << "kernelUnitLength=\"" << m_kernelUnitLengthX << ", " << m_kernelUnitLengthY << "\"]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.h b/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.h new file mode 100644 index 000000000..5f2065163 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEDiffuseLighting.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEDiffuseLighting_h +#define FEDiffuseLighting_h + +#if ENABLE(FILTERS) +#include "FELighting.h" + +namespace WebCore { + +class LightSource; + +class FEDiffuseLighting : public FELighting { +public: + static PassRefPtr<FEDiffuseLighting> create(Filter*, const Color&, float, float, + float, float, PassRefPtr<LightSource>); + virtual ~FEDiffuseLighting(); + + Color lightingColor() const; + bool setLightingColor(const Color&); + + float surfaceScale() const; + bool setSurfaceScale(float); + + float diffuseConstant() const; + bool setDiffuseConstant(float); + + float kernelUnitLengthX() const; + bool setKernelUnitLengthX(float); + + float kernelUnitLengthY() const; + bool setKernelUnitLengthY(float); + + const LightSource* lightSource() const; + void setLightSource(PassRefPtr<LightSource>); + + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEDiffuseLighting(Filter*, const Color&, float, float, float, float, PassRefPtr<LightSource>); +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEDiffuseLighting_h diff --git a/Source/WebCore/platform/graphics/filters/FEDisplacementMap.cpp b/Source/WebCore/platform/graphics/filters/FEDisplacementMap.cpp new file mode 100644 index 000000000..b0eac449a --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEDisplacementMap.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEDisplacementMap.h" + +#include "Filter.h" +#include "GraphicsContext.h" +#include "RenderTreeAsText.h" +#include "TextStream.h" + +#include <wtf/ByteArray.h> + +namespace WebCore { + +FEDisplacementMap::FEDisplacementMap(Filter* filter, ChannelSelectorType xChannelSelector, ChannelSelectorType yChannelSelector, float scale) + : FilterEffect(filter) + , m_xChannelSelector(xChannelSelector) + , m_yChannelSelector(yChannelSelector) + , m_scale(scale) +{ +} + +PassRefPtr<FEDisplacementMap> FEDisplacementMap::create(Filter* filter, ChannelSelectorType xChannelSelector, + ChannelSelectorType yChannelSelector, float scale) +{ + return adoptRef(new FEDisplacementMap(filter, xChannelSelector, yChannelSelector, scale)); +} + +ChannelSelectorType FEDisplacementMap::xChannelSelector() const +{ + return m_xChannelSelector; +} + +bool FEDisplacementMap::setXChannelSelector(const ChannelSelectorType xChannelSelector) +{ + if (m_xChannelSelector == xChannelSelector) + return false; + m_xChannelSelector = xChannelSelector; + return true; +} + +ChannelSelectorType FEDisplacementMap::yChannelSelector() const +{ + return m_yChannelSelector; +} + +bool FEDisplacementMap::setYChannelSelector(const ChannelSelectorType yChannelSelector) +{ + if (m_yChannelSelector == yChannelSelector) + return false; + m_yChannelSelector = yChannelSelector; + return true; +} + +float FEDisplacementMap::scale() const +{ + return m_scale; +} + +bool FEDisplacementMap::setScale(float scale) +{ + if (m_scale == scale) + return false; + m_scale = scale; + return true; +} + +void FEDisplacementMap::platformApplySoftware() +{ + FilterEffect* in = inputEffect(0); + FilterEffect* in2 = inputEffect(1); + + ASSERT(m_xChannelSelector != CHANNEL_UNKNOWN); + ASSERT(m_yChannelSelector != CHANNEL_UNKNOWN); + + 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 FEDisplacementMap::dump() +{ +} + +static TextStream& operator<<(TextStream& ts, const ChannelSelectorType& type) +{ + switch (type) { + case CHANNEL_UNKNOWN: + ts << "UNKNOWN"; + break; + case CHANNEL_R: + ts << "RED"; + break; + case CHANNEL_G: + ts << "GREEN"; + break; + case CHANNEL_B: + ts << "BLUE"; + break; + case CHANNEL_A: + ts << "ALPHA"; + break; + } + return ts; +} + +TextStream& FEDisplacementMap::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feDisplacementMap"; + FilterEffect::externalRepresentation(ts); + ts << " scale=\"" << m_scale << "\" " + << "xChannelSelector=\"" << m_xChannelSelector << "\" " + << "yChannelSelector=\"" << m_yChannelSelector << "\"]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + inputEffect(1)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FEDisplacementMap.h b/Source/WebCore/platform/graphics/filters/FEDisplacementMap.h new file mode 100644 index 000000000..6d9bdfe3a --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEDisplacementMap.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEDisplacementMap_h +#define FEDisplacementMap_h + +#if ENABLE(FILTERS) +#include "PlatformString.h" +#include "FilterEffect.h" +#include "Filter.h" + +namespace WebCore { + +enum ChannelSelectorType { + CHANNEL_UNKNOWN = 0, + CHANNEL_R = 1, + CHANNEL_G = 2, + CHANNEL_B = 3, + CHANNEL_A = 4 +}; + +class FEDisplacementMap : public FilterEffect { +public: + static PassRefPtr<FEDisplacementMap> create(Filter*, ChannelSelectorType xChannelSelector, ChannelSelectorType yChannelSelector, float); + + ChannelSelectorType xChannelSelector() const; + bool setXChannelSelector(const ChannelSelectorType); + + ChannelSelectorType yChannelSelector() const; + bool setYChannelSelector(const ChannelSelectorType); + + float scale() const; + bool setScale(float); + + virtual void platformApplySoftware(); + virtual void dump(); + + virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); } + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEDisplacementMap(Filter*, ChannelSelectorType xChannelSelector, ChannelSelectorType yChannelSelector, float); + + ChannelSelectorType m_xChannelSelector; + ChannelSelectorType m_yChannelSelector; + float m_scale; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEDisplacementMap_h diff --git a/Source/WebCore/platform/graphics/filters/FEDropShadow.cpp b/Source/WebCore/platform/graphics/filters/FEDropShadow.cpp new file mode 100644 index 000000000..5d807785b --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEDropShadow.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) Research In Motion Limited 2011. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEDropShadow.h" + +#include "ColorSpace.h" +#include "FEGaussianBlur.h" +#include "Filter.h" +#include "GraphicsContext.h" +#include "RenderTreeAsText.h" +#include "ShadowBlur.h" +#include "TextStream.h" +#include <wtf/ByteArray.h> +#include <wtf/MathExtras.h> + +using namespace std; + +namespace WebCore { + +FEDropShadow::FEDropShadow(Filter* filter, float stdX, float stdY, float dx, float dy, const Color& shadowColor, float shadowOpacity) + : FilterEffect(filter) + , m_stdX(stdX) + , m_stdY(stdY) + , m_dx(dx) + , m_dy(dy) + , m_shadowColor(shadowColor) + , m_shadowOpacity(shadowOpacity) +{ +} + +PassRefPtr<FEDropShadow> FEDropShadow::create(Filter* filter, float stdX, float stdY, float dx, float dy, const Color& shadowColor, float shadowOpacity) +{ + return adoptRef(new FEDropShadow(filter, stdX, stdY, dx, dy, shadowColor, shadowOpacity)); +} + +void FEDropShadow::determineAbsolutePaintRect() +{ + Filter* filter = this->filter(); + ASSERT(filter); + + FloatRect absolutePaintRect = inputEffect(0)->absolutePaintRect(); + FloatRect absoluteOffsetPaintRect(absolutePaintRect); + absoluteOffsetPaintRect.move(filter->applyHorizontalScale(m_dx), filter->applyVerticalScale(m_dy)); + absolutePaintRect.unite(absoluteOffsetPaintRect); + if (clipsToBounds()) + absolutePaintRect.intersect(maxEffectRect()); + else + absolutePaintRect.unite(maxEffectRect()); + + unsigned kernelSizeX = 0; + unsigned kernelSizeY = 0; + FEGaussianBlur::calculateKernelSize(filter, kernelSizeX, kernelSizeY, m_stdX, m_stdY); + + // We take the half kernel size and multiply it with three, because we run box blur three times. + absolutePaintRect.inflateX(3 * kernelSizeX * 0.5f); + absolutePaintRect.inflateY(3 * kernelSizeY * 0.5f); + setAbsolutePaintRect(enclosingIntRect(absolutePaintRect)); +} + +void FEDropShadow::platformApplySoftware() +{ + FilterEffect* in = inputEffect(0); + + ImageBuffer* resultImage = createImageBufferResult(); + if (!resultImage) + return; + + Filter* filter = this->filter(); + FloatSize blurRadius(filter->applyHorizontalScale(m_stdX), filter->applyVerticalScale(m_stdY)); + 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(); + ASSERT(sourceImage); + GraphicsContext* resultContext = resultImage->context(); + ASSERT(resultContext); + resultContext->setAlpha(m_shadowOpacity); + resultContext->drawImageBuffer(sourceImage, ColorSpaceDeviceRGB, drawingRegionWithOffset); + resultContext->setAlpha(1); + + ShadowBlur contextShadow(blurRadius, offset, m_shadowColor, ColorSpaceDeviceRGB); + + // TODO: Direct pixel access to ImageBuffer would avoid copying the ImageData. + IntRect shadowArea(IntPoint(), resultImage->size()); + RefPtr<ByteArray> srcPixelArray = resultImage->getPremultipliedImageData(shadowArea); + + contextShadow.blurLayerImage(srcPixelArray->data(), shadowArea.size(), 4 * shadowArea.size().width()); + + resultImage->putPremultipliedImageData(srcPixelArray.get(), shadowArea.size(), shadowArea, IntPoint()); + + resultContext->setCompositeOperation(CompositeSourceIn); + resultContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size()), m_shadowColor, ColorSpaceDeviceRGB); + resultContext->setCompositeOperation(CompositeDestinationOver); + + resultImage->context()->drawImageBuffer(sourceImage, ColorSpaceDeviceRGB, drawingRegion); +} + +void FEDropShadow::dump() +{ +} + +TextStream& FEDropShadow::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feDropShadow"; + FilterEffect::externalRepresentation(ts); + ts << " stdDeviation=\"" << m_stdX << ", " << m_stdY << "\" dx=\"" << m_dx << "\" dy=\"" << m_dy << "\" flood-color=\"" << m_shadowColor.nameForRenderTreeAsText() <<"\" flood-opacity=\"" << m_shadowOpacity << "]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FEDropShadow.h b/Source/WebCore/platform/graphics/filters/FEDropShadow.h new file mode 100644 index 000000000..d155b4638 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEDropShadow.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) Research In Motion Limited 2011. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEDropShadow_h +#define FEDropShadow_h + +#if ENABLE(FILTERS) +#include "Color.h" +#include "Filter.h" +#include "FilterEffect.h" + +namespace WebCore { + +class FEDropShadow : public FilterEffect { +public: + static PassRefPtr<FEDropShadow> create(Filter*, float, float, float, float, const Color&, float); + + float stdDeviationX() const { return m_stdX; } + void setStdDeviationX(float stdX) { m_stdX = stdX; } + + float stdDeviationY() const { return m_stdY; } + void setStdDeviationY(float stdY) { m_stdY = stdY; } + + float dx() const { return m_dx; } + void setDx(float dx) { m_dx = dx; } + + float dy() const { return m_dy; } + void setDy(float dy) { m_dy = dy; } + + Color shadowColor() const { return m_shadowColor; } + void setShadowColor(const Color& shadowColor) { m_shadowColor = shadowColor; } + + float shadowOpacity() const { return m_shadowOpacity; } + void setShadowOpacity(float shadowOpacity) { m_shadowOpacity = shadowOpacity; } + + static float calculateStdDeviation(float); + + virtual void platformApplySoftware(); + virtual void dump(); + + virtual void determineAbsolutePaintRect(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEDropShadow(Filter*, float, float, float, float, const Color&, float); + + float m_stdX; + float m_stdY; + float m_dx; + float m_dy; + Color m_shadowColor; + float m_shadowOpacity; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) +#endif // FEDropShadow_h diff --git a/Source/WebCore/platform/graphics/filters/FEFlood.cpp b/Source/WebCore/platform/graphics/filters/FEFlood.cpp new file mode 100644 index 000000000..086eb966e --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEFlood.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEFlood.h" + +#include "Filter.h" +#include "GraphicsContext.h" +#include "RenderTreeAsText.h" +#include "TextStream.h" + +namespace WebCore { + +FEFlood::FEFlood(Filter* filter, const Color& floodColor, float floodOpacity) + : FilterEffect(filter) + , m_floodColor(floodColor) + , m_floodOpacity(floodOpacity) +{ +} + +PassRefPtr<FEFlood> FEFlood::create(Filter* filter, const Color& floodColor, float floodOpacity) +{ + return adoptRef(new FEFlood(filter, floodColor, floodOpacity)); +} + +Color FEFlood::floodColor() const +{ + return m_floodColor; +} + +bool FEFlood::setFloodColor(const Color& color) +{ + if (m_floodColor == color) + return false; + m_floodColor = color; + return true; +} + +float FEFlood::floodOpacity() const +{ + return m_floodOpacity; +} + +bool FEFlood::setFloodOpacity(float floodOpacity) +{ + if (m_floodOpacity == floodOpacity) + return false; + m_floodOpacity = floodOpacity; + return true; +} + +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::dump() +{ +} + +TextStream& FEFlood::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feFlood"; + FilterEffect::externalRepresentation(ts); + ts << " flood-color=\"" << floodColor().nameForRenderTreeAsText() << "\" " + << "flood-opacity=\"" << floodOpacity() << "\"]\n"; + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FEFlood.h b/Source/WebCore/platform/graphics/filters/FEFlood.h new file mode 100644 index 000000000..e0484b449 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEFlood.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEFlood_h +#define FEFlood_h + +#if ENABLE(FILTERS) +#include "Color.h" +#include "Filter.h" +#include "FilterEffect.h" + +namespace WebCore { + +class FEFlood : public FilterEffect { +public: + static PassRefPtr<FEFlood> create(Filter* filter, const Color&, float); + + Color floodColor() const; + bool setFloodColor(const Color &); + + float floodOpacity() const; + bool setFloodOpacity(float); + + virtual void platformApplySoftware(); + virtual void dump(); + + virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); } + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEFlood(Filter*, const Color&, float); + + Color m_floodColor; + float m_floodOpacity; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEFlood_h diff --git a/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp b/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp new file mode 100644 index 000000000..f9a86eb17 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2010 Igalia, S.L. + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEGaussianBlur.h" + +#include "FEGaussianBlurNEON.h" +#include "Filter.h" +#include "GraphicsContext.h" +#include "RenderTreeAsText.h" +#include "TextStream.h" + +#include <wtf/ByteArray.h> +#include <wtf/MathExtras.h> +#include <wtf/ParallelJobs.h> + +using namespace std; + +static inline float gaussianKernelFactor() +{ + return 3 / 4.f * sqrtf(2 * piFloat); +} + +static const unsigned gMaxKernelSize = 1000; + +namespace WebCore { + +FEGaussianBlur::FEGaussianBlur(Filter* filter, float x, float y) + : FilterEffect(filter) + , m_stdX(x) + , m_stdY(y) +{ +} + +PassRefPtr<FEGaussianBlur> FEGaussianBlur::create(Filter* filter, float x, float y) +{ + return adoptRef(new FEGaussianBlur(filter, x, y)); +} + +float FEGaussianBlur::stdDeviationX() const +{ + return m_stdX; +} + +void FEGaussianBlur::setStdDeviationX(float x) +{ + m_stdX = x; +} + +float FEGaussianBlur::stdDeviationY() const +{ + return m_stdY; +} + +void FEGaussianBlur::setStdDeviationY(float y) +{ + m_stdY = y; +} + +inline void boxBlur(ByteArray* srcPixelArray, ByteArray* dstPixelArray, + unsigned dx, int dxLeft, int dxRight, int stride, int strideLine, int effectWidth, int effectHeight, bool alphaImage) +{ + for (int y = 0; y < effectHeight; ++y) { + int line = y * strideLine; + for (int channel = 3; channel >= 0; --channel) { + int sum = 0; + // Fill the kernel + int maxKernelSize = min(dxRight, effectWidth); + for (int i = 0; i < maxKernelSize; ++i) + sum += srcPixelArray->get(line + i * stride + channel); + + // Blurring + for (int x = 0; x < effectWidth; ++x) { + int pixelByteOffset = line + x * stride + channel; + dstPixelArray->set(pixelByteOffset, static_cast<unsigned char>(sum / dx)); + if (x >= dxLeft) + sum -= srcPixelArray->get(pixelByteOffset - dxLeft * stride); + if (x + dxRight < effectWidth) + sum += srcPixelArray->get(pixelByteOffset + dxRight * stride); + } + if (alphaImage) // Source image is black, it just has different alpha values + break; + } + } +} + +inline void FEGaussianBlur::platformApplyGeneric(ByteArray* srcPixelArray, ByteArray* tmpPixelArray, unsigned kernelSizeX, unsigned kernelSizeY, IntSize& paintSize) +{ + int stride = 4 * paintSize.width(); + int dxLeft = 0; + int dxRight = 0; + int dyLeft = 0; + int dyRight = 0; + ByteArray* src = srcPixelArray; + ByteArray* 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 FEGaussianBlur::platformApplyWorker(PlatformApplyParameters* parameters) +{ + IntSize paintSize(parameters->width, parameters->height); +#if CPU(ARM_NEON) && COMPILER(GCC) + parameters->filter->platformApplyNeon(parameters->srcPixelArray.get(), parameters->dstPixelArray.get(), + parameters->kernelSizeX, parameters->kernelSizeY, paintSize); +#else + parameters->filter->platformApplyGeneric(parameters->srcPixelArray.get(), parameters->dstPixelArray.get(), + parameters->kernelSizeX, parameters->kernelSizeY, paintSize); +#endif +} + +inline void FEGaussianBlur::platformApply(ByteArray* srcPixelArray, ByteArray* tmpPixelArray, unsigned kernelSizeX, unsigned kernelSizeY, IntSize& paintSize) +{ + int scanline = 4 * paintSize.width(); + int extraHeight = 3 * kernelSizeY * 0.5f; + int optimalThreadNumber = (paintSize.width() * paintSize.height()) / (s_minimalRectDimension + extraHeight * paintSize.width()); + + if (optimalThreadNumber > 1) { + WTF::ParallelJobs<PlatformApplyParameters> parallelJobs(&platformApplyWorker, optimalThreadNumber); + + int jobs = parallelJobs.numberOfJobs(); + if (jobs > 1) { + int blockHeight = paintSize.height() / jobs; + --jobs; + for (int job = jobs; job >= 0; --job) { + PlatformApplyParameters& params = parallelJobs.parameter(job); + params.filter = this; + + int startY; + int endY; + if (!job) { + startY = 0; + endY = blockHeight + extraHeight; + params.srcPixelArray = srcPixelArray; + params.dstPixelArray = tmpPixelArray; + } else { + if (job == jobs) { + startY = job * blockHeight - extraHeight; + endY = paintSize.height(); + } else { + startY = job * blockHeight - extraHeight; + endY = (job + 1) * blockHeight + extraHeight; + } + + int blockSize = (endY - startY) * scanline; + params.srcPixelArray = ByteArray::create(blockSize); + params.dstPixelArray = ByteArray::create(blockSize); + memcpy(params.srcPixelArray->data(), srcPixelArray->data() + startY * scanline, blockSize); + } + + params.width = paintSize.width(); + params.height = endY - startY; + params.kernelSizeX = kernelSizeX; + params.kernelSizeY = kernelSizeY; + } + + parallelJobs.execute(); + + // Copy together the parts of the image. + for (int job = jobs; job >= 1; --job) { + PlatformApplyParameters& params = parallelJobs.parameter(job); + int sourceOffset; + int destinationOffset; + int size; + if (job == jobs) { + sourceOffset = extraHeight * scanline; + destinationOffset = job * blockHeight * scanline; + size = (paintSize.height() - job * blockHeight) * scanline; + } else { + sourceOffset = extraHeight * scanline; + destinationOffset = job * blockHeight * scanline; + size = blockHeight * scanline; + } + memcpy(srcPixelArray->data() + destinationOffset, params.srcPixelArray->data() + sourceOffset, size); + } + return; + } + // Fallback to single threaded mode. + } + + // The selection here eventually should happen dynamically on some platforms. +#if CPU(ARM_NEON) && COMPILER(GCC) + platformApplyNeon(srcPixelArray, tmpPixelArray, kernelSizeX, kernelSizeY, paintSize); +#else + platformApplyGeneric(srcPixelArray, tmpPixelArray, kernelSizeX, kernelSizeY, paintSize); +#endif +} + +void FEGaussianBlur::calculateUnscaledKernelSize(unsigned& kernelSizeX, unsigned& kernelSizeY, float stdX, float stdY) +{ + kernelSizeX = 0; + if (stdX) + kernelSizeX = max<unsigned>(2, static_cast<unsigned>(floorf(stdX * gaussianKernelFactor() + 0.5f))); + kernelSizeY = 0; + if (stdY) + kernelSizeY = max<unsigned>(2, static_cast<unsigned>(floorf(stdY * gaussianKernelFactor() + 0.5f))); + + // Limit the kernel size to 1000. A bigger radius won't make a big difference for the result image but + // inflates the absolute paint rect to much. This is compatible with Firefox' behavior. + if (kernelSizeX > gMaxKernelSize) + kernelSizeX = gMaxKernelSize; + if (kernelSizeY > gMaxKernelSize) + kernelSizeY = gMaxKernelSize; +} + +void FEGaussianBlur::calculateKernelSize(Filter* filter, unsigned& kernelSizeX, unsigned& kernelSizeY, float stdX, float stdY) +{ + stdX = filter->applyHorizontalScale(stdX); + stdY = filter->applyVerticalScale(stdY); + + calculateUnscaledKernelSize(kernelSizeX, kernelSizeY, stdX, stdY); +} + +void FEGaussianBlur::determineAbsolutePaintRect() +{ + FloatRect absolutePaintRect = inputEffect(0)->absolutePaintRect(); + if (clipsToBounds()) + absolutePaintRect.intersect(maxEffectRect()); + else + absolutePaintRect.unite(maxEffectRect()); + + unsigned kernelSizeX = 0; + unsigned kernelSizeY = 0; + calculateKernelSize(filter(), kernelSizeX, kernelSizeY, m_stdX, m_stdY); + + // We take the half kernel size and multiply it with three, because we run box blur three times. + absolutePaintRect.inflateX(3 * kernelSizeX * 0.5f); + absolutePaintRect.inflateY(3 * kernelSizeY * 0.5f); + setAbsolutePaintRect(enclosingIntRect(absolutePaintRect)); +} + +void FEGaussianBlur::platformApplySoftware() +{ +#if USE(SKIA) + if (filter()->renderingMode() == Accelerated) { + platformApplySkia(); + return; + } +#endif + + FilterEffect* in = inputEffect(0); + + ByteArray* 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<ByteArray> tmpImageData = ByteArray::create(paintSize.width() * paintSize.height() * 4); + ByteArray* tmpPixelArray = tmpImageData.get(); + + platformApply(srcPixelArray, tmpPixelArray, kernelSizeX, kernelSizeY, paintSize); +} + +void FEGaussianBlur::dump() +{ +} + +TextStream& FEGaussianBlur::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feGaussianBlur"; + FilterEffect::externalRepresentation(ts); + ts << " stdDeviation=\"" << m_stdX << ", " << m_stdY << "\"]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + return ts; +} + +float FEGaussianBlur::calculateStdDeviation(float radius) +{ + // Blur radius represents 2/3 times the kernel size, the dest pixel is half of the radius applied 3 times + return max((radius * 2 / 3.f - 0.5f) / gaussianKernelFactor(), 0.f); +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FEGaussianBlur.h b/Source/WebCore/platform/graphics/filters/FEGaussianBlur.h new file mode 100644 index 000000000..7f6c3bbee --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEGaussianBlur.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEGaussianBlur_h +#define FEGaussianBlur_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" +#include "Filter.h" + +namespace WebCore { + +class FEGaussianBlur : public FilterEffect { +public: + static PassRefPtr<FEGaussianBlur> create(Filter*, float, float); + + float stdDeviationX() const; + void setStdDeviationX(float); + + float stdDeviationY() const; + void setStdDeviationY(float); + + static float calculateStdDeviation(float); + + virtual void platformApplySoftware(); + virtual void dump(); + + virtual void determineAbsolutePaintRect(); + static void calculateKernelSize(Filter*, unsigned& kernelSizeX, unsigned& kernelSizeY, float stdX, float stdY); + static void calculateUnscaledKernelSize(unsigned& kernelSizeX, unsigned& kernelSizeY, float stdX, float stdY); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + static const int s_minimalRectDimension = 100 * 100; // Empirical data limit for parallel jobs + + template<typename Type> + friend class ParallelJobs; + + struct PlatformApplyParameters { + FEGaussianBlur* filter; + RefPtr<ByteArray> srcPixelArray; + RefPtr<ByteArray> dstPixelArray; + int width; + int height; + unsigned kernelSizeX; + unsigned kernelSizeY; + }; + + static void platformApplyWorker(PlatformApplyParameters*); + + FEGaussianBlur(Filter*, float, float); + + static inline void kernelPosition(int boxBlur, unsigned& std, int& dLeft, int& dRight); + inline void platformApply(ByteArray* srcPixelArray, ByteArray* tmpPixelArray, unsigned kernelSizeX, unsigned kernelSizeY, IntSize& paintSize); + + inline void platformApplyGeneric(ByteArray* srcPixelArray, ByteArray* tmpPixelArray, unsigned kernelSizeX, unsigned kernelSizeY, IntSize& paintSize); + inline void platformApplyNeon(ByteArray* srcPixelArray, ByteArray* tmpPixelArray, unsigned kernelSizeX, unsigned kernelSizeY, IntSize& paintSize); + void platformApplySkia(); + + float m_stdX; + float m_stdY; +}; + +inline void FEGaussianBlur::kernelPosition(int boxBlur, unsigned& std, int& dLeft, int& dRight) +{ + // check http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement for details + switch (boxBlur) { + case 0: + if (!(std % 2)) { + dLeft = std / 2 - 1; + dRight = std - dLeft; + } else { + dLeft = std / 2; + dRight = std - dLeft; + } + break; + case 1: + if (!(std % 2)) { + dLeft++; + dRight--; + } + break; + case 2: + if (!(std % 2)) { + dRight++; + std++; + } + break; + } +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEGaussianBlur_h diff --git a/Source/WebCore/platform/graphics/filters/FELighting.cpp b/Source/WebCore/platform/graphics/filters/FELighting.cpp new file mode 100644 index 000000000..e795d3549 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FELighting.cpp @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2010 University of Szeged + * Copyright (C) 2010 Zoltan Herczeg + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FELighting.h" + +#include "FELightingNEON.h" +#include <wtf/ParallelJobs.h> + +namespace WebCore { + +FELighting::FELighting(Filter* filter, LightingType lightingType, const Color& lightingColor, float surfaceScale, + float diffuseConstant, float specularConstant, float specularExponent, + float kernelUnitLengthX, float kernelUnitLengthY, PassRefPtr<LightSource> lightSource) + : FilterEffect(filter) + , m_lightingType(lightingType) + , m_lightSource(lightSource) + , m_lightingColor(lightingColor) + , m_surfaceScale(surfaceScale) + , m_diffuseConstant(diffuseConstant) + , m_specularConstant(specularConstant) + , m_specularExponent(specularExponent) + , m_kernelUnitLengthX(kernelUnitLengthX) + , m_kernelUnitLengthY(kernelUnitLengthY) +{ +} + +const static int cPixelSize = 4; +const static int cAlphaChannelOffset = 3; +const static unsigned char cOpaqueAlpha = static_cast<unsigned char>(0xff); +const static float cFactor1div2 = -1 / 2.f; +const static float cFactor1div3 = -1 / 3.f; +const static float cFactor1div4 = -1 / 4.f; +const static float cFactor2div3 = -2 / 3.f; + +// << 1 is signed multiply by 2 +inline void FELighting::LightingData::topLeft(int offset, IntPoint& normalVector) +{ + int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset)); + offset += widthMultipliedByPixelSize; + int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + int bottomRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset)); + normalVector.setX(-(center << 1) + (right << 1) - bottom + bottomRight); + normalVector.setY(-(center << 1) - right + (bottom << 1) + bottomRight); +} + +inline void FELighting::LightingData::topRow(int offset, IntPoint& normalVector) +{ + int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset)); + int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset)); + offset += widthMultipliedByPixelSize; + int bottomLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset)); + int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + int bottomRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset)); + normalVector.setX(-(left << 1) + (right << 1) - bottomLeft + bottomRight); + normalVector.setY(-left - (center << 1) - right + bottomLeft + (bottom << 1) + bottomRight); +} + +inline void FELighting::LightingData::topRight(int offset, IntPoint& normalVector) +{ + int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset)); + int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + offset += widthMultipliedByPixelSize; + int bottomLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset)); + int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + normalVector.setX(-(left << 1) + (center << 1) - bottomLeft + bottom); + normalVector.setY(-left - (center << 1) + bottomLeft + (bottom << 1)); +} + +inline void FELighting::LightingData::leftColumn(int offset, IntPoint& normalVector) +{ + int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset)); + offset -= widthMultipliedByPixelSize; + int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + int topRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset)); + offset += widthMultipliedByPixelSize << 1; + int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + int bottomRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset)); + normalVector.setX(-top + topRight - (center << 1) + (right << 1) - bottom + bottomRight); + normalVector.setY(-(top << 1) - topRight + (bottom << 1) + bottomRight); +} + +inline void FELighting::LightingData::interior(int offset, IntPoint& normalVector) +{ + int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset)); + int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset)); + offset -= widthMultipliedByPixelSize; + int topLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset)); + int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + int topRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset)); + offset += widthMultipliedByPixelSize << 1; + int bottomLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset)); + int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + int bottomRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset)); + normalVector.setX(-topLeft + topRight - (left << 1) + (right << 1) - bottomLeft + bottomRight); + normalVector.setY(-topLeft - (top << 1) - topRight + bottomLeft + (bottom << 1) + bottomRight); +} + +inline void FELighting::LightingData::rightColumn(int offset, IntPoint& normalVector) +{ + int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset)); + int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + offset -= widthMultipliedByPixelSize; + int topLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset)); + int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + offset += widthMultipliedByPixelSize << 1; + int bottomLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset)); + int bottom = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + normalVector.setX(-topLeft + top - (left << 1) + (center << 1) - bottomLeft + bottom); + normalVector.setY(-topLeft - (top << 1) + bottomLeft + (bottom << 1)); +} + +inline void FELighting::LightingData::bottomLeft(int offset, IntPoint& normalVector) +{ + int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset)); + offset -= widthMultipliedByPixelSize; + int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + int topRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset)); + normalVector.setX(-top + topRight - (center << 1) + (right << 1)); + normalVector.setY(-(top << 1) - topRight + (center << 1) + right); +} + +inline void FELighting::LightingData::bottomRow(int offset, IntPoint& normalVector) +{ + int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset)); + int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + int right = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset)); + offset -= widthMultipliedByPixelSize; + int topLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset)); + int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + int topRight = static_cast<int>(pixels->get(offset + cPixelSize + cAlphaChannelOffset)); + normalVector.setX(-topLeft + topRight - (left << 1) + (right << 1)); + normalVector.setY(-topLeft - (top << 1) - topRight + left + (center << 1) + right); +} + +inline void FELighting::LightingData::bottomRight(int offset, IntPoint& normalVector) +{ + int left = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset)); + int center = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + offset -= widthMultipliedByPixelSize; + int topLeft = static_cast<int>(pixels->get(offset - cPixelSize + cAlphaChannelOffset)); + int top = static_cast<int>(pixels->get(offset + cAlphaChannelOffset)); + normalVector.setX(-topLeft + top - (left << 1) + (center << 1)); + normalVector.setY(-topLeft - (top << 1) + left + (center << 1)); +} + +inline void FELighting::inlineSetPixel(int offset, LightingData& data, LightSource::PaintingData& paintingData, + int lightX, int lightY, float factorX, float factorY, IntPoint& normal2DVector) +{ + m_lightSource->updatePaintingData(paintingData, lightX, lightY, static_cast<float>(data.pixels->get(offset + cAlphaChannelOffset)) * data.surfaceScale); + + float lightStrength; + if (!normal2DVector.x() && !normal2DVector.y()) { + // Normal vector is (0, 0, 1). This is a quite frequent case. + if (m_lightingType == FELighting::DiffuseLighting) + lightStrength = m_diffuseConstant * paintingData.lightVector.z() / paintingData.lightVectorLength; + else { + FloatPoint3D halfwayVector = paintingData.lightVector; + halfwayVector.setZ(halfwayVector.z() + paintingData.lightVectorLength); + float halfwayVectorLength = halfwayVector.length(); + if (m_specularExponent == 1) + lightStrength = m_specularConstant * halfwayVector.z() / halfwayVectorLength; + else + lightStrength = m_specularConstant * powf(halfwayVector.z() / halfwayVectorLength, m_specularExponent); + } + } else { + FloatPoint3D normalVector; + normalVector.setX(factorX * static_cast<float>(normal2DVector.x()) * data.surfaceScale); + normalVector.setY(factorY * static_cast<float>(normal2DVector.y()) * data.surfaceScale); + normalVector.setZ(1); + float normalVectorLength = normalVector.length(); + + if (m_lightingType == FELighting::DiffuseLighting) + lightStrength = m_diffuseConstant * (normalVector * paintingData.lightVector) / (normalVectorLength * paintingData.lightVectorLength); + else { + FloatPoint3D halfwayVector = paintingData.lightVector; + halfwayVector.setZ(halfwayVector.z() + paintingData.lightVectorLength); + float halfwayVectorLength = halfwayVector.length(); + if (m_specularExponent == 1) + lightStrength = m_specularConstant * (normalVector * halfwayVector) / (normalVectorLength * halfwayVectorLength); + else + lightStrength = m_specularConstant * powf((normalVector * halfwayVector) / (normalVectorLength * halfwayVectorLength), m_specularExponent); + } + } + + if (lightStrength > 1) + lightStrength = 1; + if (lightStrength < 0) + lightStrength = 0; + + data.pixels->set(offset, static_cast<unsigned char>(lightStrength * paintingData.colorVector.x())); + data.pixels->set(offset + 1, static_cast<unsigned char>(lightStrength * paintingData.colorVector.y())); + data.pixels->set(offset + 2, static_cast<unsigned char>(lightStrength * paintingData.colorVector.z())); +} + +void FELighting::setPixel(int offset, LightingData& data, LightSource::PaintingData& paintingData, + int lightX, int lightY, float factorX, float factorY, IntPoint& normalVector) +{ + inlineSetPixel(offset, data, paintingData, lightX, lightY, factorX, factorY, normalVector); +} + +inline void FELighting::platformApplyGenericPaint(LightingData& data, LightSource::PaintingData& paintingData, int startY, int endY) +{ + IntPoint normalVector; + int offset = 0; + + for (int y = startY; y < endY; ++y) { + offset = y * data.widthMultipliedByPixelSize + cPixelSize; + for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) { + data.interior(offset, normalVector); + inlineSetPixel(offset, data, paintingData, x, y, cFactor1div4, cFactor1div4, normalVector); + } + } +} + +void FELighting::platformApplyGenericWorker(PlatformApplyGenericParameters* parameters) +{ + parameters->filter->platformApplyGenericPaint(parameters->data, parameters->paintingData, parameters->yStart, parameters->yEnd); +} + +inline void FELighting::platformApplyGeneric(LightingData& data, LightSource::PaintingData& paintingData) +{ + int optimalThreadNumber = ((data.widthDecreasedByOne - 1) * (data.heightDecreasedByOne - 1)) / s_minimalRectDimension; + if (optimalThreadNumber > 1) { + // Initialize parallel jobs + WTF::ParallelJobs<PlatformApplyGenericParameters> parallelJobs(&platformApplyGenericWorker, optimalThreadNumber); + + // Fill the parameter array + int job = parallelJobs.numberOfJobs(); + if (job > 1) { + int yStart = 1; + int yStep = (data.heightDecreasedByOne - 1) / job; + for (--job; job >= 0; --job) { + PlatformApplyGenericParameters& params = parallelJobs.parameter(job); + params.filter = this; + params.data = data; + params.paintingData = paintingData; + params.yStart = yStart; + if (job > 0) { + params.yEnd = yStart + yStep; + yStart += yStep; + } else + params.yEnd = data.heightDecreasedByOne; + } + parallelJobs.execute(); + return; + } + // Fallback to single threaded mode. + } + + platformApplyGenericPaint(data, paintingData, 1, data.heightDecreasedByOne); +} + +inline void FELighting::platformApply(LightingData& data, LightSource::PaintingData& paintingData) +{ + // The selection here eventually should happen dynamically on some platforms. +#if CPU(ARM_NEON) && COMPILER(GCC) + platformApplyNeon(data, paintingData); +#else + platformApplyGeneric(data, paintingData); +#endif +} + +bool FELighting::drawLighting(ByteArray* pixels, int width, int height) +{ + LightSource::PaintingData paintingData; + LightingData data; + + if (!m_lightSource) + return false; + + // FIXME: do something if width or height (or both) is 1 pixel. + // The W3 spec does not define this case. Now the filter just returns. + if (width <= 2 || height <= 2) + return false; + + data.pixels = pixels; + data.surfaceScale = m_surfaceScale / 255.0f; + data.widthMultipliedByPixelSize = width * cPixelSize; + data.widthDecreasedByOne = width - 1; + data.heightDecreasedByOne = height - 1; + paintingData.colorVector = FloatPoint3D(m_lightingColor.red(), m_lightingColor.green(), m_lightingColor.blue()); + m_lightSource->initPaintingData(paintingData); + + // Top/Left corner. + IntPoint normalVector; + int offset = 0; + data.topLeft(offset, normalVector); + setPixel(offset, data, paintingData, 0, 0, cFactor2div3, cFactor2div3, normalVector); + + // Top/Right pixel. + offset = data.widthMultipliedByPixelSize - cPixelSize; + data.topRight(offset, normalVector); + setPixel(offset, data, paintingData, data.widthDecreasedByOne, 0, cFactor2div3, cFactor2div3, normalVector); + + // Bottom/Left pixel. + offset = data.heightDecreasedByOne * data.widthMultipliedByPixelSize; + data.bottomLeft(offset, normalVector); + setPixel(offset, data, paintingData, 0, data.heightDecreasedByOne, cFactor2div3, cFactor2div3, normalVector); + + // Bottom/Right pixel. + offset = height * data.widthMultipliedByPixelSize - cPixelSize; + data.bottomRight(offset, normalVector); + setPixel(offset, data, paintingData, data.widthDecreasedByOne, data.heightDecreasedByOne, cFactor2div3, cFactor2div3, normalVector); + + if (width >= 3) { + // Top row. + offset = cPixelSize; + for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) { + data.topRow(offset, normalVector); + inlineSetPixel(offset, data, paintingData, x, 0, cFactor1div3, cFactor1div2, normalVector); + } + // Bottom row. + offset = data.heightDecreasedByOne * data.widthMultipliedByPixelSize + cPixelSize; + for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) { + data.bottomRow(offset, normalVector); + inlineSetPixel(offset, data, paintingData, x, data.heightDecreasedByOne, cFactor1div3, cFactor1div2, normalVector); + } + } + + if (height >= 3) { + // Left column. + offset = data.widthMultipliedByPixelSize; + for (int y = 1; y < data.heightDecreasedByOne; ++y, offset += data.widthMultipliedByPixelSize) { + data.leftColumn(offset, normalVector); + inlineSetPixel(offset, data, paintingData, 0, y, cFactor1div2, cFactor1div3, normalVector); + } + // Right column. + offset = (data.widthMultipliedByPixelSize << 1) - cPixelSize; + for (int y = 1; y < data.heightDecreasedByOne; ++y, offset += data.widthMultipliedByPixelSize) { + data.rightColumn(offset, normalVector); + inlineSetPixel(offset, data, paintingData, data.widthDecreasedByOne, y, cFactor1div2, cFactor1div3, normalVector); + } + } + + if (width >= 3 && height >= 3) { + // Interior pixels. + platformApply(data, paintingData); + } + + int lastPixel = data.widthMultipliedByPixelSize * height; + if (m_lightingType == DiffuseLighting) { + for (int i = cAlphaChannelOffset; i < lastPixel; i += cPixelSize) + data.pixels->set(i, cOpaqueAlpha); + } else { + for (int i = 0; i < lastPixel; i += cPixelSize) { + unsigned char a1 = data.pixels->get(i); + unsigned char a2 = data.pixels->get(i + 1); + unsigned char a3 = data.pixels->get(i + 2); + // alpha set to set to max(a1, a2, a3) + data.pixels->set(i + 3, a1 >= a2 ? (a1 >= a3 ? a1 : a3) : (a2 >= a3 ? a2 : a3)); + } + } + + return true; +} + +void FELighting::platformApplySoftware() +{ + FilterEffect* in = inputEffect(0); + + ByteArray* srcPixelArray = createUnmultipliedImageResult(); + if (!srcPixelArray) + return; + + setIsAlphaImage(false); + + IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); + in->copyUnmultipliedImage(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()); +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FELighting.h b/Source/WebCore/platform/graphics/filters/FELighting.h new file mode 100644 index 000000000..5426f912c --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FELighting.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2010 University of Szeged + * Copyright (C) 2010 Zoltan Herczeg + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FELighting_h +#define FELighting_h + +#if ENABLE(FILTERS) +#include "Color.h" +#include "Filter.h" +#include "FilterEffect.h" +#include "LightSource.h" +#include "PointLightSource.h" +#include "SpotLightSource.h" +#include <wtf/ByteArray.h> +#include <wtf/Platform.h> + +// Common base class for FEDiffuseLighting and FESpecularLighting + +namespace WebCore { + +struct FELightingPaintingDataForNeon; + +class FELighting : public FilterEffect { +public: + virtual void platformApplySoftware(); + + virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); } + +protected: + static const int s_minimalRectDimension = 100 * 100; // Empirical data limit for parallel jobs + + enum LightingType { + DiffuseLighting, + SpecularLighting + }; + + struct LightingData { + // This structure contains only read-only (SMP safe) data + ByteArray* pixels; + float surfaceScale; + int widthMultipliedByPixelSize; + int widthDecreasedByOne; + int heightDecreasedByOne; + + inline void topLeft(int offset, IntPoint& normalVector); + inline void topRow(int offset, IntPoint& normalVector); + inline void topRight(int offset, IntPoint& normalVector); + inline void leftColumn(int offset, IntPoint& normalVector); + inline void interior(int offset, IntPoint& normalVector); + inline void rightColumn(int offset, IntPoint& normalVector); + inline void bottomLeft(int offset, IntPoint& normalVector); + inline void bottomRow(int offset, IntPoint& normalVector); + inline void bottomRight(int offset, IntPoint& normalVector); + }; + + template<typename Type> + friend class ParallelJobs; + + struct PlatformApplyGenericParameters { + FELighting* filter; + LightingData data; + LightSource::PaintingData paintingData; + int yStart; + int yEnd; + }; + + static void platformApplyGenericWorker(PlatformApplyGenericParameters*); + static void platformApplyNeonWorker(FELightingPaintingDataForNeon*); + + FELighting(Filter*, LightingType, const Color&, float, float, float, float, float, float, PassRefPtr<LightSource>); + + bool drawLighting(ByteArray*, int, int); + inline void inlineSetPixel(int offset, LightingData&, LightSource::PaintingData&, + int lightX, int lightY, float factorX, float factorY, IntPoint& normalVector); + + // Not worth to inline every occurence of setPixel. + void setPixel(int offset, LightingData&, LightSource::PaintingData&, + int lightX, int lightY, float factorX, float factorY, IntPoint& normalVector); + + inline void platformApply(LightingData&, LightSource::PaintingData&); + + inline void platformApplyGenericPaint(LightingData&, LightSource::PaintingData&, int startX, int startY); + inline void platformApplyGeneric(LightingData&, LightSource::PaintingData&); + + static int getPowerCoefficients(float exponent); + inline void platformApplyNeon(LightingData&, LightSource::PaintingData&); + + LightingType m_lightingType; + RefPtr<LightSource> m_lightSource; + + Color m_lightingColor; + float m_surfaceScale; + float m_diffuseConstant; + float m_specularConstant; + float m_specularExponent; + float m_kernelUnitLengthX; + float m_kernelUnitLengthY; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FELighting_h diff --git a/Source/WebCore/platform/graphics/filters/FEMerge.cpp b/Source/WebCore/platform/graphics/filters/FEMerge.cpp new file mode 100644 index 000000000..eddb61a21 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEMerge.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEMerge.h" + +#include "Filter.h" +#include "GraphicsContext.h" +#include "RenderTreeAsText.h" +#include "TextStream.h" + +namespace WebCore { + +FEMerge::FEMerge(Filter* filter) + : FilterEffect(filter) +{ +} + +PassRefPtr<FEMerge> FEMerge::create(Filter* filter) +{ + return adoptRef(new FEMerge(filter)); +} + +void FEMerge::platformApplySoftware() +{ + unsigned size = numberOfEffectInputs(); + ASSERT(size > 0); + + ImageBuffer* resultImage = createImageBufferResult(); + if (!resultImage) + return; + + GraphicsContext* filterContext = resultImage->context(); + for (unsigned i = 0; i < size; ++i) { + FilterEffect* in = inputEffect(i); + filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); + } +} + +void FEMerge::dump() +{ +} + +TextStream& FEMerge::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feMerge"; + FilterEffect::externalRepresentation(ts); + unsigned size = numberOfEffectInputs(); + ASSERT(size > 0); + ts << " mergeNodes=\"" << size << "\"]\n"; + for (unsigned i = 0; i < size; ++i) + inputEffect(i)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FEMerge.h b/Source/WebCore/platform/graphics/filters/FEMerge.h new file mode 100644 index 000000000..302336b63 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEMerge.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEMerge_h +#define FEMerge_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" +#include "Filter.h" +#include <wtf/Vector.h> + +namespace WebCore { + +class FEMerge : public FilterEffect { +public: + static PassRefPtr<FEMerge> create(Filter*); + + virtual void platformApplySoftware(); + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEMerge(Filter*); +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEMerge_h diff --git a/Source/WebCore/platform/graphics/filters/FEMorphology.cpp b/Source/WebCore/platform/graphics/filters/FEMorphology.cpp new file mode 100644 index 000000000..5ba4dfc14 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEMorphology.cpp @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEMorphology.h" + +#include "Filter.h" +#include "RenderTreeAsText.h" +#include "TextStream.h" + +#include <wtf/ByteArray.h> +#include <wtf/ParallelJobs.h> +#include <wtf/Vector.h> + +using std::min; +using std::max; + +namespace WebCore { + +FEMorphology::FEMorphology(Filter* filter, MorphologyOperatorType type, float radiusX, float radiusY) + : FilterEffect(filter) + , m_type(type) + , m_radiusX(radiusX) + , m_radiusY(radiusY) +{ +} + +PassRefPtr<FEMorphology> FEMorphology::create(Filter* filter, MorphologyOperatorType type, float radiusX, float radiusY) +{ + return adoptRef(new FEMorphology(filter, type, radiusX, radiusY)); +} + +MorphologyOperatorType FEMorphology::morphologyOperator() const +{ + return m_type; +} + +bool FEMorphology::setMorphologyOperator(MorphologyOperatorType type) +{ + if (m_type == type) + return false; + m_type = type; + return true; +} + +float FEMorphology::radiusX() const +{ + return m_radiusX; +} + +bool FEMorphology::setRadiusX(float radiusX) +{ + if (m_radiusX == radiusX) + return false; + m_radiusX = radiusX; + return true; +} + +float FEMorphology::radiusY() const +{ + return m_radiusY; +} + +void FEMorphology::determineAbsolutePaintRect() +{ + FloatRect paintRect = inputEffect(0)->absolutePaintRect(); + Filter* filter = this->filter(); + paintRect.inflateX(filter->applyHorizontalScale(m_radiusX)); + paintRect.inflateY(filter->applyVerticalScale(m_radiusY)); + if (clipsToBounds()) + paintRect.intersect(maxEffectRect()); + else + paintRect.unite(maxEffectRect()); + setAbsolutePaintRect(enclosingIntRect(paintRect)); +} + +bool FEMorphology::setRadiusY(float radiusY) +{ + if (m_radiusY == radiusY) + return false; + m_radiusY = radiusY; + return true; +} + +void FEMorphology::platformApplyGeneric(PaintingData* paintingData, int yStart, int yEnd) +{ + ByteArray* srcPixelArray = paintingData->srcPixelArray; + ByteArray* dstPixelArray = paintingData->dstPixelArray; + const int width = paintingData->width; + const int height = paintingData->height; + const int effectWidth = width * 4; + const int radiusX = paintingData->radiusX; + const int radiusY = paintingData->radiusY; + + Vector<unsigned char> extrema; + for (int y = yStart; y < yEnd; ++y) { + int extremaStartY = max(0, y - radiusY); + int extremaEndY = min(height - 1, y + radiusY); + for (unsigned int clrChannel = 0; clrChannel < 4; ++clrChannel) { + extrema.clear(); + // Compute extremas for each columns + for (int x = 0; x <= radiusX; ++x) { + unsigned char columnExtrema = srcPixelArray->get(extremaStartY * effectWidth + 4 * x + clrChannel); + for (int eY = extremaStartY + 1; eY < extremaEndY; ++eY) { + unsigned char pixel = srcPixelArray->get(eY * effectWidth + 4 * x + clrChannel); + 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 < width; ++x) { + const int endX = min(x + radiusX, width - 1); + unsigned char columnExtrema = srcPixelArray->get(extremaStartY * effectWidth + endX * 4 + clrChannel); + for (int i = extremaStartY + 1; i <= extremaEndY; ++i) { + unsigned char pixel = srcPixelArray->get(i * effectWidth + endX * 4 + clrChannel); + 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 <= width) + extrema.append(columnExtrema); + + unsigned char entireExtrema = extrema[0]; + for (unsigned kernelIndex = 1; kernelIndex < extrema.size(); ++kernelIndex) { + if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && extrema[kernelIndex] <= entireExtrema) + || (m_type == FEMORPHOLOGY_OPERATOR_DILATE && extrema[kernelIndex] >= entireExtrema)) + entireExtrema = extrema[kernelIndex]; + } + dstPixelArray->set(y * effectWidth + 4 * x + clrChannel, entireExtrema); + } + } + } +} + +void FEMorphology::platformApplyWorker(PlatformApplyParameters* param) +{ + param->filter->platformApplyGeneric(param->paintingData, param->startY, param->endY); +} + +void FEMorphology::platformApply(PaintingData* paintingData) +{ + int optimalThreadNumber = (paintingData->width * paintingData->height) / s_minimalArea; + if (optimalThreadNumber > 1) { + ParallelJobs<PlatformApplyParameters> parallelJobs(&WebCore::FEMorphology::platformApplyWorker, optimalThreadNumber); + int numOfThreads = parallelJobs.numberOfJobs(); + if (numOfThreads > 1) { + const int deltaY = 1 + paintingData->height / numOfThreads; + int currentY = 0; + for (int job = numOfThreads - 1; job >= 0; --job) { + PlatformApplyParameters& param = parallelJobs.parameter(job); + param.filter = this; + param.startY = currentY; + currentY += deltaY; + param.endY = job ? currentY : paintingData->height; + param.paintingData = paintingData; + } + parallelJobs.execute(); + return; + } + // Fallback to single thread model + } + + platformApplyGeneric(paintingData, 0, paintingData->height); +} + + +void FEMorphology::platformApplySoftware() +{ + FilterEffect* in = inputEffect(0); + + ByteArray* dstPixelArray = createPremultipliedImageResult(); + if (!dstPixelArray) + return; + + setIsAlphaImage(in->isAlphaImage()); + if (m_radiusX <= 0 || m_radiusY <= 0) { + dstPixelArray->clear(); + 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<ByteArray> srcPixelArray = in->asPremultipliedImage(effectDrawingRect); + + PaintingData paintingData; + paintingData.srcPixelArray = srcPixelArray.get(); + paintingData.dstPixelArray = dstPixelArray; + paintingData.width = effectDrawingRect.width(); + paintingData.height = effectDrawingRect.height(); + paintingData.radiusX = min(effectDrawingRect.width() - 1, radiusX); + paintingData.radiusY = min(effectDrawingRect.height() - 1, radiusY); + + platformApply(&paintingData); +} + +void FEMorphology::dump() +{ +} + +static TextStream& operator<<(TextStream& ts, const MorphologyOperatorType& type) +{ + switch (type) { + case FEMORPHOLOGY_OPERATOR_UNKNOWN: + ts << "UNKNOWN"; + break; + case FEMORPHOLOGY_OPERATOR_ERODE: + ts << "ERODE"; + break; + case FEMORPHOLOGY_OPERATOR_DILATE: + ts << "DILATE"; + break; + } + return ts; +} + +TextStream& FEMorphology::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feMorphology"; + FilterEffect::externalRepresentation(ts); + ts << " operator=\"" << morphologyOperator() << "\" " + << "radius=\"" << radiusX() << ", " << radiusY() << "\"]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FEMorphology.h b/Source/WebCore/platform/graphics/filters/FEMorphology.h new file mode 100644 index 000000000..f92540342 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEMorphology.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEMorphology_h +#define FEMorphology_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" +#include "Filter.h" + +namespace WebCore { + +enum MorphologyOperatorType { + FEMORPHOLOGY_OPERATOR_UNKNOWN = 0, + FEMORPHOLOGY_OPERATOR_ERODE = 1, + FEMORPHOLOGY_OPERATOR_DILATE = 2 +}; + +class FEMorphology : public FilterEffect { +public: + static PassRefPtr<FEMorphology> create(Filter*, MorphologyOperatorType, float radiusX, float radiusY); + MorphologyOperatorType morphologyOperator() const; + bool setMorphologyOperator(MorphologyOperatorType); + + float radiusX() const; + bool setRadiusX(float); + + float radiusY() const; + bool setRadiusY(float); + + virtual void platformApplySoftware(); + virtual void dump(); + + virtual void determineAbsolutePaintRect(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + + struct PaintingData { + ByteArray* srcPixelArray; + ByteArray* dstPixelArray; + int width; + int height; + int radiusX; + int radiusY; + }; + + static const int s_minimalArea = (300 * 300); // Empirical data limit for parallel jobs + + struct PlatformApplyParameters { + FEMorphology* filter; + int startY; + int endY; + PaintingData* paintingData; + }; + + static void platformApplyWorker(PlatformApplyParameters*); + + inline void platformApply(PaintingData*); + inline void platformApplyGeneric(PaintingData*, const int yStart, const int yEnd); +private: + FEMorphology(Filter*, MorphologyOperatorType, float radiusX, float radiusY); + + MorphologyOperatorType m_type; + float m_radiusX; + float m_radiusY; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEMorphology_h diff --git a/Source/WebCore/platform/graphics/filters/FEOffset.cpp b/Source/WebCore/platform/graphics/filters/FEOffset.cpp new file mode 100644 index 000000000..ef2c46683 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEOffset.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEOffset.h" + +#include "Filter.h" +#include "GraphicsContext.h" +#include "RenderTreeAsText.h" +#include "TextStream.h" + +namespace WebCore { + +FEOffset::FEOffset(Filter* filter, float dx, float dy) + : FilterEffect(filter) + , m_dx(dx) + , m_dy(dy) +{ +} + +PassRefPtr<FEOffset> FEOffset::create(Filter* filter, float dx, float dy) +{ + return adoptRef(new FEOffset(filter, dx, dy)); +} + +float FEOffset::dx() const +{ + return m_dx; +} + +void FEOffset::setDx(float dx) +{ + m_dx = dx; +} + +float FEOffset::dy() const +{ + return m_dy; +} + +void FEOffset::setDy(float dy) +{ + m_dy = dy; +} + +void FEOffset::determineAbsolutePaintRect() +{ + FloatRect paintRect = inputEffect(0)->absolutePaintRect(); + Filter* filter = this->filter(); + paintRect.move(filter->applyHorizontalScale(m_dx), filter->applyVerticalScale(m_dy)); + if (clipsToBounds()) + paintRect.intersect(maxEffectRect()); + else + paintRect.unite(maxEffectRect()); + setAbsolutePaintRect(enclosingIntRect(paintRect)); +} + +void FEOffset::platformApplySoftware() +{ + 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(), ColorSpaceDeviceRGB, drawingRegion); +} + +void FEOffset::dump() +{ +} + +TextStream& FEOffset::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feOffset"; + FilterEffect::externalRepresentation(ts); + ts << " dx=\"" << dx() << "\" dy=\"" << dy() << "\"]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FEOffset.h b/Source/WebCore/platform/graphics/filters/FEOffset.h new file mode 100644 index 000000000..e75febd9c --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FEOffset.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEOffset_h +#define FEOffset_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" +#include "Filter.h" + +namespace WebCore { + +class FEOffset : public FilterEffect { +public: + static PassRefPtr<FEOffset> create(Filter*, float dx, float dy); + + float dx() const; + void setDx(float); + + float dy() const; + void setDy(float); + + virtual void platformApplySoftware(); + virtual void dump(); + + virtual void determineAbsolutePaintRect(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FEOffset(Filter*, float dx, float dy); + + float m_dx; + float m_dy; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEOffset_h diff --git a/Source/WebCore/platform/graphics/filters/FESpecularLighting.cpp b/Source/WebCore/platform/graphics/filters/FESpecularLighting.cpp new file mode 100644 index 000000000..2c7b1ebf9 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FESpecularLighting.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FESpecularLighting.h" + +#include "LightSource.h" +#include "RenderTreeAsText.h" +#include "TextStream.h" + +namespace WebCore { + +FESpecularLighting::FESpecularLighting(Filter* filter, const Color& lightingColor, float surfaceScale, + float specularConstant, float specularExponent, float kernelUnitLengthX, + float kernelUnitLengthY, PassRefPtr<LightSource> lightSource) + : FELighting(filter, SpecularLighting, lightingColor, surfaceScale, 0, specularConstant, specularExponent, kernelUnitLengthX, kernelUnitLengthY, lightSource) +{ +} + +PassRefPtr<FESpecularLighting> FESpecularLighting::create(Filter* filter, const Color& lightingColor, + float surfaceScale, float specularConstant, float specularExponent, + float kernelUnitLengthX, float kernelUnitLengthY, PassRefPtr<LightSource> lightSource) +{ + return adoptRef(new FESpecularLighting(filter, lightingColor, surfaceScale, specularConstant, specularExponent, + kernelUnitLengthX, kernelUnitLengthY, lightSource)); +} + +FESpecularLighting::~FESpecularLighting() +{ +} + +Color FESpecularLighting::lightingColor() const +{ + return m_lightingColor; +} + +bool FESpecularLighting::setLightingColor(const Color& lightingColor) +{ + if (m_lightingColor == lightingColor) + return false; + m_lightingColor = lightingColor; + return true; +} + +float FESpecularLighting::surfaceScale() const +{ + return m_surfaceScale; +} + +bool FESpecularLighting::setSurfaceScale(float surfaceScale) +{ + if (m_surfaceScale == surfaceScale) + return false; + m_surfaceScale = surfaceScale; + return true; +} + +float FESpecularLighting::specularConstant() const +{ + return m_specularConstant; +} + +bool FESpecularLighting::setSpecularConstant(float specularConstant) +{ + if (m_specularConstant == specularConstant) + return false; + m_specularConstant = specularConstant; + return true; +} + +float FESpecularLighting::specularExponent() const +{ + return m_specularExponent; +} + +bool FESpecularLighting::setSpecularExponent(float specularExponent) +{ + if (m_specularExponent == specularExponent) + return false; + m_specularExponent = specularExponent; + return true; +} + +float FESpecularLighting::kernelUnitLengthX() const +{ + return m_kernelUnitLengthX; +} + +bool FESpecularLighting::setKernelUnitLengthX(float kernelUnitLengthX) +{ + if (m_kernelUnitLengthX == kernelUnitLengthX) + return false; + m_kernelUnitLengthX = kernelUnitLengthX; + return true; +} + +float FESpecularLighting::kernelUnitLengthY() const +{ + return m_kernelUnitLengthY; +} + +bool FESpecularLighting::setKernelUnitLengthY(float kernelUnitLengthY) +{ + if (m_kernelUnitLengthY == kernelUnitLengthY) + return false; + m_kernelUnitLengthY = kernelUnitLengthY; + return true; +} + +const LightSource* FESpecularLighting::lightSource() const +{ + return m_lightSource.get(); +} + +void FESpecularLighting::setLightSource(PassRefPtr<LightSource> lightSource) +{ + m_lightSource = lightSource; +} + +void FESpecularLighting::dump() +{ +} + +TextStream& FESpecularLighting::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feSpecularLighting"; + FilterEffect::externalRepresentation(ts); + ts << " surfaceScale=\"" << m_surfaceScale << "\" " + << "specualConstant=\"" << m_specularConstant << "\" " + << "specularExponent=\"" << m_specularExponent << "\"]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FESpecularLighting.h b/Source/WebCore/platform/graphics/filters/FESpecularLighting.h new file mode 100644 index 000000000..9fa3addac --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FESpecularLighting.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FESpecularLighting_h +#define FESpecularLighting_h + +#if ENABLE(FILTERS) +#include "FELighting.h" + +namespace WebCore { + +class FESpecularLighting : public FELighting { +public: + static PassRefPtr<FESpecularLighting> create(Filter*, const Color&, float, float, + float, float, float, PassRefPtr<LightSource>); + virtual ~FESpecularLighting(); + + Color lightingColor() const; + bool setLightingColor(const Color&); + + float surfaceScale() const; + bool setSurfaceScale(float); + + float specularConstant() const; + bool setSpecularConstant(float); + + float specularExponent() const; + bool setSpecularExponent(float); + + float kernelUnitLengthX() const; + bool setKernelUnitLengthX(float); + + float kernelUnitLengthY() const; + bool setKernelUnitLengthY(float); + + const LightSource* lightSource() const; + void setLightSource(PassRefPtr<LightSource>); + + virtual void dump(); + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FESpecularLighting(Filter*, const Color&, float, float, float, float, float, PassRefPtr<LightSource>); +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FESpecularLighting_h diff --git a/Source/WebCore/platform/graphics/filters/FETile.cpp b/Source/WebCore/platform/graphics/filters/FETile.cpp new file mode 100644 index 000000000..a6e1da334 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FETile.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FETile.h" + +#include "AffineTransform.h" +#include "Filter.h" +#include "GraphicsContext.h" +#include "Pattern.h" +#include "RenderTreeAsText.h" +#include "SVGImageBufferTools.h" +#include "TextStream.h" + +namespace WebCore { + +FETile::FETile(Filter* filter) + : FilterEffect(filter) +{ +} + +PassRefPtr<FETile> FETile::create(Filter* filter) +{ + return adoptRef(new FETile(filter)); +} + +void FETile::platformApplySoftware() +{ +// 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); + + 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->filterRegion(); + tileRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); + } + + OwnPtr<ImageBuffer> tileImage; + if (!SVGImageBufferTools::createImageBuffer(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())); +#endif +} + +void FETile::dump() +{ +} + +TextStream& FETile::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feTile"; + FilterEffect::externalRepresentation(ts); + ts << "]\n"; + inputEffect(0)->externalRepresentation(ts, indent + 1); + + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FETile.h b/Source/WebCore/platform/graphics/filters/FETile.h new file mode 100644 index 000000000..633276a3e --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FETile.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FETile_h +#define FETile_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" +#include "Filter.h" + +namespace WebCore { + +class FETile : public FilterEffect { +public: + static PassRefPtr<FETile> create(Filter* filter); + + virtual void platformApplySoftware(); + virtual void dump(); + + virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); } + + virtual FilterEffectType filterEffectType() const { return FilterEffectTypeTile; } + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + FETile(Filter*); +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FETile_h diff --git a/Source/WebCore/platform/graphics/filters/FETurbulence.cpp b/Source/WebCore/platform/graphics/filters/FETurbulence.cpp new file mode 100644 index 000000000..3ca45717e --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FETurbulence.cpp @@ -0,0 +1,447 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2010 Renata Hodovan <reni@inf.u-szeged.hu> + * Copyright (C) 2011 Gabor Loki <loki@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FETurbulence.h" + +#include "Filter.h" +#include "RenderTreeAsText.h" +#include "TextStream.h" + +#include <wtf/ByteArray.h> +#include <wtf/MathExtras.h> +#include <wtf/ParallelJobs.h> + +namespace WebCore { + +/* + Produces results in the range [1, 2**31 - 2]. Algorithm is: + r = (a * r) mod m where a = randAmplitude = 16807 and + m = randMaximum = 2**31 - 1 = 2147483647, r = seed. + See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988 + To test: the algorithm should produce the result 1043618065 + as the 10,000th generated number if the original seed is 1. +*/ +static const int s_perlinNoise = 4096; +static const long s_randMaximum = 2147483647; // 2**31 - 1 +static const int s_randAmplitude = 16807; // 7**5; primitive root of m +static const int s_randQ = 127773; // m / a +static const int s_randR = 2836; // m % a + +FETurbulence::FETurbulence(Filter* filter, TurbulenceType type, float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed, bool stitchTiles) + : FilterEffect(filter) + , m_type(type) + , m_baseFrequencyX(baseFrequencyX) + , m_baseFrequencyY(baseFrequencyY) + , m_numOctaves(numOctaves) + , m_seed(seed) + , m_stitchTiles(stitchTiles) +{ +} + +PassRefPtr<FETurbulence> FETurbulence::create(Filter* filter, TurbulenceType type, float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed, bool stitchTiles) +{ + return adoptRef(new FETurbulence(filter, type, baseFrequencyX, baseFrequencyY, numOctaves, seed, stitchTiles)); +} + +TurbulenceType FETurbulence::type() const +{ + return m_type; +} + +bool FETurbulence::setType(TurbulenceType type) +{ + if (m_type == type) + return false; + m_type = type; + return true; +} + +float FETurbulence::baseFrequencyY() const +{ + return m_baseFrequencyY; +} + +bool FETurbulence::setBaseFrequencyY(float baseFrequencyY) +{ + if (m_baseFrequencyY == baseFrequencyY) + return false; + m_baseFrequencyY = baseFrequencyY; + return true; +} + +float FETurbulence::baseFrequencyX() const +{ + return m_baseFrequencyX; +} + +bool FETurbulence::setBaseFrequencyX(float baseFrequencyX) +{ + if (m_baseFrequencyX == baseFrequencyX) + return false; + m_baseFrequencyX = baseFrequencyX; + return true; +} + +float FETurbulence::seed() const +{ + return m_seed; +} + +bool FETurbulence::setSeed(float seed) +{ + if (m_seed == seed) + return false; + m_seed = seed; + return true; +} + +int FETurbulence::numOctaves() const +{ + return m_numOctaves; +} + +bool FETurbulence::setNumOctaves(int numOctaves) +{ + if (m_numOctaves == numOctaves) + return false; + m_numOctaves = numOctaves; + return true; +} + +bool FETurbulence::stitchTiles() const +{ + return m_stitchTiles; +} + +bool FETurbulence::setStitchTiles(bool stitch) +{ + if (m_stitchTiles == stitch) + return false; + m_stitchTiles = stitch; + return true; +} + +// The turbulence calculation code is an adapted version of what appears in the SVG 1.1 specification: +// http://www.w3.org/TR/SVG11/filters.html#feTurbulence + +FETurbulence::PaintingData::PaintingData(long paintingSeed, const IntSize& paintingSize) + : seed(paintingSeed) + , width(0) + , height(0) + , wrapX(0) + , wrapY(0) + , filterSize(paintingSize) +{ +} + +// Compute pseudo random number. +inline long FETurbulence::PaintingData::random() +{ + long result = s_randAmplitude * (seed % s_randQ) - s_randR * (seed / s_randQ); + if (result <= 0) + result += s_randMaximum; + seed = result; + return result; +} + +inline float smoothCurve(float t) +{ + return t * t * (3 - 2 * t); +} + +inline float linearInterpolation(float t, float a, float b) +{ + return a + t * (b - a); +} + +inline void FETurbulence::initPaint(PaintingData& paintingData) +{ + float normalizationFactor; + + // The seed value clamp to the range [1, s_randMaximum - 1]. + if (paintingData.seed <= 0) + paintingData.seed = -(paintingData.seed % (s_randMaximum - 1)) + 1; + if (paintingData.seed > s_randMaximum - 1) + paintingData.seed = s_randMaximum - 1; + + float* gradient; + for (int channel = 0; channel < 4; ++channel) { + for (int i = 0; i < s_blockSize; ++i) { + paintingData.latticeSelector[i] = i; + gradient = paintingData.gradient[channel][i]; + gradient[0] = static_cast<float>((paintingData.random() % (2 * s_blockSize)) - s_blockSize) / s_blockSize; + gradient[1] = static_cast<float>((paintingData.random() % (2 * s_blockSize)) - s_blockSize) / s_blockSize; + normalizationFactor = sqrtf(gradient[0] * gradient[0] + gradient[1] * gradient[1]); + gradient[0] /= normalizationFactor; + gradient[1] /= normalizationFactor; + } + } + for (int i = s_blockSize - 1; i > 0; --i) { + int k = paintingData.latticeSelector[i]; + int j = paintingData.random() % s_blockSize; + ASSERT(j >= 0); + ASSERT(j < 2 * s_blockSize + 2); + paintingData.latticeSelector[i] = paintingData.latticeSelector[j]; + paintingData.latticeSelector[j] = k; + } + for (int i = 0; i < s_blockSize + 2; ++i) { + paintingData.latticeSelector[s_blockSize + i] = paintingData.latticeSelector[i]; + for (int channel = 0; channel < 4; ++channel) { + paintingData.gradient[channel][s_blockSize + i][0] = paintingData.gradient[channel][i][0]; + paintingData.gradient[channel][s_blockSize + i][1] = paintingData.gradient[channel][i][1]; + } + } +} + +inline void checkNoise(int& noiseValue, int limitValue, int newValue) +{ + if (noiseValue >= limitValue) + noiseValue -= newValue; + if (noiseValue >= limitValue - 1) + noiseValue -= newValue - 1; +} + +float FETurbulence::noise2D(int channel, PaintingData& paintingData, const FloatPoint& noiseVector) +{ + struct Noise { + int noisePositionIntegerValue; + float noisePositionFractionValue; + + Noise(float component) + { + float position = component + s_perlinNoise; + noisePositionIntegerValue = static_cast<int>(position); + noisePositionFractionValue = position - noisePositionIntegerValue; + } + }; + + Noise noiseX(noiseVector.x()); + Noise noiseY(noiseVector.y()); + float* q; + float sx, sy, a, b, u, v; + + // If stitching, adjust lattice points accordingly. + if (m_stitchTiles) { + checkNoise(noiseX.noisePositionIntegerValue, paintingData.wrapX, paintingData.width); + checkNoise(noiseY.noisePositionIntegerValue, paintingData.wrapY, paintingData.height); + } + + noiseX.noisePositionIntegerValue &= s_blockMask; + noiseY.noisePositionIntegerValue &= s_blockMask; + int latticeIndex = paintingData.latticeSelector[noiseX.noisePositionIntegerValue]; + int nextLatticeIndex = paintingData.latticeSelector[(noiseX.noisePositionIntegerValue + 1) & s_blockMask]; + + sx = smoothCurve(noiseX.noisePositionFractionValue); + sy = smoothCurve(noiseY.noisePositionFractionValue); + + // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement. + int temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue]; + q = paintingData.gradient[channel][temp]; + u = noiseX.noisePositionFractionValue * q[0] + noiseY.noisePositionFractionValue * q[1]; + temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue]; + q = paintingData.gradient[channel][temp]; + v = (noiseX.noisePositionFractionValue - 1) * q[0] + noiseY.noisePositionFractionValue * q[1]; + a = linearInterpolation(sx, u, v); + temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue + 1]; + q = paintingData.gradient[channel][temp]; + u = noiseX.noisePositionFractionValue * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1]; + temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue + 1]; + q = paintingData.gradient[channel][temp]; + v = (noiseX.noisePositionFractionValue - 1) * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1]; + b = linearInterpolation(sx, u, v); + return linearInterpolation(sy, a, b); +} + +unsigned char FETurbulence::calculateTurbulenceValueForPoint(int channel, PaintingData& paintingData, const FloatPoint& point) +{ + float tileWidth = paintingData.filterSize.width(); + ASSERT(tileWidth > 0); + float tileHeight = paintingData.filterSize.height(); + ASSERT(tileHeight > 0); + // Adjust the base frequencies if necessary for stitching. + if (m_stitchTiles) { + // When stitching tiled turbulence, the frequencies must be adjusted + // so that the tile borders will be continuous. + if (m_baseFrequencyX) { + float lowFrequency = floorf(tileWidth * m_baseFrequencyX) / tileWidth; + float highFrequency = ceilf(tileWidth * m_baseFrequencyX) / tileWidth; + // BaseFrequency should be non-negative according to the standard. + if (m_baseFrequencyX / lowFrequency < highFrequency / m_baseFrequencyX) + m_baseFrequencyX = lowFrequency; + else + m_baseFrequencyX = highFrequency; + } + if (m_baseFrequencyY) { + float lowFrequency = floorf(tileHeight * m_baseFrequencyY) / tileHeight; + float highFrequency = ceilf(tileHeight * m_baseFrequencyY) / tileHeight; + if (m_baseFrequencyY / lowFrequency < highFrequency / m_baseFrequencyY) + m_baseFrequencyY = lowFrequency; + else + m_baseFrequencyY = highFrequency; + } + // Set up TurbulenceInitial stitch values. + paintingData.width = roundf(tileWidth * m_baseFrequencyX); + paintingData.wrapX = s_perlinNoise + paintingData.width; + paintingData.height = roundf(tileHeight * m_baseFrequencyY); + paintingData.wrapY = s_perlinNoise + paintingData.height; + } + float turbulenceFunctionResult = 0; + FloatPoint noiseVector(point.x() * m_baseFrequencyX, point.y() * m_baseFrequencyY); + float ratio = 1; + for (int octave = 0; octave < m_numOctaves; ++octave) { + if (m_type == FETURBULENCE_TYPE_FRACTALNOISE) + turbulenceFunctionResult += noise2D(channel, paintingData, noiseVector) / ratio; + else + turbulenceFunctionResult += fabsf(noise2D(channel, paintingData, noiseVector)) / ratio; + noiseVector.setX(noiseVector.x() * 2); + noiseVector.setY(noiseVector.y() * 2); + ratio *= 2; + if (m_stitchTiles) { + // Update stitch values. Subtracting s_perlinNoiseoise before the multiplication and + // adding it afterward simplifies to subtracting it once. + paintingData.width *= 2; + paintingData.wrapX = 2 * paintingData.wrapX - s_perlinNoise; + paintingData.height *= 2; + paintingData.wrapY = 2 * paintingData.wrapY - s_perlinNoise; + } + } + + // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult * 255) + 255) / 2 by fractalNoise + // and (turbulenceFunctionResult * 255) by turbulence. + if (m_type == FETURBULENCE_TYPE_FRACTALNOISE) + turbulenceFunctionResult = turbulenceFunctionResult * 0.5f + 0.5f; + // Clamp result + turbulenceFunctionResult = std::max(std::min(turbulenceFunctionResult, 1.f), 0.f); + return static_cast<unsigned char>(turbulenceFunctionResult * 255); +} + +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))); + } + } +} + +void FETurbulence::fillRegionWorker(FillRegionParameters* parameters) +{ + parameters->filter->fillRegion(parameters->pixelArray, *parameters->paintingData, parameters->startY, parameters->endY); +} + +void FETurbulence::platformApplySoftware() +{ + ByteArray* pixelArray = createUnmultipliedImageResult(); + if (!pixelArray) + return; + + if (absolutePaintRect().isEmpty()) { + pixelArray->clear(); + return; + } + + PaintingData paintingData(m_seed, roundedIntSize(filterPrimitiveSubregion().size())); + initPaint(paintingData); + + int optimalThreadNumber = (absolutePaintRect().width() * absolutePaintRect().height()) / s_minimalRectDimension; + if (optimalThreadNumber > 1) { + // Initialize parallel jobs + WTF::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 single threaded mode if there is no room for a new thread or the paint area is too small. + fillRegion(pixelArray, paintingData, 0, absolutePaintRect().height()); +} + +void FETurbulence::dump() +{ +} + +static TextStream& operator<<(TextStream& ts, const TurbulenceType& type) +{ + switch (type) { + case FETURBULENCE_TYPE_UNKNOWN: + ts << "UNKNOWN"; + break; + case FETURBULENCE_TYPE_TURBULENCE: + ts << "TURBULANCE"; + break; + case FETURBULENCE_TYPE_FRACTALNOISE: + ts << "NOISE"; + break; + } + return ts; +} + +TextStream& FETurbulence::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feTurbulence"; + FilterEffect::externalRepresentation(ts); + ts << " type=\"" << type() << "\" " + << "baseFrequency=\"" << baseFrequencyX() << ", " << baseFrequencyY() << "\" " + << "seed=\"" << seed() << "\" " + << "numOctaves=\"" << numOctaves() << "\" " + << "stitchTiles=\"" << stitchTiles() << "\"]\n"; + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FETurbulence.h b/Source/WebCore/platform/graphics/filters/FETurbulence.h new file mode 100644 index 000000000..01d3c597a --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FETurbulence.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2010 Renata Hodovan <reni@inf.u-szeged.hu> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FETurbulence_h +#define FETurbulence_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" +#include "Filter.h" + +namespace WebCore { + +enum TurbulenceType { + FETURBULENCE_TYPE_UNKNOWN = 0, + FETURBULENCE_TYPE_FRACTALNOISE = 1, + FETURBULENCE_TYPE_TURBULENCE = 2 +}; + +class FETurbulence : public FilterEffect { +public: + static PassRefPtr<FETurbulence> create(Filter*, TurbulenceType, float, float, int, float, bool); + + TurbulenceType type() const; + bool setType(TurbulenceType); + + float baseFrequencyY() const; + bool setBaseFrequencyY(float); + + float baseFrequencyX() const; + bool setBaseFrequencyX(float); + + float seed() const; + bool setSeed(float); + + int numOctaves() const; + bool setNumOctaves(int); + + bool stitchTiles() const; + bool setStitchTiles(bool); + + static void fillRegionWorker(void*); + + virtual void platformApplySoftware(); + virtual void dump(); + + virtual void determineAbsolutePaintRect() { setAbsolutePaintRect(enclosingIntRect(maxEffectRect())); } + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + static const int s_blockSize = 256; + static const int s_blockMask = s_blockSize - 1; + + static const int s_minimalRectDimension = (100 * 100); // Empirical data limit for parallel jobs. + + struct PaintingData { + long seed; + int latticeSelector[2 * s_blockSize + 2]; + float gradient[4][2 * s_blockSize + 2][2]; + int width; // How much to subtract to wrap for stitching. + int height; + int wrapX; // Minimum value to wrap. + int wrapY; + IntSize filterSize; + + PaintingData(long paintingSeed, const IntSize& paintingSize); + inline long random(); + }; + + template<typename Type> + friend class ParallelJobs; + + struct FillRegionParameters { + FETurbulence* filter; + ByteArray* pixelArray; + PaintingData* paintingData; + int startY; + int endY; + }; + + static void fillRegionWorker(FillRegionParameters*); + + FETurbulence(Filter*, TurbulenceType, float, float, int, float, bool); + + inline void initPaint(PaintingData&); + float noise2D(int channel, PaintingData&, const FloatPoint&); + unsigned char calculateTurbulenceValueForPoint(int channel, PaintingData&, const FloatPoint&); + inline void fillRegion(ByteArray*, PaintingData&, int, int); + + TurbulenceType m_type; + float m_baseFrequencyX; + float m_baseFrequencyY; + int m_numOctaves; + float m_seed; + bool m_stitchTiles; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FETurbulence_h diff --git a/Source/WebCore/platform/graphics/filters/Filter.h b/Source/WebCore/platform/graphics/filters/Filter.h new file mode 100644 index 000000000..b0f604d56 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/Filter.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef Filter_h +#define Filter_h + +#if ENABLE(FILTERS) +#include "FloatRect.h" +#include "FloatSize.h" +#include "ImageBuffer.h" +#include <wtf/RefCounted.h> + +namespace WebCore { + +class FilterEffect; + +class Filter : public RefCounted<Filter> { +public: + Filter() : m_renderingMode(Unaccelerated) { } + virtual ~Filter() { } + + void setSourceImage(PassOwnPtr<ImageBuffer> sourceImage) { m_sourceImage = sourceImage; } + ImageBuffer* sourceImage() { return m_sourceImage.get(); } + + FloatSize filterResolution() const { return m_filterResolution; } + void setFilterResolution(const FloatSize& filterResolution) { m_filterResolution = filterResolution; } + + RenderingMode renderingMode() const { return m_renderingMode; } + void setRenderingMode(RenderingMode renderingMode) { m_renderingMode = renderingMode; } + + virtual float applyHorizontalScale(float value) const { return value * m_filterResolution.width(); } + virtual float applyVerticalScale(float value) const { return value * m_filterResolution.height(); } + + virtual FloatRect sourceImageRect() const = 0; + virtual FloatRect filterRegion() const = 0; + + virtual FloatPoint mapAbsolutePointToLocalPoint(const FloatPoint&) const { return FloatPoint(); } + +private: + OwnPtr<ImageBuffer> m_sourceImage; + FloatSize m_filterResolution; + RenderingMode m_renderingMode; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // Filter_h diff --git a/Source/WebCore/platform/graphics/filters/FilterEffect.cpp b/Source/WebCore/platform/graphics/filters/FilterEffect.cpp new file mode 100644 index 000000000..6516faadc --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FilterEffect.cpp @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FilterEffect.h" + +#include "Filter.h" +#include "ImageBuffer.h" +#include "TextStream.h" +#include <wtf/ByteArray.h> + +namespace WebCore { + +FilterEffect::FilterEffect(Filter* filter) + : m_alphaImage(false) + , m_filter(filter) + , m_hasX(false) + , m_hasY(false) + , m_hasWidth(false) + , m_hasHeight(false) + , m_clipsToBounds(true) +{ + ASSERT(m_filter); +} + +FilterEffect::~FilterEffect() +{ +} + +inline bool isFilterSizeValid(IntRect rect) +{ + if (rect.width() < 0 || rect.width() > kMaxFilterSize + || rect.height() < 0 || rect.height() > kMaxFilterSize) + return false; + return true; +} + +void FilterEffect::determineAbsolutePaintRect() +{ + m_absolutePaintRect = IntRect(); + unsigned size = m_inputEffects.size(); + for (unsigned i = 0; i < size; ++i) + m_absolutePaintRect.unite(m_inputEffects.at(i)->absolutePaintRect()); + + // Filters in SVG clip to primitive subregion, while CSS doesn't. + if (m_clipsToBounds) + m_absolutePaintRect.intersect(enclosingIntRect(m_maxEffectRect)); + else + m_absolutePaintRect.unite(enclosingIntRect(m_maxEffectRect)); + +} + +IntRect FilterEffect::requestedRegionOfInputImageData(const IntRect& effectRect) const +{ + ASSERT(hasResult()); + IntPoint location = m_absolutePaintRect.location(); + location.moveBy(-effectRect.location()); + return IntRect(location, m_absolutePaintRect.size()); +} + +IntRect FilterEffect::drawingRegionOfInputImage(const IntRect& srcRect) const +{ + return IntRect(IntPoint(srcRect.x() - m_absolutePaintRect.x(), + srcRect.y() - m_absolutePaintRect.y()), srcRect.size()); +} + +FilterEffect* FilterEffect::inputEffect(unsigned number) const +{ + ASSERT(number < m_inputEffects.size()); + return m_inputEffects.at(number).get(); +} + +void FilterEffect::apply() +{ + if (hasResult()) + return; + unsigned size = m_inputEffects.size(); + for (unsigned i = 0; i < size; ++i) { + FilterEffect* in = m_inputEffects.at(i).get(); + in->apply(); + if (!in->hasResult()) + return; + } + determineAbsolutePaintRect(); + + // Add platform specific apply functions here and return earlier. + platformApplySoftware(); +} + +void FilterEffect::clearResult() +{ + if (m_imageBufferResult) + m_imageBufferResult.clear(); + if (m_unmultipliedImageResult) + m_unmultipliedImageResult.clear(); + if (m_premultipliedImageResult) + m_premultipliedImageResult.clear(); +} + +ImageBuffer* FilterEffect::asImageBuffer() +{ + if (!hasResult()) + return 0; + if (m_imageBufferResult) + return m_imageBufferResult.get(); + m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB, m_filter->renderingMode()); + IntRect destinationRect(IntPoint(), m_absolutePaintRect.size()); + if (m_premultipliedImageResult) + m_imageBufferResult->putPremultipliedImageData(m_premultipliedImageResult.get(), destinationRect.size(), destinationRect, IntPoint()); + else + m_imageBufferResult->putUnmultipliedImageData(m_unmultipliedImageResult.get(), destinationRect.size(), destinationRect, IntPoint()); + return m_imageBufferResult.get(); +} + +PassRefPtr<ByteArray> FilterEffect::asUnmultipliedImage(const IntRect& rect) +{ + ASSERT(isFilterSizeValid(rect)); + RefPtr<ByteArray> imageData = ByteArray::create(rect.width() * rect.height() * 4); + copyUnmultipliedImage(imageData.get(), rect); + return imageData.release(); +} + +PassRefPtr<ByteArray> FilterEffect::asPremultipliedImage(const IntRect& rect) +{ + ASSERT(isFilterSizeValid(rect)); + RefPtr<ByteArray> imageData = ByteArray::create(rect.width() * rect.height() * 4); + copyPremultipliedImage(imageData.get(), rect); + return imageData.release(); +} + +inline void FilterEffect::copyImageBytes(ByteArray* source, ByteArray* destination, const IntRect& rect) +{ + // Initialize the destination to transparent black, if not entirely covered by the source. + if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > m_absolutePaintRect.width() || rect.maxY() > m_absolutePaintRect.height()) + memset(destination->data(), 0, destination->length()); + + // Early return if the rect does not intersect with the source. + if (rect.maxX() <= 0 || rect.maxY() <= 0 || rect.x() >= m_absolutePaintRect.width() || rect.y() >= m_absolutePaintRect.height()) + return; + + int xOrigin = rect.x(); + int xDest = 0; + if (xOrigin < 0) { + xDest = -xOrigin; + xOrigin = 0; + } + int xEnd = rect.maxX(); + if (xEnd > m_absolutePaintRect.width()) + xEnd = m_absolutePaintRect.width(); + + int yOrigin = rect.y(); + int yDest = 0; + if (yOrigin < 0) { + yDest = -yOrigin; + yOrigin = 0; + } + int yEnd = rect.maxY(); + if (yEnd > m_absolutePaintRect.height()) + yEnd = m_absolutePaintRect.height(); + + int size = (xEnd - xOrigin) * 4; + int destinationScanline = rect.width() * 4; + int sourceScanline = m_absolutePaintRect.width() * 4; + unsigned char *destinationPixel = destination->data() + ((yDest * rect.width()) + xDest) * 4; + unsigned char *sourcePixel = source->data() + ((yOrigin * m_absolutePaintRect.width()) + xOrigin) * 4; + + while (yOrigin < yEnd) { + memcpy(destinationPixel, sourcePixel, size); + destinationPixel += destinationScanline; + sourcePixel += sourceScanline; + ++yOrigin; + } +} + +void FilterEffect::copyUnmultipliedImage(ByteArray* destination, const IntRect& rect) +{ + ASSERT(hasResult()); + + if (!m_unmultipliedImageResult) { + // We prefer a conversion from the image buffer. + if (m_imageBufferResult) + m_unmultipliedImageResult = m_imageBufferResult->getUnmultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size())); + else { + ASSERT(isFilterSizeValid(m_absolutePaintRect)); + m_unmultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4); + unsigned char* sourceComponent = m_premultipliedImageResult->data(); + unsigned char* destinationComponent = m_unmultipliedImageResult->data(); + unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4); + while (sourceComponent < end) { + int alpha = sourceComponent[3]; + if (alpha) { + destinationComponent[0] = static_cast<int>(sourceComponent[0]) * 255 / alpha; + destinationComponent[1] = static_cast<int>(sourceComponent[1]) * 255 / alpha; + destinationComponent[2] = static_cast<int>(sourceComponent[2]) * 255 / alpha; + } else { + destinationComponent[0] = 0; + destinationComponent[1] = 0; + destinationComponent[2] = 0; + } + destinationComponent[3] = alpha; + sourceComponent += 4; + destinationComponent += 4; + } + } + } + copyImageBytes(m_unmultipliedImageResult.get(), destination, rect); +} + +void FilterEffect::copyPremultipliedImage(ByteArray* destination, const IntRect& rect) +{ + ASSERT(hasResult()); + + if (!m_premultipliedImageResult) { + // We prefer a conversion from the image buffer. + if (m_imageBufferResult) + m_premultipliedImageResult = m_imageBufferResult->getPremultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size())); + else { + ASSERT(isFilterSizeValid(m_absolutePaintRect)); + m_premultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4); + unsigned char* sourceComponent = m_unmultipliedImageResult->data(); + unsigned char* destinationComponent = m_premultipliedImageResult->data(); + unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4); + while (sourceComponent < end) { + int alpha = sourceComponent[3]; + destinationComponent[0] = static_cast<int>(sourceComponent[0]) * alpha / 255; + destinationComponent[1] = static_cast<int>(sourceComponent[1]) * alpha / 255; + destinationComponent[2] = static_cast<int>(sourceComponent[2]) * alpha / 255; + destinationComponent[3] = alpha; + sourceComponent += 4; + destinationComponent += 4; + } + } + } + copyImageBytes(m_premultipliedImageResult.get(), destination, rect); +} + +ImageBuffer* FilterEffect::createImageBufferResult() +{ + // Only one result type is allowed. + ASSERT(!hasResult()); + if (m_absolutePaintRect.isEmpty()) + return 0; + m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB, m_filter->renderingMode()); + if (!m_imageBufferResult) + return 0; + ASSERT(m_imageBufferResult->context()); + return m_imageBufferResult.get(); +} + +ByteArray* FilterEffect::createUnmultipliedImageResult() +{ + // Only one result type is allowed. + ASSERT(!hasResult()); + ASSERT(isFilterSizeValid(m_absolutePaintRect)); + + if (m_absolutePaintRect.isEmpty()) + return 0; + m_unmultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4); + return m_unmultipliedImageResult.get(); +} + +ByteArray* FilterEffect::createPremultipliedImageResult() +{ + // Only one result type is allowed. + ASSERT(!hasResult()); + ASSERT(isFilterSizeValid(m_absolutePaintRect)); + + if (m_absolutePaintRect.isEmpty()) + return 0; + m_premultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4); + return m_premultipliedImageResult.get(); +} + +TextStream& FilterEffect::externalRepresentation(TextStream& ts, int) const +{ + // FIXME: We should dump the subRegions of the filter primitives here later. This isn't + // possible at the moment, because we need more detailed informations from the target object. + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FilterEffect.h b/Source/WebCore/platform/graphics/filters/FilterEffect.h new file mode 100644 index 000000000..073010d27 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FilterEffect.h @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FilterEffect_h +#define FilterEffect_h + +#if ENABLE(FILTERS) +#include "FloatRect.h" +#include "IntRect.h" + +#include <wtf/ByteArray.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +static const float kMaxFilterSize = 5000.0f; + +namespace WebCore { + +class Filter; +class FilterEffect; +class ImageBuffer; +class TextStream; + +typedef Vector<RefPtr<FilterEffect> > FilterEffectVector; + +enum FilterEffectType { + FilterEffectTypeUnknown, + FilterEffectTypeImage, + FilterEffectTypeTile, + FilterEffectTypeSourceInput +}; + +class FilterEffect : public RefCounted<FilterEffect> { +public: + virtual ~FilterEffect(); + + void clearResult(); + ImageBuffer* asImageBuffer(); + PassRefPtr<ByteArray> asUnmultipliedImage(const IntRect&); + PassRefPtr<ByteArray> asPremultipliedImage(const IntRect&); + void copyUnmultipliedImage(ByteArray* destination, const IntRect&); + void copyPremultipliedImage(ByteArray* destination, const IntRect&); + + FilterEffectVector& inputEffects() { return m_inputEffects; } + FilterEffect* inputEffect(unsigned) const; + unsigned numberOfEffectInputs() const { return m_inputEffects.size(); } + + inline bool hasResult() const + { + // This function needs platform specific checks, if the memory managment is not done by FilterEffect. + return m_imageBufferResult || m_unmultipliedImageResult || m_premultipliedImageResult; + } + + IntRect drawingRegionOfInputImage(const IntRect&) const; + IntRect requestedRegionOfInputImageData(const IntRect&) const; + + // Solid black image with different alpha values. + bool isAlphaImage() const { return m_alphaImage; } + void setIsAlphaImage(bool alphaImage) { m_alphaImage = alphaImage; } + + IntRect absolutePaintRect() const { return m_absolutePaintRect; } + void setAbsolutePaintRect(const IntRect& absolutePaintRect) { m_absolutePaintRect = absolutePaintRect; } + + FloatRect maxEffectRect() const { return m_maxEffectRect; } + void setMaxEffectRect(const FloatRect& maxEffectRect) { m_maxEffectRect = maxEffectRect; } + + void apply(); + + virtual void platformApplySoftware() = 0; + virtual void dump() = 0; + + virtual void determineAbsolutePaintRect(); + + virtual FilterEffectType filterEffectType() const { return FilterEffectTypeUnknown; } + + virtual TextStream& externalRepresentation(TextStream&, int indention = 0) const; + +public: + // The following functions are SVG specific and will move to RenderSVGResourceFilterPrimitive. + // See bug https://bugs.webkit.org/show_bug.cgi?id=45614. + bool hasX() const { return m_hasX; } + void setHasX(bool value) { m_hasX = value; } + + bool hasY() const { return m_hasY; } + void setHasY(bool value) { m_hasY = value; } + + bool hasWidth() const { return m_hasWidth; } + void setHasWidth(bool value) { m_hasWidth = value; } + + bool hasHeight() const { return m_hasHeight; } + void setHasHeight(bool value) { m_hasHeight = value; } + + FloatRect filterPrimitiveSubregion() const { return m_filterPrimitiveSubregion; } + void setFilterPrimitiveSubregion(const FloatRect& filterPrimitiveSubregion) { m_filterPrimitiveSubregion = filterPrimitiveSubregion; } + + FloatRect effectBoundaries() const { return m_effectBoundaries; } + void setEffectBoundaries(const FloatRect& effectBoundaries) { m_effectBoundaries = effectBoundaries; } + + Filter* filter() { return m_filter; } + + bool clipsToBounds() const { return m_clipsToBounds; } + void setClipsToBounds(bool value) { m_clipsToBounds = value; } + +protected: + FilterEffect(Filter*); + + ImageBuffer* createImageBufferResult(); + ByteArray* createUnmultipliedImageResult(); + ByteArray* createPremultipliedImageResult(); + +private: + OwnPtr<ImageBuffer> m_imageBufferResult; + RefPtr<ByteArray> m_unmultipliedImageResult; + RefPtr<ByteArray> m_premultipliedImageResult; + FilterEffectVector m_inputEffects; + + bool m_alphaImage; + + IntRect m_absolutePaintRect; + + // The maximum size of a filter primitive. In SVG this is the primitive subregion in absolute coordinate space. + // The absolute paint rect should never be bigger than m_maxEffectRect. + FloatRect m_maxEffectRect; + Filter* m_filter; + +private: + inline void copyImageBytes(ByteArray* source, ByteArray* destination, const IntRect&); + + // The following member variables are SVG specific and will move to RenderSVGResourceFilterPrimitive. + // See bug https://bugs.webkit.org/show_bug.cgi?id=45614. + + // The subregion of a filter primitive according to the SVG Filter specification in local coordinates. + // This is SVG specific and needs to move to RenderSVGResourceFilterPrimitive. + FloatRect m_filterPrimitiveSubregion; + + // x, y, width and height of the actual SVGFE*Element. Is needed to determine the subregion of the + // filter primitive on a later step. + FloatRect m_effectBoundaries; + bool m_hasX; + bool m_hasY; + bool m_hasWidth; + bool m_hasHeight; + + // Should the effect clip to its primitive region, or expand to use the combined region of its inputs. + bool m_clipsToBounds; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FilterEffect_h diff --git a/Source/WebCore/platform/graphics/filters/FilterOperation.cpp b/Source/WebCore/platform/graphics/filters/FilterOperation.cpp new file mode 100644 index 000000000..5de6ec0aa --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FilterOperation.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(CSS_FILTERS) +#include "FilterOperation.h" + +#include "AnimationUtilities.h" + +namespace WebCore { + +PassRefPtr<FilterOperation> BasicColorMatrixFilterOperation::blend(const FilterOperation* from, double progress, bool blendToPassthrough) +{ + if (from && !from->isSameType(*this)) + return this; + + if (blendToPassthrough) + return BasicColorMatrixFilterOperation::create(WebCore::blend(m_amount, passthroughAmount(), progress), m_type); + + const BasicColorMatrixFilterOperation* fromOp = static_cast<const BasicColorMatrixFilterOperation*>(from); + double fromAmount = fromOp ? fromOp->amount() : passthroughAmount(); + return BasicColorMatrixFilterOperation::create(WebCore::blend(fromAmount, m_amount, progress), m_type); +} + +double BasicColorMatrixFilterOperation::passthroughAmount() const +{ + switch (m_type) { + case GRAYSCALE: + case SEPIA: + case HUE_ROTATE: + return 0; + case SATURATE: + return 1; + default: + ASSERT_NOT_REACHED(); + return 0; + } +} + +PassRefPtr<FilterOperation> BasicComponentTransferFilterOperation::blend(const FilterOperation* from, double progress, bool blendToPassthrough) +{ + if (from && !from->isSameType(*this)) + return this; + + if (blendToPassthrough) + return BasicComponentTransferFilterOperation::create(WebCore::blend(m_amount, passthroughAmount(), progress), m_type); + + const BasicComponentTransferFilterOperation* fromOp = static_cast<const BasicComponentTransferFilterOperation*>(from); + double fromAmount = fromOp ? fromOp->amount() : passthroughAmount(); + return BasicComponentTransferFilterOperation::create(WebCore::blend(fromAmount, m_amount, progress), m_type); +} + +double BasicComponentTransferFilterOperation::passthroughAmount() const +{ + switch (m_type) { + case OPACITY: + return 1; + case INVERT: + return 0; + case CONTRAST: + return 1; + case BRIGHTNESS: + return 1; + default: + ASSERT_NOT_REACHED(); + return 0; + } +} + +PassRefPtr<FilterOperation> GammaFilterOperation::blend(const FilterOperation* from, double progress, bool blendToPassthrough) +{ + if (from && !from->isSameType(*this)) + return this; + + if (blendToPassthrough) + return GammaFilterOperation::create( + WebCore::blend(m_amplitude, 1.0, progress), + WebCore::blend(m_exponent, 1.0, progress), + WebCore::blend(m_offset, 0.0, progress), m_type); + + const GammaFilterOperation* fromOp = static_cast<const GammaFilterOperation*>(from); + double fromAmplitude = fromOp ? fromOp->amplitude() : 1; + double fromExponent = fromOp ? fromOp->exponent() : 1; + double fromOffset = fromOp ? fromOp->offset() : 0; + return GammaFilterOperation::create( + WebCore::blend(fromAmplitude, m_amplitude, progress), + WebCore::blend(fromExponent, m_exponent, progress), + WebCore::blend(fromOffset, m_offset, progress), m_type); +} + +PassRefPtr<FilterOperation> BlurFilterOperation::blend(const FilterOperation* from, double progress, bool blendToPassthrough) +{ + if (from && !from->isSameType(*this)) + return this; + + LengthType lengthType = m_stdDeviation.type(); + + if (blendToPassthrough) + return BlurFilterOperation::create(Length(lengthType).blend(m_stdDeviation, progress), m_type); + + const BlurFilterOperation* fromOp = static_cast<const BlurFilterOperation*>(from); + Length fromLength = fromOp ? fromOp->m_stdDeviation : Length(lengthType); + return BlurFilterOperation::create(m_stdDeviation.blend(fromLength, progress), m_type); +} + +PassRefPtr<FilterOperation> DropShadowFilterOperation::blend(const FilterOperation* from, double progress, bool blendToPassthrough) +{ + if (from && !from->isSameType(*this)) + return this; + + if (blendToPassthrough) + return DropShadowFilterOperation::create( + WebCore::blend(m_x, 0, progress), + WebCore::blend(m_y, 0, progress), + WebCore::blend(m_stdDeviation, 0, progress), + WebCore::blend(m_color, Color(Color::transparent), progress), + m_type); + + const DropShadowFilterOperation* fromOp = static_cast<const DropShadowFilterOperation*>(from); + int fromX = fromOp ? fromOp->x() : 0; + int fromY = fromOp ? fromOp->y() : 0; + int fromStdDeviation = fromOp ? fromOp->stdDeviation() : 0; + Color fromColor = fromOp ? fromOp->color() : Color(Color::transparent); + + return DropShadowFilterOperation::create( + WebCore::blend(fromX, m_x, progress), + WebCore::blend(fromY, m_y, progress), + WebCore::blend(fromStdDeviation, m_stdDeviation, progress), + WebCore::blend(fromColor, m_color, progress), m_type); +} + +} // namespace WebCore + +#endif // ENABLE(CSS_FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FilterOperation.h b/Source/WebCore/platform/graphics/filters/FilterOperation.h new file mode 100644 index 000000000..4d15ec8ed --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FilterOperation.h @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FilterOperation_h +#define FilterOperation_h + +#if ENABLE(CSS_FILTERS) + +#include "Color.h" +#include "Length.h" +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/text/AtomicString.h> + +// Annoyingly, wingdi.h #defines this. +#ifdef PASSTHROUGH +#undef PASSTHROUGH +#endif + +namespace WebCore { + +// CSS Filters + +class FilterOperation : public RefCounted<FilterOperation> { +public: + enum OperationType { + REFERENCE, // url(#somefilter) + GRAYSCALE, + SEPIA, + SATURATE, + HUE_ROTATE, + INVERT, + OPACITY, + BRIGHTNESS, + CONTRAST, + BLUR, + DROP_SHADOW, +#if ENABLE(CSS_SHADERS) + CUSTOM, +#endif + PASSTHROUGH, + NONE + }; + + virtual ~FilterOperation() { } + + virtual bool operator==(const FilterOperation&) const = 0; + bool operator!=(const FilterOperation& o) const { return !(*this == o); } + + virtual PassRefPtr<FilterOperation> blend(const FilterOperation* /*from*/, double /*progress*/, bool /*blendToPassthrough*/ = false) { return 0; } + + virtual OperationType getOperationType() const { return m_type; } + virtual bool isSameType(const FilterOperation& o) const { return o.getOperationType() == m_type; } + +protected: + FilterOperation(OperationType type) + : m_type(type) + { + } + + OperationType m_type; +}; + +class PassthroughFilterOperation : public FilterOperation { +public: + static PassRefPtr<PassthroughFilterOperation> create() + { + return adoptRef(new PassthroughFilterOperation()); + } + +private: + + virtual bool operator==(const FilterOperation& o) const + { + return isSameType(o); + } + + PassthroughFilterOperation() + : FilterOperation(PASSTHROUGH) + { + } +}; + +class ReferenceFilterOperation : public FilterOperation { +public: + static PassRefPtr<ReferenceFilterOperation> create(const AtomicString& reference, OperationType type) + { + return adoptRef(new ReferenceFilterOperation(reference, type)); + } + + const AtomicString& reference() const { return m_reference; } + +private: + + virtual bool operator==(const FilterOperation& o) const + { + if (!isSameType(o)) + return false; + const ReferenceFilterOperation* other = static_cast<const ReferenceFilterOperation*>(&o); + return m_reference == other->m_reference; + } + + ReferenceFilterOperation(const AtomicString& reference, OperationType type) + : FilterOperation(type) + , m_reference(reference) + { + } + + AtomicString m_reference; +}; + +// GRAYSCALE, SEPIA, SATURATE and HUE_ROTATE are variations on a basic color matrix effect. +// For HUE_ROTATE, the angle of rotation is stored in m_amount. +class BasicColorMatrixFilterOperation : public FilterOperation { +public: + static PassRefPtr<BasicColorMatrixFilterOperation> create(double amount, OperationType type) + { + return adoptRef(new BasicColorMatrixFilterOperation(amount, type)); + } + + double amount() const { return m_amount; } + + virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress, bool blendToPassthrough = false); + +private: + virtual bool operator==(const FilterOperation& o) const + { + if (!isSameType(o)) + return false; + const BasicColorMatrixFilterOperation* other = static_cast<const BasicColorMatrixFilterOperation*>(&o); + return m_amount == other->m_amount; + } + + double passthroughAmount() const; + + BasicColorMatrixFilterOperation(double amount, OperationType type) + : FilterOperation(type) + , m_amount(amount) + { + } + + double m_amount; +}; + +// INVERT, BRIGHTNESS, CONTRAST and OPACITY are variations on a basic component transfer effect. +class BasicComponentTransferFilterOperation : public FilterOperation { +public: + static PassRefPtr<BasicComponentTransferFilterOperation> create(double amount, OperationType type) + { + return adoptRef(new BasicComponentTransferFilterOperation(amount, type)); + } + + double amount() const { return m_amount; } + + virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress, bool blendToPassthrough = false); + +private: + virtual bool operator==(const FilterOperation& o) const + { + if (!isSameType(o)) + return false; + const BasicComponentTransferFilterOperation* other = static_cast<const BasicComponentTransferFilterOperation*>(&o); + return m_amount == other->m_amount; + } + + double passthroughAmount() const; + + BasicComponentTransferFilterOperation(double amount, OperationType type) + : FilterOperation(type) + , m_amount(amount) + { + } + + double m_amount; +}; + +class GammaFilterOperation : public FilterOperation { +public: + static PassRefPtr<GammaFilterOperation> create(double amplitude, double exponent, double offset, OperationType type) + { + return adoptRef(new GammaFilterOperation(amplitude, exponent, offset, type)); + } + + double amplitude() const { return m_amplitude; } + double exponent() const { return m_exponent; } + double offset() const { return m_offset; } + + virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress, bool blendToPassthrough = false); + +private: + virtual bool operator==(const FilterOperation& o) const + { + if (!isSameType(o)) + return false; + const GammaFilterOperation* other = static_cast<const GammaFilterOperation*>(&o); + return m_amplitude == other->m_amplitude && m_exponent == other->m_exponent && m_offset == other->m_offset; + } + + GammaFilterOperation(double amplitude, double exponent, double offset, OperationType type) + : FilterOperation(type) + , m_amplitude(amplitude) + , m_exponent(exponent) + , m_offset(offset) + { + } + + double m_amplitude; + double m_exponent; + double m_offset; +}; + +class BlurFilterOperation : public FilterOperation { +public: + static PassRefPtr<BlurFilterOperation> create(Length stdDeviation, OperationType type) + { + return adoptRef(new BlurFilterOperation(stdDeviation, type)); + } + + Length stdDeviation() const { return m_stdDeviation; } + + virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress, bool blendToPassthrough = false); + +private: + virtual bool operator==(const FilterOperation& o) const + { + if (!isSameType(o)) + return false; + const BlurFilterOperation* other = static_cast<const BlurFilterOperation*>(&o); + return m_stdDeviation == other->m_stdDeviation; + } + + BlurFilterOperation(Length stdDeviation, OperationType type) + : FilterOperation(type) + , m_stdDeviation(stdDeviation) + { + } + + Length m_stdDeviation; +}; + +class DropShadowFilterOperation : public FilterOperation { +public: + static PassRefPtr<DropShadowFilterOperation> create(int x, int y, int stdDeviation, Color color, OperationType type) + { + return adoptRef(new DropShadowFilterOperation(x, y, stdDeviation, color, type)); + } + + int x() const { return m_x; } + int y() const { return m_y; } + int stdDeviation() const { return m_stdDeviation; } + Color color() const { return m_color; } + + virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress, bool blendToPassthrough = false); + +private: + + virtual bool operator==(const FilterOperation& o) const + { + if (!isSameType(o)) + return false; + const DropShadowFilterOperation* other = static_cast<const DropShadowFilterOperation*>(&o); + return m_x == other->m_x && m_y == other->m_y && m_stdDeviation == other->m_stdDeviation && m_color == other->m_color; + } + + DropShadowFilterOperation(int x, int y, int stdDeviation, Color color, OperationType type) + : FilterOperation(type) + , m_x(x) + , m_y(y) + , m_stdDeviation(stdDeviation) + , m_color(color) + { + } + + int m_x; // FIXME: x and y should be Lengths? + int m_y; + int m_stdDeviation; + Color m_color; +}; + +} // namespace WebCore + +#endif // ENABLE(CSS_FILTERS) + +#endif // FilterOperation_h diff --git a/Source/WebCore/platform/graphics/filters/FilterOperations.cpp b/Source/WebCore/platform/graphics/filters/FilterOperations.cpp new file mode 100644 index 000000000..dd92ac1aa --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FilterOperations.cpp @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FilterOperations.h" + +#include "FEGaussianBlur.h" +#include "IntSize.h" + +#if ENABLE(CSS_FILTERS) + +namespace WebCore { + +static inline IntSize outsetSizeForBlur(float stdDeviation) +{ + unsigned kernelSizeX = 0; + unsigned kernelSizeY = 0; + FEGaussianBlur::calculateUnscaledKernelSize(kernelSizeX, kernelSizeY, stdDeviation, stdDeviation); + + IntSize outset; + // We take the half kernel size and multiply it with three, because we run box blur three times. + outset.setWidth(3 * kernelSizeX * 0.5f); + outset.setHeight(3 * kernelSizeY * 0.5f); + + return outset; +} + +FilterOperations::FilterOperations() +{ +} + +FilterOperations& FilterOperations::operator=(const FilterOperations& other) +{ + m_operations = other.m_operations; + return *this; +} + +bool FilterOperations::operator==(const FilterOperations& o) const +{ + if (m_operations.size() != o.m_operations.size()) + return false; + + unsigned s = m_operations.size(); + for (unsigned i = 0; i < s; i++) { + if (*m_operations[i] != *o.m_operations[i]) + return false; + } + + return true; +} + +bool FilterOperations::operationsMatch(const FilterOperations& other) const +{ + size_t numOperations = operations().size(); + // If the sizes of the function lists don't match, the lists don't match + if (numOperations != other.operations().size()) + return false; + + // If the types of each function are not the same, the lists don't match + for (size_t i = 0; i < numOperations; ++i) { + if (!operations()[i]->isSameType(*other.operations()[i])) + return false; + } + return true; +} + +bool FilterOperations::hasOutsets() const +{ + for (size_t i = 0; i < m_operations.size(); ++i) { + FilterOperation::OperationType operationType = m_operations.at(i).get()->getOperationType(); + if (operationType == FilterOperation::BLUR || operationType == FilterOperation::DROP_SHADOW) + return true; + } + return false; +} + +void FilterOperations::getOutsets(LayoutUnit& top, LayoutUnit& right, LayoutUnit& bottom, LayoutUnit& left) const +{ + top = 0; + right = 0; + bottom = 0; + left = 0; + for (size_t i = 0; i < m_operations.size(); ++i) { + FilterOperation* filterOperation = m_operations.at(i).get(); + switch (filterOperation->getOperationType()) { + case FilterOperation::BLUR: { + BlurFilterOperation* blurOperation = static_cast<BlurFilterOperation*>(filterOperation); + float stdDeviation = blurOperation->stdDeviation().calcFloatValue(0); + IntSize outset = outsetSizeForBlur(stdDeviation); + top += outset.height(); + right += outset.width(); + bottom += outset.height(); + left += outset.width(); + break; + } + case FilterOperation::DROP_SHADOW: { + DropShadowFilterOperation* dropShadowOperation = static_cast<DropShadowFilterOperation*>(filterOperation); + IntSize outset = outsetSizeForBlur(dropShadowOperation->stdDeviation()); + top += outset.height() - dropShadowOperation->y(); + right += outset.width() + dropShadowOperation->x(); + bottom += outset.height() + dropShadowOperation->y(); + left += outset.width() - dropShadowOperation->x(); + break; + } +#if ENABLE(CSS_SHADERS) + case FilterOperation::CUSTOM: { + // Need to include the filter margins here. + break; + } +#endif + default: + break; + } + } +} + +} // namespace WebCore + +#endif // ENABLE(CSS_FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FilterOperations.h b/Source/WebCore/platform/graphics/filters/FilterOperations.h new file mode 100644 index 000000000..64cee8808 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/FilterOperations.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FilterOperations_h +#define FilterOperations_h + +#if ENABLE(CSS_FILTERS) + +#include "FilterOperation.h" +#include "LayoutTypes.h" +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class FilterOperations { + WTF_MAKE_FAST_ALLOCATED; +public: + FilterOperations(); + FilterOperations(const FilterOperations& other) { *this = other; } + + FilterOperations& operator=(const FilterOperations&); + + bool operator==(const FilterOperations&) const; + bool operator!=(const FilterOperations& o) const + { + return !(*this == o); + } + + void clear() + { + m_operations.clear(); + } + + Vector<RefPtr<FilterOperation> >& operations() { return m_operations; } + const Vector<RefPtr<FilterOperation> >& operations() const { return m_operations; } + + size_t size() const { return m_operations.size(); } + const FilterOperation* at(size_t index) const { return index < m_operations.size() ? m_operations.at(index).get() : 0; } + + bool operationsMatch(const FilterOperations&) const; + + bool hasOutsets() const; + void getOutsets(LayoutUnit& top, LayoutUnit& right, LayoutUnit& bottom, LayoutUnit& left) const; + +private: + Vector<RefPtr<FilterOperation> > m_operations; +}; + +} // namespace WebCore + +#endif // ENABLE(CSS_FILTERS) + +#endif // FilterOperations_h diff --git a/Source/WebCore/platform/graphics/filters/LightSource.cpp b/Source/WebCore/platform/graphics/filters/LightSource.cpp new file mode 100644 index 000000000..cf262e852 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/LightSource.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2010 Zoltan Herczeg <zherczeg@webkit.org> + * Copyright (C) 2011 Renata Hodovan <reni@webkit.org>, University of Szeged. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "LightSource.h" + +#include "DistantLightSource.h" +#include "PointLightSource.h" +#include "RenderTreeAsText.h" +#include "SpotLightSource.h" +#include <wtf/MathExtras.h> + +namespace WebCore { + +bool LightSource::setAzimuth(float azimuth) +{ + if (m_type == LS_DISTANT) + return static_cast<DistantLightSource*>(this)->setAzimuth(azimuth); + return false; +} + +bool LightSource::setElevation(float elevation) +{ + if (m_type == LS_DISTANT) + return static_cast<DistantLightSource*>(this)->setElevation(elevation); + return false; +} + +bool LightSource::setX(float x) +{ + if (m_type == LS_SPOT) + return static_cast<SpotLightSource*>(this)->setX(x); + if (m_type == LS_POINT) + return static_cast<PointLightSource*>(this)->setX(x); + return false; +} + +bool LightSource::setY(float y) +{ + if (m_type == LS_SPOT) + return static_cast<SpotLightSource*>(this)->setY(y); + if (m_type == LS_POINT) + return static_cast<PointLightSource*>(this)->setY(y); + return false; +} + +bool LightSource::setZ(float z) +{ + if (m_type == LS_SPOT) + return static_cast<SpotLightSource*>(this)->setZ(z); + if (m_type == LS_POINT) + return static_cast<PointLightSource*>(this)->setZ(z); + return false; +} + +bool LightSource::setPointsAtX(float pointsAtX) +{ + if (m_type == LS_SPOT) + return static_cast<SpotLightSource*>(this)->setPointsAtX(pointsAtX); + return false; +} + +bool LightSource::setPointsAtY(float pointsAtY) +{ + if (m_type == LS_SPOT) + return static_cast<SpotLightSource*>(this)->setPointsAtY(pointsAtY); + return false; +} + +bool LightSource::setPointsAtZ(float pointsAtZ) +{ + if (m_type == LS_SPOT) + return static_cast<SpotLightSource*>(this)->setPointsAtZ(pointsAtZ); + return false; +} + +bool LightSource::setSpecularExponent(float specularExponent) +{ + if (m_type == LS_SPOT) + return static_cast<SpotLightSource*>(this)->setSpecularExponent(specularExponent); + return false; +} + +bool LightSource::setLimitingConeAngle(float limitingConeAngle) +{ + if (m_type == LS_SPOT) + return static_cast<SpotLightSource*>(this)->setLimitingConeAngle(limitingConeAngle); + return false; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/LightSource.h b/Source/WebCore/platform/graphics/filters/LightSource.h new file mode 100644 index 000000000..24c319a61 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/LightSource.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2010 Zoltan Herczeg <zherczeg@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef LightSource_h +#define LightSource_h + +#if ENABLE(FILTERS) +#include "FloatPoint3D.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +enum LightType { + LS_DISTANT, + LS_POINT, + LS_SPOT +}; + +class TextStream; + +class LightSource : public RefCounted<LightSource> { +public: + + // Light vectors must be calculated for every pixel during + // painting. It is expensive to pass all these arguments to + // a frequently called function, especially because not all + // light sources require all of them. Instead, we just pass + // a reference to the following structure + struct PaintingData { + // SVGFELighting also use them + FloatPoint3D lightVector; + FloatPoint3D colorVector; + float lightVectorLength; + // Private members + FloatPoint3D directionVector; + FloatPoint3D privateColorVector; + float coneCutOffLimit; + float coneFullLight; + int specularExponent; + }; + + LightSource(LightType type) + : m_type(type) + { } + + virtual ~LightSource() { } + + LightType type() const { return m_type; } + virtual TextStream& externalRepresentation(TextStream&) const = 0; + + virtual void initPaintingData(PaintingData&) = 0; + // z is a float number, since it is the alpha value scaled by a user + // specified "surfaceScale" constant, which type is <number> in the SVG standard + virtual void updatePaintingData(PaintingData&, int x, int y, float z) = 0; + + bool setAzimuth(float); + bool setElevation(float); + bool setX(float); + bool setY(float); + bool setZ(float); + bool setPointsAtX(float); + bool setPointsAtY(float); + bool setPointsAtZ(float); + bool setSpecularExponent(float); + bool setLimitingConeAngle(float); + +private: + LightType m_type; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // LightSource_h diff --git a/Source/WebCore/platform/graphics/filters/PointLightSource.cpp b/Source/WebCore/platform/graphics/filters/PointLightSource.cpp new file mode 100644 index 000000000..207ed8eae --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/PointLightSource.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2010 Zoltan Herczeg <zherczeg@webkit.org> + * Copyright (C) 2011 University of Szeged + * Copyright (C) 2011 Renata Hodovan <reni@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "PointLightSource.h" + +#include "TextStream.h" + +namespace WebCore { + +void PointLightSource::initPaintingData(PaintingData&) +{ +} + +void PointLightSource::updatePaintingData(PaintingData& paintingData, int x, int y, float z) +{ + paintingData.lightVector.setX(m_position.x() - x); + paintingData.lightVector.setY(m_position.y() - y); + paintingData.lightVector.setZ(m_position.z() - z); + paintingData.lightVectorLength = paintingData.lightVector.length(); +} + +bool PointLightSource::setX(float x) +{ + if (m_position.x() == x) + return false; + m_position.setX(x); + return true; +} + +bool PointLightSource::setY(float y) +{ + if (m_position.y() == y) + return false; + m_position.setY(y); + return true; +} + +bool PointLightSource::setZ(float z) +{ + if (m_position.z() == z) + return false; + m_position.setZ(z); + return true; +} + +static TextStream& operator<<(TextStream& ts, const FloatPoint3D& p) +{ + ts << "x=" << p.x() << " y=" << p.y() << " z=" << p.z(); + return ts; +} + +TextStream& PointLightSource::externalRepresentation(TextStream& ts) const +{ + ts << "[type=POINT-LIGHT] "; + ts << "[position=\"" << position() << "\"]"; + return ts; +} + +}; // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/PointLightSource.h b/Source/WebCore/platform/graphics/filters/PointLightSource.h new file mode 100644 index 000000000..a93bf2cf7 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/PointLightSource.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef PointLightSource_h +#define PointLightSource_h + +#if ENABLE(FILTERS) +#include "LightSource.h" + +namespace WebCore { + +class PointLightSource : public LightSource { +public: + static PassRefPtr<PointLightSource> create(const FloatPoint3D& position) + { + return adoptRef(new PointLightSource(position)); + } + + const FloatPoint3D& position() const { return m_position; } + bool setX(float); + bool setY(float); + bool setZ(float); + + virtual void initPaintingData(PaintingData&); + virtual void updatePaintingData(PaintingData&, int x, int y, float z); + + virtual TextStream& externalRepresentation(TextStream&) const; + +private: + PointLightSource(const FloatPoint3D& position) + : LightSource(LS_POINT) + , m_position(position) + { + } + + FloatPoint3D m_position; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // PointLightSource_h diff --git a/Source/WebCore/platform/graphics/filters/SourceAlpha.cpp b/Source/WebCore/platform/graphics/filters/SourceAlpha.cpp new file mode 100644 index 000000000..aeebde6f8 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/SourceAlpha.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "SourceAlpha.h" + +#include "Color.h" +#include "Filter.h" +#include "GraphicsContext.h" +#include "PlatformString.h" +#include "RenderTreeAsText.h" +#include "TextStream.h" + +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +PassRefPtr<SourceAlpha> SourceAlpha::create(Filter* filter) +{ + return adoptRef(new SourceAlpha(filter)); +} + +const AtomicString& SourceAlpha::effectName() +{ + DEFINE_STATIC_LOCAL(const AtomicString, s_effectName, ("SourceAlpha")); + return s_effectName; +} + +void SourceAlpha::determineAbsolutePaintRect() +{ + Filter* filter = this->filter(); + FloatRect paintRect = filter->sourceImageRect(); + paintRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); + setAbsolutePaintRect(enclosingIntRect(paintRect)); +} + +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(); + GraphicsContextStateSaver stateSaver(*filterContext); + filterContext->clipToImageBuffer(filter->sourceImage(), imageRect); + filterContext->fillRect(imageRect, Color::black, ColorSpaceDeviceRGB); +} + +void SourceAlpha::dump() +{ +} + +TextStream& SourceAlpha::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[SourceAlpha]\n"; + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/SourceAlpha.h b/Source/WebCore/platform/graphics/filters/SourceAlpha.h new file mode 100644 index 000000000..62f19fc41 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/SourceAlpha.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef SourceAlpha_h +#define SourceAlpha_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" + +#include "PlatformString.h" +#include "Filter.h" + +namespace WebCore { + +class SourceAlpha : public FilterEffect { +public: + static PassRefPtr<SourceAlpha> create(Filter*); + + static const AtomicString& effectName(); + + virtual void platformApplySoftware(); + virtual void dump(); + + virtual void determineAbsolutePaintRect(); + + virtual FilterEffectType filterEffectType() const { return FilterEffectTypeSourceInput; } + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + SourceAlpha(Filter* filter) + : FilterEffect(filter) + { + } +}; + +} //namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // SourceAlpha_h diff --git a/Source/WebCore/platform/graphics/filters/SourceGraphic.cpp b/Source/WebCore/platform/graphics/filters/SourceGraphic.cpp new file mode 100644 index 000000000..f46d87da8 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/SourceGraphic.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "SourceGraphic.h" + +#include "Filter.h" +#include "GraphicsContext.h" +#include "PlatformString.h" +#include "RenderTreeAsText.h" +#include "TextStream.h" + +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +PassRefPtr<SourceGraphic> SourceGraphic::create(Filter* filter) +{ + return adoptRef(new SourceGraphic(filter)); +} + +const AtomicString& SourceGraphic::effectName() +{ + DEFINE_STATIC_LOCAL(const AtomicString, s_effectName, ("SourceGraphic")); + return s_effectName; +} + +void SourceGraphic::determineAbsolutePaintRect() +{ + Filter* filter = this->filter(); + FloatRect paintRect = filter->sourceImageRect(); + paintRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); + setAbsolutePaintRect(enclosingIntRect(paintRect)); +} + +void SourceGraphic::platformApplySoftware() +{ + ImageBuffer* resultImage = createImageBufferResult(); + Filter* filter = this->filter(); + if (!resultImage || !filter->sourceImage()) + return; + + resultImage->context()->drawImageBuffer(filter->sourceImage(), ColorSpaceDeviceRGB, IntPoint()); +} + +void SourceGraphic::dump() +{ +} + +TextStream& SourceGraphic::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[SourceGraphic]\n"; + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/SourceGraphic.h b/Source/WebCore/platform/graphics/filters/SourceGraphic.h new file mode 100644 index 000000000..06e6d09ba --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/SourceGraphic.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef SourceGraphic_h +#define SourceGraphic_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" + +#include "Filter.h" +#include "PlatformString.h" + +namespace WebCore { + +class SourceGraphic : public FilterEffect { +public: + static PassRefPtr<SourceGraphic> create(Filter*); + + static const AtomicString& effectName(); + + virtual void platformApplySoftware(); + virtual void dump(); + + virtual void determineAbsolutePaintRect(); + + virtual FilterEffectType filterEffectType() const { return FilterEffectTypeSourceInput; } + + virtual TextStream& externalRepresentation(TextStream&, int indention) const; + +private: + SourceGraphic(Filter* filter) + : FilterEffect(filter) + { + } +}; + +} //namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // SourceGraphic_h diff --git a/Source/WebCore/platform/graphics/filters/SpotLightSource.cpp b/Source/WebCore/platform/graphics/filters/SpotLightSource.cpp new file mode 100644 index 000000000..648fcae6d --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/SpotLightSource.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * Copyright (C) 2010 Zoltan Herczeg <zherczeg@webkit.org> + * Copyright (C) 2011 University of Szeged + * Copyright (C) 2011 Renata Hodovan <reni@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "SpotLightSource.h" + +#include "TextStream.h" + +namespace WebCore { + +// spot-light edge darkening depends on an absolute treshold +// according to the SVG 1.1 SE light regression tests +static const float antiAliasTreshold = 0.016f; + +void SpotLightSource::initPaintingData(PaintingData& paintingData) +{ + paintingData.privateColorVector = paintingData.colorVector; + paintingData.directionVector.setX(m_direction.x() - m_position.x()); + paintingData.directionVector.setY(m_direction.y() - m_position.y()); + paintingData.directionVector.setZ(m_direction.z() - m_position.z()); + paintingData.directionVector.normalize(); + + if (!m_limitingConeAngle) { + paintingData.coneCutOffLimit = 0.0f; + paintingData.coneFullLight = -antiAliasTreshold; + } else { + float limitingConeAngle = m_limitingConeAngle; + if (limitingConeAngle < 0.0f) + limitingConeAngle = -limitingConeAngle; + if (limitingConeAngle > 90.0f) + limitingConeAngle = 90.0f; + paintingData.coneCutOffLimit = cosf(deg2rad(180.0f - limitingConeAngle)); + paintingData.coneFullLight = paintingData.coneCutOffLimit - antiAliasTreshold; + } + + // Optimization for common specularExponent values + if (!m_specularExponent) + paintingData.specularExponent = 0; + else if (m_specularExponent == 1.0f) + paintingData.specularExponent = 1; + else // It is neither 0.0f nor 1.0f + paintingData.specularExponent = 2; +} + +void SpotLightSource::updatePaintingData(PaintingData& paintingData, int x, int y, float z) +{ + paintingData.lightVector.setX(m_position.x() - x); + paintingData.lightVector.setY(m_position.y() - y); + paintingData.lightVector.setZ(m_position.z() - z); + paintingData.lightVectorLength = paintingData.lightVector.length(); + + float cosineOfAngle = (paintingData.lightVector * paintingData.directionVector) / paintingData.lightVectorLength; + if (cosineOfAngle > paintingData.coneCutOffLimit) { + // No light is produced, scanlines are not updated + paintingData.colorVector.setX(0.0f); + paintingData.colorVector.setY(0.0f); + paintingData.colorVector.setZ(0.0f); + return; + } + + // Set the color of the pixel + float lightStrength; + switch (paintingData.specularExponent) { + case 0: + lightStrength = 1.0f; // -cosineOfAngle ^ 0 == 1 + break; + case 1: + lightStrength = -cosineOfAngle; // -cosineOfAngle ^ 1 == -cosineOfAngle + break; + default: + lightStrength = powf(-cosineOfAngle, m_specularExponent); + break; + } + + if (cosineOfAngle > paintingData.coneFullLight) + lightStrength *= (paintingData.coneCutOffLimit - cosineOfAngle) / (paintingData.coneCutOffLimit - paintingData.coneFullLight); + + if (lightStrength > 1.0f) + lightStrength = 1.0f; + + paintingData.colorVector.setX(paintingData.privateColorVector.x() * lightStrength); + paintingData.colorVector.setY(paintingData.privateColorVector.y() * lightStrength); + paintingData.colorVector.setZ(paintingData.privateColorVector.z() * lightStrength); +} + +bool SpotLightSource::setX(float x) +{ + if (m_position.x() == x) + return false; + m_position.setX(x); + return true; +} + +bool SpotLightSource::setY(float y) +{ + if (m_position.y() == y) + return false; + m_position.setY(y); + return true; +} + +bool SpotLightSource::setZ(float z) +{ + if (m_position.z() == z) + return false; + m_position.setZ(z); + return true; +} + +bool SpotLightSource::setPointsAtX(float pointsAtX) +{ + if (m_direction.x() == pointsAtX) + return false; + m_direction.setX(pointsAtX); + return true; +} + +bool SpotLightSource::setPointsAtY(float pointsAtY) +{ + if (m_direction.y() == pointsAtY) + return false; + m_direction.setY(pointsAtY); + return true; +} + +bool SpotLightSource::setPointsAtZ(float pointsAtZ) +{ + if (m_direction.z() == pointsAtZ) + return false; + m_direction.setZ(pointsAtZ); + return true; +} + +bool SpotLightSource::setSpecularExponent(float specularExponent) +{ + if (m_specularExponent == specularExponent) + return false; + m_specularExponent = specularExponent; + return true; +} + +bool SpotLightSource::setLimitingConeAngle(float limitingConeAngle) +{ + if (m_limitingConeAngle == limitingConeAngle) + return false; + m_limitingConeAngle = limitingConeAngle; + return true; +} + +static TextStream& operator<<(TextStream& ts, const FloatPoint3D& p) +{ + ts << "x=" << p.x() << " y=" << p.y() << " z=" << p.z(); + return ts; +} + +TextStream& SpotLightSource::externalRepresentation(TextStream& ts) const +{ + ts << "[type=SPOT-LIGHT] "; + ts << "[position=\"" << position() << "\"]"; + ts << "[direction=\"" << direction() << "\"]"; + ts << "[specularExponent=\"" << specularExponent() << "\"]"; + ts << "[limitingConeAngle=\"" << limitingConeAngle() << "\"]"; + return ts; +} + +}; // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/SpotLightSource.h b/Source/WebCore/platform/graphics/filters/SpotLightSource.h new file mode 100644 index 000000000..b4f1b6182 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/SpotLightSource.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> + * Copyright (C) 2005 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef SpotLightSource_h +#define SpotLightSource_h + +#if ENABLE(FILTERS) +#include "LightSource.h" + +namespace WebCore { + +class SpotLightSource : public LightSource { +public: + static PassRefPtr<SpotLightSource> create(const FloatPoint3D& position, + const FloatPoint3D& direction, float specularExponent, float limitingConeAngle) + { + return adoptRef(new SpotLightSource(position, direction, specularExponent, limitingConeAngle)); + } + + const FloatPoint3D& position() const { return m_position; } + bool setX(float); + bool setY(float); + bool setZ(float); + const FloatPoint3D& direction() const { return m_direction; } + bool setPointsAtX(float); + bool setPointsAtY(float); + bool setPointsAtZ(float); + + float specularExponent() const { return m_specularExponent; } + bool setSpecularExponent(float); + float limitingConeAngle() const { return m_limitingConeAngle; } + bool setLimitingConeAngle(float); + + virtual void initPaintingData(PaintingData&); + virtual void updatePaintingData(PaintingData&, int x, int y, float z); + + virtual TextStream& externalRepresentation(TextStream&) const; + +private: + SpotLightSource(const FloatPoint3D& position, const FloatPoint3D& direction, + float specularExponent, float limitingConeAngle) + : LightSource(LS_SPOT) + , m_position(position) + , m_direction(direction) + , m_specularExponent(specularExponent) + , m_limitingConeAngle(limitingConeAngle) + { + } + + FloatPoint3D m_position; + FloatPoint3D m_direction; + + float m_specularExponent; + float m_limitingConeAngle; +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // SpotLightSource_h diff --git a/Source/WebCore/platform/graphics/filters/arm/FECompositeArithmeticNEON.cpp b/Source/WebCore/platform/graphics/filters/arm/FECompositeArithmeticNEON.cpp new file mode 100644 index 000000000..22a845823 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/arm/FECompositeArithmeticNEON.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2011 University of Szeged + * Copyright (C) 2011 Felician Marton + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FECompositeArithmeticNEON.h" + +#if CPU(ARM_NEON) && COMPILER(GCC) + +namespace WebCore { + +#define ASSTRING(str) #str +#define TOSTRING(value) ASSTRING(value) + +#define NL "\n" + +#define SOURCE_R "r0" +#define DEST_R "r1" +#define END_R "r2" +#define K_R "r3" +#define NEXTPIXEL_R "r12" + +#define TEMP_Q "q0" +#define TEMP_D0 "d0" +#define TEMP_D00 "d0[0]" +#define TEMP_D01 "d0[1]" +#define TEMP_D10 "d1[0]" +#define TEMP_D11 "d1[1]" +#define PIXEL1_Q "q1" +#define PIXEL1_D0 "d2" +#define PIXEL1_D00 "d2[0]" +#define PIXEL2_Q "q2" +#define PIXEL2_D0 "d4" +#define PIXEL2_D00 "d4[0]" +#define BYTEMAX_Q "q3" +#define K1_Q "q8" +#define K2_Q "q9" +#define K3_Q "q10" +#define K4_Q "q11" + +asm ( // NOLINT +".globl " TOSTRING(neonDrawCompositeArithmetic) NL +TOSTRING(neonDrawCompositeArithmetic) ":" NL + "cmp " END_R ", #0" NL + "bxeq lr" NL + // Set the end of the source register. + "add " END_R ", " SOURCE_R ", " END_R NL + + "vld1.f32 {" TEMP_Q "}, [" K_R "]" NL + "ldr " K_R ", [" K_R "]" NL + "vdup.f32 " K1_Q ", " TEMP_D00 NL + "vdup.f32 " K2_Q ", " TEMP_D01 NL + "vdup.f32 " K3_Q ", " TEMP_D10 NL + "vdup.f32 " K4_Q ", " TEMP_D11 NL + + "vmov.i32 " BYTEMAX_Q ", #0xFF" NL + "vcvt.f32.u32 " TEMP_Q ", " BYTEMAX_Q NL + "vmul.f32 " K4_Q ", " K4_Q ", " TEMP_Q NL + + "mov " NEXTPIXEL_R ", #4" NL + "cmp " K_R ", #0" NL + "beq .arithmeticK1IsZero" NL + + "vrecpe.f32 " TEMP_Q ", " TEMP_Q NL + "vmul.f32 " K1_Q ", " K1_Q ", " TEMP_Q NL + +".arithmeticK1IsNonZero:" NL + + "vld1.u32 " PIXEL1_D00 ", [ " SOURCE_R "], " NEXTPIXEL_R NL + "vld1.u32 " PIXEL2_D00 ", [" DEST_R "]" NL + + "vmovl.u8 " PIXEL1_Q ", " PIXEL1_D0 NL + "vmovl.u16 " PIXEL1_Q ", " PIXEL1_D0 NL + "vcvt.f32.u32 " PIXEL1_Q ", " PIXEL1_Q NL + "vmovl.u8 " PIXEL2_Q ", " PIXEL2_D0 NL + "vmovl.u16 " PIXEL2_Q ", " PIXEL2_D0 NL + "vcvt.f32.u32 " PIXEL2_Q ", " PIXEL2_Q NL + + "vmul.f32 " TEMP_Q ", " PIXEL1_Q ", " PIXEL2_Q NL + "vmul.f32 " TEMP_Q ", " TEMP_Q ", " K1_Q NL + "vmla.f32 " TEMP_Q ", " PIXEL1_Q ", " K2_Q NL + "vmla.f32 " TEMP_Q ", " PIXEL2_Q ", " K3_Q NL + "vadd.f32 " TEMP_Q ", " K4_Q NL + + // Convert result to uint so negative values are converted to zero. + "vcvt.u32.f32 " TEMP_Q ", " TEMP_Q NL + "vmin.u32 " TEMP_Q ", " TEMP_Q ", " BYTEMAX_Q NL + "vmovn.u32 " TEMP_D0 ", " TEMP_Q NL + "vmovn.u16 " TEMP_D0 ", " TEMP_Q NL + + "vst1.u32 " TEMP_D00 ", [" DEST_R "], " NEXTPIXEL_R NL + + "cmp " SOURCE_R ", " END_R NL + "bcc .arithmeticK1IsNonZero" NL + "bx lr" NL + +".arithmeticK1IsZero:" NL + + "vld1.u32 " PIXEL1_D00 ", [ " SOURCE_R "], " NEXTPIXEL_R NL + "vld1.u32 " PIXEL2_D00 ", [" DEST_R "]" NL + + "vmovl.u8 " PIXEL1_Q ", " PIXEL1_D0 NL + "vmovl.u16 " PIXEL1_Q ", " PIXEL1_D0 NL + "vcvt.f32.u32 " PIXEL1_Q ", " PIXEL1_Q NL + "vmovl.u8 " PIXEL2_Q ", " PIXEL2_D0 NL + "vmovl.u16 " PIXEL2_Q ", " PIXEL2_D0 NL + "vcvt.f32.u32 " PIXEL2_Q ", " PIXEL2_Q NL + + "vmul.f32 " TEMP_Q ", " PIXEL1_Q ", " K2_Q NL + "vmla.f32 " TEMP_Q ", " PIXEL2_Q ", " K3_Q NL + "vadd.f32 " TEMP_Q ", " K4_Q NL + + // Convert result to uint so negative values are converted to zero. + "vcvt.u32.f32 " TEMP_Q ", " TEMP_Q NL + "vmin.u32 " TEMP_Q ", " TEMP_Q ", " BYTEMAX_Q NL + "vmovn.u32 " TEMP_D0 ", " TEMP_Q NL + "vmovn.u16 " TEMP_D0 ", " TEMP_Q NL + + "vst1.u32 " TEMP_D00 ", [" DEST_R "], " NEXTPIXEL_R NL + + "cmp " SOURCE_R ", " END_R NL + "bcc .arithmeticK1IsZero" NL + "bx lr" NL +); // NOLINT + +} // namespace WebCore + +#endif // CPU(ARM_NEON) && COMPILER(GCC) + +#endif // ENABLE(FILTERS) + diff --git a/Source/WebCore/platform/graphics/filters/arm/FECompositeArithmeticNEON.h b/Source/WebCore/platform/graphics/filters/arm/FECompositeArithmeticNEON.h new file mode 100644 index 000000000..a2b3f6f4d --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/arm/FECompositeArithmeticNEON.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 University of Szeged + * Copyright (C) 2011 Felician Marton + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FECompositeArithmeticNEON_h +#define FECompositeArithmeticNEON_h + +#include <wtf/Platform.h> + +#if ENABLE(FILTERS) +#if CPU(ARM_NEON) && COMPILER(GCC) + +#include "FEComposite.h" + +namespace WebCore { + +extern "C" { +void neonDrawCompositeArithmetic(unsigned char* source, unsigned char* destination, unsigned pixelArrayLength, float* coefficients); +} + +inline void FEComposite::platformArithmeticNeon(unsigned char* source, unsigned char* destination, unsigned pixelArrayLength, float* coefficients) +{ + neonDrawCompositeArithmetic(source, destination, pixelArrayLength, coefficients); +} + +} // namespace WebCore + +#endif // CPU(ARM_NEON) && COMPILER(GCC) +#endif // ENABLE(FILTERS) + +#endif // FECompositeArithmeticNEON_h diff --git a/Source/WebCore/platform/graphics/filters/arm/FEGaussianBlurNEON.cpp b/Source/WebCore/platform/graphics/filters/arm/FEGaussianBlurNEON.cpp new file mode 100644 index 000000000..d17f2caf4 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/arm/FEGaussianBlurNEON.cpp @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2011 University of Szeged + * Copyright (C) 2011 Zoltan Herczeg + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FEGaussianBlurNEON.h" + +#if CPU(ARM_NEON) && COMPILER(GCC) + +#include <wtf/Alignment.h> + +namespace WebCore { + +static WTF_ALIGNED(unsigned char, s_FEGaussianBlurConstantsForNeon[], 16) = { + // Mapping from NEON to ARM registers. + 0, 4, 8, 12, 16, 16, 16, 16 +}; + +unsigned char* feGaussianBlurConstantsForNeon() +{ + return s_FEGaussianBlurConstantsForNeon; +} + +#define ASSTRING(str) #str +#define TOSTRING(value) ASSTRING(value) + +#define STRIDE_OFFSET TOSTRING(0) +#define STRIDE_WIDTH_OFFSET TOSTRING(4) +#define STRIDE_LINE_OFFSET TOSTRING(8) +#define STRIDE_LINE_WIDTH_OFFSET TOSTRING(12) +#define REMAINING_STRIDES_OFFSET TOSTRING(16) +#define DISTANCE_LEFT_OFFSET TOSTRING(20) +#define DISTANCE_RIGHT_OFFSET TOSTRING(24) +#define INVERTED_KERNEL_SIZE_OFFSET TOSTRING(28) +#define PAINTING_CONSTANTS_OFFSET TOSTRING(32) +#define NL "\n" + +// Register allocation. +#define SOURCE_R "r0" +#define DESTINATION_R "r1" +#define LEFT_R "r2" +#define RIGHT_R "r3" +#define SOURCE_END_R "r4" +#define DESTINATION_END_R "r5" +#define STRIDE_R "r6" +#define STRIDE_WIDTH_R "r7" +#define STRIDE_LINE_R "r8" +#define SOURCE_LINE_END_R "r10" +#define DISTANCE_LEFT_R "r11" +#define DISTANCE_RIGHT_R "r12" +#define MAX_KERNEL_SIZE_R "lr" + +// Alternate names. +#define INIT_INVERTED_KERNEL_SIZE_R SOURCE_END_R +#define INIT_PAINTING_CONSTANTS_R DESTINATION_END_R +#define INIT_SUM_R LEFT_R +#define REMAINING_STRIDES_R SOURCE_LINE_END_R + +#define INVERTED_KERNEL_SIZE_Q "q0" +#define SUM_Q "q1" +#define PIXEL_Q "q2" +#define PIXEL_D0 "d4" +#define PIXEL_D1 "d5" +#define PIXEL_D00 "d4[0]" +#define PIXEL_D01 "d4[1]" +#define PIXEL_S1 "s9" +#define PIXEL_D10 "d5[0]" +#define PIXEL_S2 "s10" +#define PIXEL_D11 "d5[1]" +#define REMAINING_STRIDES_S0 "s12" + +#define REMAP_NEON_ARM_Q "d16" + +asm ( // NOLINT +".globl " TOSTRING(neonDrawAllChannelGaussianBlur) NL +TOSTRING(neonDrawAllChannelGaussianBlur) ":" NL + "stmdb sp!, {r4-r8, r10, r11, lr}" NL + "ldr " STRIDE_R ", [r2, #" STRIDE_OFFSET "]" NL + "ldr " STRIDE_WIDTH_R ", [r2, #" STRIDE_WIDTH_OFFSET "]" NL + "ldr " DISTANCE_LEFT_R ", [r2, #" DISTANCE_LEFT_OFFSET "]" NL + "ldr " DISTANCE_RIGHT_R ", [r2, #" DISTANCE_RIGHT_OFFSET "]" NL + "ldr " STRIDE_LINE_R ", [r2, #" STRIDE_LINE_OFFSET "]" NL + "ldr " SOURCE_LINE_END_R ", [r2, #" STRIDE_LINE_WIDTH_OFFSET "]" NL + "ldr " INIT_INVERTED_KERNEL_SIZE_R ", [r2, #" INVERTED_KERNEL_SIZE_OFFSET "]" NL + "ldr " INIT_PAINTING_CONSTANTS_R ", [r2, #" PAINTING_CONSTANTS_OFFSET "]" NL + + // Initialize locals. + "mul " DISTANCE_LEFT_R ", " DISTANCE_LEFT_R ", " STRIDE_R NL + "mul " DISTANCE_RIGHT_R ", " DISTANCE_RIGHT_R ", " STRIDE_R NL + "mov " MAX_KERNEL_SIZE_R ", " DISTANCE_RIGHT_R NL + "cmp " MAX_KERNEL_SIZE_R ", " STRIDE_WIDTH_R NL + "movcs " MAX_KERNEL_SIZE_R ", " STRIDE_WIDTH_R NL + "add " SOURCE_LINE_END_R ", " SOURCE_LINE_END_R ", " SOURCE_R NL + "vdup.f32 " INVERTED_KERNEL_SIZE_Q ", " INIT_INVERTED_KERNEL_SIZE_R NL + "vld1.f32 { " REMAP_NEON_ARM_Q " }, [" INIT_PAINTING_CONSTANTS_R "]!" NL + +".allChannelMainLoop:" NL + + // Initialize the sum variable. + "vmov.u32 " SUM_Q ", #0" NL + "mov " INIT_SUM_R ", " SOURCE_R NL + "add " SOURCE_END_R ", " SOURCE_R ", " MAX_KERNEL_SIZE_R NL + "cmp " INIT_SUM_R ", " SOURCE_END_R NL + "bcs .allChannelInitSumDone" NL +".allChannelInitSum:" NL + "vld1.u32 " PIXEL_D00 ", [" INIT_SUM_R "], " STRIDE_R NL + "vmovl.u8 " PIXEL_Q ", " PIXEL_D0 NL + "vmovl.u16 " PIXEL_Q ", " PIXEL_D0 NL + "vadd.u32 " SUM_Q ", " SUM_Q ", " PIXEL_Q NL + "cmp " INIT_SUM_R ", " SOURCE_END_R NL + "bcc .allChannelInitSum" NL +".allChannelInitSumDone:" NL + + // Blurring. + "add " SOURCE_END_R ", " SOURCE_R ", " STRIDE_WIDTH_R NL + "add " DESTINATION_END_R ", " DESTINATION_R ", " STRIDE_WIDTH_R NL + "sub " LEFT_R ", " SOURCE_R ", " DISTANCE_LEFT_R NL + "add " RIGHT_R ", " SOURCE_R ", " DISTANCE_RIGHT_R NL + +".allChannelBlur:" NL + "vcvt.f32.u32 " PIXEL_Q ", " SUM_Q NL + "vmul.f32 " PIXEL_Q ", " PIXEL_Q ", " INVERTED_KERNEL_SIZE_Q NL + "vcvt.u32.f32 " PIXEL_Q ", " PIXEL_Q NL + "vtbl.8 " PIXEL_D0 ", {" PIXEL_D0 "-" PIXEL_D1 "}, " REMAP_NEON_ARM_Q NL + "vst1.u32 " PIXEL_D00 ", [" DESTINATION_R "], " STRIDE_R NL + + "cmp " LEFT_R ", " SOURCE_R NL + "bcc .allChannelSkipLeft" NL + "vld1.u32 " PIXEL_D00 ", [" LEFT_R "]" NL + "vmovl.u8 " PIXEL_Q ", " PIXEL_D0 NL + "vmovl.u16 " PIXEL_Q ", " PIXEL_D0 NL + "vsub.u32 " SUM_Q ", " SUM_Q ", " PIXEL_Q NL +".allChannelSkipLeft: " NL + + "cmp " RIGHT_R ", " SOURCE_END_R NL + "bcs .allChannelSkipRight" NL + "vld1.u32 " PIXEL_D00 ", [" RIGHT_R "]" NL + "vmovl.u8 " PIXEL_Q ", " PIXEL_D0 NL + "vmovl.u16 " PIXEL_Q ", " PIXEL_D0 NL + "vadd.u32 " SUM_Q ", " SUM_Q ", " PIXEL_Q NL +".allChannelSkipRight: " NL + + "add " LEFT_R ", " LEFT_R ", " STRIDE_R NL + "add " RIGHT_R ", " RIGHT_R ", " STRIDE_R NL + "cmp " DESTINATION_R ", " DESTINATION_END_R NL + "bcc .allChannelBlur" NL + "sub " DESTINATION_R ", " DESTINATION_R ", " STRIDE_WIDTH_R NL + + "add " SOURCE_R ", " SOURCE_R ", " STRIDE_LINE_R NL + "add " DESTINATION_R ", " DESTINATION_R ", " STRIDE_LINE_R NL + "cmp " SOURCE_R ", " SOURCE_LINE_END_R NL + "bcc .allChannelMainLoop" NL + + "ldmia sp!, {r4-r8, r10, r11, pc}" NL +); // NOLINT + +#define DATA_TRANSFER4(command, base) \ + command " " PIXEL_D00 ", [" base "], " STRIDE_LINE_R NL \ + command " " PIXEL_D01 ", [" base "], " STRIDE_LINE_R NL \ + command " " PIXEL_D10 ", [" base "], " STRIDE_LINE_R NL \ + command " " PIXEL_D11 ", [" base "], " STRIDE_LINE_R NL \ + "sub " base ", " base ", " STRIDE_LINE_R ", lsl #2" NL + +// The number of reads depend on REMAINING_STRIDES_R, but it is always >= 1 and <= 3 +#define CONDITIONAL_DATA_TRANSFER4(command1, command2, base) \ + command1 " " PIXEL_D00 ", [" base "], " STRIDE_LINE_R NL \ + "cmp " REMAINING_STRIDES_R ", #2" NL \ + command2 "cs " PIXEL_S1 ", [" base "]" NL \ + "add " base ", " base ", " STRIDE_LINE_R NL \ + "cmp " REMAINING_STRIDES_R ", #3" NL \ + command2 "cs " PIXEL_S2 ", [" base "]" NL \ + "sub " base ", " base ", " STRIDE_LINE_R ", lsl #1" NL + +asm ( // NOLINT +".globl " TOSTRING(neonDrawAlphaChannelGaussianBlur) NL +TOSTRING(neonDrawAlphaChannelGaussianBlur) ":" NL + "stmdb sp!, {r4-r8, r10, r11, lr}" NL + "ldr " STRIDE_R ", [r2, #" STRIDE_OFFSET "]" NL + "ldr " STRIDE_WIDTH_R ", [r2, #" STRIDE_WIDTH_OFFSET "]" NL + "ldr " DISTANCE_LEFT_R ", [r2, #" DISTANCE_LEFT_OFFSET "]" NL + "ldr " DISTANCE_RIGHT_R ", [r2, #" DISTANCE_RIGHT_OFFSET "]" NL + "ldr " STRIDE_LINE_R ", [r2, #" STRIDE_LINE_OFFSET "]" NL + "ldr " SOURCE_LINE_END_R ", [r2, #" STRIDE_LINE_WIDTH_OFFSET "]" NL + "ldr " INIT_INVERTED_KERNEL_SIZE_R ", [r2, #" INVERTED_KERNEL_SIZE_OFFSET "]" NL + "vldr.u32 " REMAINING_STRIDES_S0 ", [r2, #" REMAINING_STRIDES_OFFSET "]" NL + + // Initialize locals. + "mul " DISTANCE_LEFT_R ", " DISTANCE_LEFT_R ", " STRIDE_R NL + "mul " DISTANCE_RIGHT_R ", " DISTANCE_RIGHT_R ", " STRIDE_R NL + "mov " MAX_KERNEL_SIZE_R ", " DISTANCE_RIGHT_R NL + "cmp " MAX_KERNEL_SIZE_R ", " STRIDE_WIDTH_R NL + "movcs " MAX_KERNEL_SIZE_R ", " STRIDE_WIDTH_R NL + "add " SOURCE_LINE_END_R ", " SOURCE_LINE_END_R ", " SOURCE_R NL + "vdup.f32 " INVERTED_KERNEL_SIZE_Q ", " INIT_INVERTED_KERNEL_SIZE_R NL + "cmp " SOURCE_LINE_END_R ", " SOURCE_R NL + "beq .alphaChannelEarlyLeave" NL + + // Processing 4 strides parallelly. + +".alphaChannelMainLoop:" NL + + // Initialize the sum variable. + "vmov.u32 " SUM_Q ", #0" NL + "mov " INIT_SUM_R ", " SOURCE_R NL + "add " SOURCE_END_R ", " SOURCE_R ", " MAX_KERNEL_SIZE_R NL + "cmp " INIT_SUM_R ", " SOURCE_END_R NL + "bcs .alphaChannelInitSumDone" NL +".alphaChannelInitSum:" NL + DATA_TRANSFER4("vld1.u32", INIT_SUM_R) + "vshr.u32 " PIXEL_Q ", " PIXEL_Q ", #24" NL + "vadd.u32 " SUM_Q ", " SUM_Q ", " PIXEL_Q NL + "add " INIT_SUM_R ", " INIT_SUM_R ", " STRIDE_R NL + "cmp " INIT_SUM_R ", " SOURCE_END_R NL + "bcc .alphaChannelInitSum" NL +".alphaChannelInitSumDone:" NL + + // Blurring. + "add " SOURCE_END_R ", " SOURCE_R ", " STRIDE_WIDTH_R NL + "add " DESTINATION_END_R ", " DESTINATION_R ", " STRIDE_WIDTH_R NL + "sub " LEFT_R ", " SOURCE_R ", " DISTANCE_LEFT_R NL + "add " RIGHT_R ", " SOURCE_R ", " DISTANCE_RIGHT_R NL + +".alphaChannelBlur:" NL + "vcvt.f32.u32 " PIXEL_Q ", " SUM_Q NL + "vmul.f32 " PIXEL_Q ", " PIXEL_Q ", " INVERTED_KERNEL_SIZE_Q NL + "vcvt.u32.f32 " PIXEL_Q ", " PIXEL_Q NL + "vshl.u32 " PIXEL_Q ", " PIXEL_Q ", #24" NL + DATA_TRANSFER4("vst1.u32", DESTINATION_R) + + "cmp " LEFT_R ", " SOURCE_R NL + "bcc .alphaChannelSkipLeft" NL + DATA_TRANSFER4("vld1.u32", LEFT_R) + "vshr.u32 " PIXEL_Q ", " PIXEL_Q ", #24" NL + "vsub.u32 " SUM_Q ", " SUM_Q ", " PIXEL_Q NL +".alphaChannelSkipLeft: " NL + + "cmp " RIGHT_R ", " SOURCE_END_R NL + "bcs .alphaChannelSkipRight" NL + DATA_TRANSFER4("vld1.u32", RIGHT_R) + "vshr.u32 " PIXEL_Q ", " PIXEL_Q ", #24" NL + "vadd.u32 " SUM_Q ", " SUM_Q ", " PIXEL_Q NL +".alphaChannelSkipRight: " NL + + "add " DESTINATION_R ", " DESTINATION_R ", " STRIDE_R NL + "add " LEFT_R ", " LEFT_R ", " STRIDE_R NL + "add " RIGHT_R ", " RIGHT_R ", " STRIDE_R NL + "cmp " DESTINATION_R ", " DESTINATION_END_R NL + "bcc .alphaChannelBlur" NL + "sub " DESTINATION_R ", " DESTINATION_R ", " STRIDE_WIDTH_R NL + + "add " SOURCE_R ", " SOURCE_R ", " STRIDE_LINE_R ", lsl #2" NL + "add " DESTINATION_R ", " DESTINATION_R ", " STRIDE_LINE_R ", lsl #2" NL + "cmp " SOURCE_R ", " SOURCE_LINE_END_R NL + "bcc .alphaChannelMainLoop" NL + + // Processing the remaining strides (0 - 3). +".alphaChannelEarlyLeave:" NL + "vmov.u32 " REMAINING_STRIDES_R ", " REMAINING_STRIDES_S0 NL + // Early return for 0 strides. + "cmp " REMAINING_STRIDES_R ", #0" NL + "ldmeqia sp!, {r4-r8, r10, r11, pc}" NL + + // Initialize the sum variable. + "vmov.u32 " SUM_Q ", #0" NL + "mov " INIT_SUM_R ", " SOURCE_R NL + "add " SOURCE_END_R ", " SOURCE_R ", " MAX_KERNEL_SIZE_R NL + "cmp " INIT_SUM_R ", " SOURCE_END_R NL + "bcs .alphaChannelSecondInitSumDone" NL +".alphaChannelSecondInitSum:" NL + CONDITIONAL_DATA_TRANSFER4("vld1.u32", "vldr", INIT_SUM_R) + "vshr.u32 " PIXEL_Q ", " PIXEL_Q ", #24" NL + "vadd.u32 " SUM_Q ", " SUM_Q ", " PIXEL_Q NL + "add " INIT_SUM_R ", " INIT_SUM_R ", " STRIDE_R NL + "cmp " INIT_SUM_R ", " SOURCE_END_R NL + "bcc .alphaChannelSecondInitSum" NL +".alphaChannelSecondInitSumDone:" NL + + // Blurring. + "add " SOURCE_END_R ", " SOURCE_R ", " STRIDE_WIDTH_R NL + "add " DESTINATION_END_R ", " DESTINATION_R ", " STRIDE_WIDTH_R NL + "sub " LEFT_R ", " SOURCE_R ", " DISTANCE_LEFT_R NL + "add " RIGHT_R ", " SOURCE_R ", " DISTANCE_RIGHT_R NL + +".alphaChannelSecondBlur:" NL + "vcvt.f32.u32 " PIXEL_Q ", " SUM_Q NL + "vmul.f32 " PIXEL_Q ", " PIXEL_Q ", " INVERTED_KERNEL_SIZE_Q NL + "vcvt.u32.f32 " PIXEL_Q ", " PIXEL_Q NL + "vshl.u32 " PIXEL_Q ", " PIXEL_Q ", #24" NL + CONDITIONAL_DATA_TRANSFER4("vst1.u32", "vstr", DESTINATION_R) + + "cmp " LEFT_R ", " SOURCE_R NL + "bcc .alphaChannelSecondSkipLeft" NL + CONDITIONAL_DATA_TRANSFER4("vld1.u32", "vldr", LEFT_R) + "vshr.u32 " PIXEL_Q ", " PIXEL_Q ", #24" NL + "vsub.u32 " SUM_Q ", " SUM_Q ", " PIXEL_Q NL +".alphaChannelSecondSkipLeft: " NL + + "cmp " RIGHT_R ", " SOURCE_END_R NL + "bcs .alphaChannelSecondSkipRight" NL + CONDITIONAL_DATA_TRANSFER4("vld1.u32", "vldr", RIGHT_R) + "vshr.u32 " PIXEL_Q ", " PIXEL_Q ", #24" NL + "vadd.u32 " SUM_Q ", " SUM_Q ", " PIXEL_Q NL +".alphaChannelSecondSkipRight: " NL + + "add " DESTINATION_R ", " DESTINATION_R ", " STRIDE_R NL + "add " LEFT_R ", " LEFT_R ", " STRIDE_R NL + "add " RIGHT_R ", " RIGHT_R ", " STRIDE_R NL + "cmp " DESTINATION_R ", " DESTINATION_END_R NL + "bcc .alphaChannelSecondBlur" NL + + "ldmia sp!, {r4-r8, r10, r11, pc}" NL +); // NOLINT + +} // namespace WebCore + +#endif // CPU(ARM_NEON) && COMPILER(GCC) diff --git a/Source/WebCore/platform/graphics/filters/arm/FEGaussianBlurNEON.h b/Source/WebCore/platform/graphics/filters/arm/FEGaussianBlurNEON.h new file mode 100644 index 000000000..96037aab9 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/arm/FEGaussianBlurNEON.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2011 University of Szeged + * Copyright (C) 2011 Zoltan Herczeg + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FEGaussianBlurNEON_h +#define FEGaussianBlurNEON_h + +#include <wtf/Platform.h> + +#if CPU(ARM_NEON) && COMPILER(GCC) + +#include "FEGaussianBlur.h" + +namespace WebCore { + +struct FEGaussianBlurPaintingDataForNeon { + int stride; + int strideWidth; + int strideLine; + int strideLineWidth; + int remainingStrides; + int distanceLeft; + int distanceRight; + float invertedKernelSize; + unsigned char* paintingConstants; +}; + +unsigned char* feGaussianBlurConstantsForNeon(); + +extern "C" { +void neonDrawAllChannelGaussianBlur(unsigned char* source, unsigned char* destination, FEGaussianBlurPaintingDataForNeon*); +void neonDrawAlphaChannelGaussianBlur(unsigned char* source, unsigned char* destination, FEGaussianBlurPaintingDataForNeon*); +} + +inline void FEGaussianBlur::platformApplyNeon(ByteArray* srcPixelArray, ByteArray* tmpPixelArray, unsigned kernelSizeX, unsigned kernelSizeY, IntSize& paintSize) +{ + const int widthMultipliedByFour = 4 * paintSize.width(); + FEGaussianBlurPaintingDataForNeon argumentsX = { + 4, + widthMultipliedByFour, + widthMultipliedByFour, + (isAlphaImage() ? ((paintSize.height() >> 2) << 2) : paintSize.height()) * widthMultipliedByFour, + isAlphaImage() ? (paintSize.height() & 0x3) : 0, + 0, + 0, + 0, + isAlphaImage() ? 0 : feGaussianBlurConstantsForNeon() + }; + FEGaussianBlurPaintingDataForNeon argumentsY = { + widthMultipliedByFour, + widthMultipliedByFour * paintSize.height(), + 4, + (isAlphaImage() ? ((paintSize.width() >> 2) << 2) : paintSize.width()) * 4, + isAlphaImage() ? (paintSize.width() & 0x3) : 0, + 0, + 0, + 0, + isAlphaImage() ? 0 : feGaussianBlurConstantsForNeon() + }; + + for (int i = 0; i < 3; ++i) { + if (kernelSizeX) { + kernelPosition(i, kernelSizeX, argumentsX.distanceLeft, argumentsX.distanceRight); + argumentsX.invertedKernelSize = 1 / static_cast<float>(kernelSizeX); + if (isAlphaImage()) + neonDrawAlphaChannelGaussianBlur(srcPixelArray->data(), tmpPixelArray->data(), &argumentsX); + else + neonDrawAllChannelGaussianBlur(srcPixelArray->data(), tmpPixelArray->data(), &argumentsX); + } else { + ByteArray* auxPixelArray = tmpPixelArray; + tmpPixelArray = srcPixelArray; + srcPixelArray = auxPixelArray; + } + + if (kernelSizeY) { + kernelPosition(i, kernelSizeY, argumentsY.distanceLeft, argumentsY.distanceRight); + argumentsY.invertedKernelSize = 1 / static_cast<float>(kernelSizeY); + if (isAlphaImage()) + neonDrawAlphaChannelGaussianBlur(tmpPixelArray->data(), srcPixelArray->data(), &argumentsY); + else + neonDrawAllChannelGaussianBlur(tmpPixelArray->data(), srcPixelArray->data(), &argumentsY); + } else { + ByteArray* auxPixelArray = tmpPixelArray; + tmpPixelArray = srcPixelArray; + srcPixelArray = auxPixelArray; + } + } +} + +} // namespace WebCore + +#endif // CPU(ARM_NEON) && COMPILER(GCC) + +#endif // FEGaussianBlurNEON_h diff --git a/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.cpp b/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.cpp new file mode 100644 index 000000000..110b528c4 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.cpp @@ -0,0 +1,504 @@ +/* + * Copyright (C) 2011 University of Szeged + * Copyright (C) 2011 Zoltan Herczeg + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FELightingNEON.h" + +#if CPU(ARM_NEON) && COMPILER(GCC) + +#include <wtf/Alignment.h> + +namespace WebCore { + +// These constants are copied to the following SIMD registers: +// ALPHAX_Q ALPHAY_Q REMAPX_D REMAPY_D + +static WTF_ALIGNED(short, s_FELightingConstantsForNeon[], 16) = { + // Alpha coefficients. + -2, 1, 0, -1, 2, 1, 0, -1, + 0, -1, -2, -1, 0, 1, 2, 1, + // Remapping indicies. + 0x0f0e, 0x0302, 0x0504, 0x0706, + 0x0b0a, 0x1312, 0x1514, 0x1716, +}; + +short* feLightingConstantsForNeon() +{ + return s_FELightingConstantsForNeon; +} + +void FELighting::platformApplyNeonWorker(FELightingPaintingDataForNeon* parameters) +{ + neonDrawLighting(parameters); +} + +#define ASSTRING(str) #str +#define TOSTRING(value) ASSTRING(value) + +#define PIXELS_OFFSET TOSTRING(0) +#define YSTART_OFFSET TOSTRING(4) +#define WIDTH_OFFSET TOSTRING(8) +#define HEIGHT_OFFSET TOSTRING(12) +#define FLAGS_OFFSET TOSTRING(16) +#define SPECULAR_EXPONENT_OFFSET TOSTRING(20) +#define CONE_EXPONENT_OFFSET TOSTRING(24) +#define FLOAT_ARGUMENTS_OFFSET TOSTRING(28) +#define PAINTING_CONSTANTS_OFFSET TOSTRING(32) +#define NL "\n" + +// Register allocation +#define PAINTING_DATA_R "r11" +#define RESET_WIDTH_R PAINTING_DATA_R +#define PIXELS_R "r4" +#define WIDTH_R "r5" +#define HEIGHT_R "r6" +#define FLAGS_R "r7" +#define SPECULAR_EXPONENT_R "r8" +#define CONE_EXPONENT_R "r10" +#define SCANLINE_R "r12" + +#define TMP1_Q "q0" +#define TMP1_D0 "d0" +#define TMP1_S0 "s0" +#define TMP1_S1 "s1" +#define TMP1_D1 "d1" +#define TMP1_S2 "s2" +#define TMP1_S3 "s3" +#define TMP2_Q "q1" +#define TMP2_D0 "d2" +#define TMP2_S0 "s4" +#define TMP2_S1 "s5" +#define TMP2_D1 "d3" +#define TMP2_S2 "s6" +#define TMP2_S3 "s7" +#define TMP3_Q "q2" +#define TMP3_D0 "d4" +#define TMP3_S0 "s8" +#define TMP3_S1 "s9" +#define TMP3_D1 "d5" +#define TMP3_S2 "s10" +#define TMP3_S3 "s11" + +#define COSINE_OF_ANGLE "s12" +#define POWF_INT_S "s13" +#define POWF_FRAC_S "s14" +#define SPOT_COLOR_Q "q4" + +// Because of VMIN and VMAX CONST_ZERO_S and CONST_ONE_S +// must be placed on the same side of the double vector + +// Current pixel position +#define POSITION_Q "q5" +#define POSITION_X_S "s20" +#define POSITION_Y_S "s21" +#define POSITION_Z_S "s22" +#define CONST_ZERO_HI_D "d11" +#define CONST_ZERO_S "s23" + +// ------------------------------- +// Variable arguments +// Misc arguments +#define READ1_RANGE "d12-d15" +#define READ2_RANGE "d16-d19" +#define READ3_RANGE "d20-d21" + +#define SCALE_S "s24" +#define SCALE_DIV4_S "s25" +#define DIFFUSE_CONST_S "s26" + +// Light source position +#define CONE_CUT_OFF_S "s28" +#define CONE_FULL_LIGHT_S "s29" +#define CONE_CUT_OFF_RANGE_S "s30" +#define CONST_ONE_HI_D "d15" +#define CONST_ONE_S "s31" + +#define LIGHT_Q "q8" +#define DIRECTION_Q "q9" +#define COLOR_Q "q10" +// ------------------------------- +// Constant coefficients +#define READ4_RANGE "d22-d25" +#define READ5_RANGE "d26-d27" + +#define ALPHAX_Q "q11" +#define ALPHAY_Q "q12" +#define REMAPX_D "d26" +#define REMAPY_D "d27" +// ------------------------------- + +#define ALL_ROWS_D "{d28,d29,d30}" +#define TOP_ROW_D "d28" +#define MIDDLE_ROW_D "d29" +#define BOTTOM_ROW_D "d30" + +#define GET_LENGTH(source, temp) \ + "vmul.f32 " temp##_Q ", " source##_Q ", " source##_Q NL \ + "vadd.f32 " source##_S3 ", " temp##_S0 ", " temp##_S1 NL \ + "vadd.f32 " source##_S3 ", " source##_S3 ", " temp##_S2 NL \ + "vsqrt.f32 " source##_S3 ", " source##_S3 NL + +// destination##_S3 can contain the multiply of length. +#define DOT_PRODUCT(destination, source1, source2) \ + "vmul.f32 " destination##_Q ", " source1##_Q ", " source2##_Q NL \ + "vadd.f32 " destination##_S0 ", " destination##_S0 ", " destination##_S1 NL \ + "vadd.f32 " destination##_S0 ", " destination##_S0 ", " destination##_S2 NL + +#define MULTIPLY_BY_DIFFUSE_CONST(normalVectorLength, dotProductLength) \ + "tst " FLAGS_R ", #" TOSTRING(FLAG_DIFFUSE_CONST_IS_1) NL \ + "vmuleq.f32 " TMP2_S1 ", " DIFFUSE_CONST_S ", " normalVectorLength NL \ + "vdiveq.f32 " TMP2_S1 ", " TMP2_S1 ", " dotProductLength NL \ + "vdivne.f32 " TMP2_S1 ", " normalVectorLength ", " dotProductLength NL + +#define POWF_SQR(value, exponent, current, remaining) \ + "tst " exponent ", #" ASSTRING(current) NL \ + "vmulne.f32 " value ", " value ", " POWF_INT_S NL \ + "tst " exponent ", #" ASSTRING(remaining) NL \ + "vmulne.f32 " POWF_INT_S ", " POWF_INT_S ", " POWF_INT_S NL + +#define POWF_SQRT(value, exponent, current, remaining) \ + "tst " exponent ", #" ASSTRING(remaining) NL \ + "vsqrtne.f32 " POWF_FRAC_S ", " POWF_FRAC_S NL \ + "tst " exponent ", #" ASSTRING(current) NL \ + "vmulne.f32 " value ", " value ", " POWF_FRAC_S NL + +// This simplified powf function is sufficiently accurate. +#define POWF(value, exponent) \ + "tst " exponent ", #0xfc0" NL \ + "vmovne.f32 " POWF_INT_S ", " value NL \ + "tst " exponent ", #0x03f" NL \ + "vmovne.f32 " POWF_FRAC_S ", " value NL \ + "vmov.f32 " value ", " CONST_ONE_S NL \ + \ + POWF_SQR(value, exponent, 0x040, 0xf80) \ + POWF_SQR(value, exponent, 0x080, 0xf00) \ + POWF_SQR(value, exponent, 0x100, 0xe00) \ + POWF_SQR(value, exponent, 0x200, 0xc00) \ + POWF_SQR(value, exponent, 0x400, 0x800) \ + "tst " exponent ", #0x800" NL \ + "vmulne.f32 " value ", " value ", " POWF_INT_S NL \ + \ + POWF_SQRT(value, exponent, 0x20, 0x3f) \ + POWF_SQRT(value, exponent, 0x10, 0x1f) \ + POWF_SQRT(value, exponent, 0x08, 0x0f) \ + POWF_SQRT(value, exponent, 0x04, 0x07) \ + POWF_SQRT(value, exponent, 0x02, 0x03) \ + POWF_SQRT(value, exponent, 0x01, 0x01) + +// The following algorithm is an ARM-NEON optimized version of +// the main loop found in FELighting.cpp. Since the whole code +// is redesigned to be as effective as possible (ARM specific +// thinking), it is four times faster than its C++ counterpart. + +asm ( // NOLINT +".globl " TOSTRING(neonDrawLighting) NL +TOSTRING(neonDrawLighting) ":" NL + // Because of the clever register allocation, nothing is stored on the stack + // except the saved registers. + // Stack must be aligned to 8 bytes. + "stmdb sp!, {r4-r8, r10, r11, lr}" NL + "vstmdb sp!, {d8-d15}" NL + "mov " PAINTING_DATA_R ", r0" NL + + // The following two arguments are loaded to SIMD registers. + "ldr r0, [" PAINTING_DATA_R ", #" FLOAT_ARGUMENTS_OFFSET "]" NL + "ldr r1, [" PAINTING_DATA_R ", #" PAINTING_CONSTANTS_OFFSET "]" NL + "ldr " PIXELS_R ", [" PAINTING_DATA_R ", #" PIXELS_OFFSET "]" NL + "vldr.f32 " POSITION_Y_S ", [" PAINTING_DATA_R ", #" YSTART_OFFSET "]" NL + "ldr " WIDTH_R ", [" PAINTING_DATA_R ", #" WIDTH_OFFSET "]" NL + "ldr " HEIGHT_R ", [" PAINTING_DATA_R ", #" HEIGHT_OFFSET "]" NL + "ldr " FLAGS_R ", [" PAINTING_DATA_R ", #" FLAGS_OFFSET "]" NL + "ldr " SPECULAR_EXPONENT_R ", [" PAINTING_DATA_R ", #" SPECULAR_EXPONENT_OFFSET "]" NL + "ldr " CONE_EXPONENT_R ", [" PAINTING_DATA_R ", #" CONE_EXPONENT_OFFSET "]" NL + + // Load all data to the SIMD registers with the least number of instructions. + "vld1.f32 { " READ1_RANGE " }, [r0]!" NL + "vld1.f32 { " READ2_RANGE " }, [r0]!" NL + "vld1.f32 { " READ3_RANGE " }, [r0]!" NL + "vld1.s16 {" READ4_RANGE "}, [r1]!" NL + "vld1.s16 {" READ5_RANGE "}, [r1]!" NL + + // Initializing local variables. + "mov " SCANLINE_R ", " WIDTH_R ", lsl #2" NL + "add " SCANLINE_R ", " SCANLINE_R ", #8" NL + "add " PIXELS_R ", " PIXELS_R ", " SCANLINE_R NL + "add " PIXELS_R ", " PIXELS_R ", #3" NL + "mov r0, #0" NL + "vmov.f32 " CONST_ZERO_S ", r0" NL + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPOT_LIGHT) NL + "vmov.f32 " SPOT_COLOR_Q ", " COLOR_Q NL + "mov " RESET_WIDTH_R ", " WIDTH_R NL + +".mainLoop:" NL + "mov r3, #3" NL + "vmov.f32 " POSITION_X_S ", " CONST_ONE_S NL + +".scanline:" NL + // The ROW registers are storing the alpha channel of the last three pixels. + // The alpha channel is stored as signed short (sint16) values. The fourth value + // is garbage. The following instructions are shifting out the unnecessary alpha + // values and load the next ones. + "ldrb r0, [" PIXELS_R ", -" SCANLINE_R "]" NL + "ldrb r1, [" PIXELS_R ", +" SCANLINE_R "]" NL + "ldrb r2, [" PIXELS_R "], #4" NL + "vext.s16 " TOP_ROW_D ", " TOP_ROW_D ", " TOP_ROW_D ", #3" NL + "vext.s16 " MIDDLE_ROW_D ", " MIDDLE_ROW_D ", " MIDDLE_ROW_D ", #3" NL + "vext.s16 " BOTTOM_ROW_D ", " BOTTOM_ROW_D ", " BOTTOM_ROW_D ", #3" NL + "vmov.s16 " TOP_ROW_D "[1], r0" NL + "vmov.s16 " MIDDLE_ROW_D "[1], r2" NL + "vmov.s16 " BOTTOM_ROW_D "[1], r1" NL + + // The two border pixels (rightmost and leftmost) are skipped when + // the next scanline is reached. It also jumps, when the algorithm + // is started, and the first free alpha values are loaded to each row. + "subs r3, r3, #1" NL + "bne .scanline" NL + + // The light vector goes to TMP1_Q. It is constant in case of distant light. + // The fourth value contains the length of the light vector. + "tst " FLAGS_R ", #" TOSTRING(FLAG_POINT_LIGHT | FLAG_SPOT_LIGHT) NL + "beq .distantLight" NL + + "vmov.s16 r3, " MIDDLE_ROW_D "[2]" NL + "vmov.f32 " POSITION_Z_S ", r3" NL + "vcvt.f32.s32 " POSITION_Z_S ", " POSITION_Z_S NL + "vmul.f32 " POSITION_Z_S ", " POSITION_Z_S ", " SCALE_S NL + + "vsub.f32 " TMP1_Q ", " LIGHT_Q ", " POSITION_Q NL + GET_LENGTH(TMP1, TMP2) + + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPOT_LIGHT) NL + "bne .cosineOfAngle" NL +".visiblePixel:" NL + + // | -1 0 1 | | -1 -2 -1 | + // X = | -2 0 2 | Y = | 0 0 0 | + // | -1 0 1 | | 1 2 1 | + + // Multiply the alpha values by the X and Y matrices. + + // Moving the 8 alpha value to TMP3. + "vtbl.8 " TMP3_D0 ", " ALL_ROWS_D ", " REMAPX_D NL + "vtbl.8 " TMP3_D1 ", " ALL_ROWS_D ", " REMAPY_D NL + + "vmul.s16 " TMP2_Q ", " TMP3_Q ", " ALPHAX_Q NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D1 NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D0 NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D0 NL + "vmov.s16 r0, " TMP2_D0 "[0]" NL + + "vmul.s16 " TMP2_Q ", " TMP3_Q ", " ALPHAY_Q NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D1 NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D0 NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D0 NL + "vmov.s16 r1, " TMP2_D0 "[0]" NL + + // r0 and r1 contains the X and Y coordinates of the + // normal vector, respectively. + + // Calculating the spot light strength. + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPOT_LIGHT) NL + "beq .endLight" NL + + "vneg.f32 " TMP3_S1 ", " COSINE_OF_ANGLE NL + "tst " FLAGS_R ", #" TOSTRING(FLAG_CONE_EXPONENT_IS_1) NL + "beq .coneExpPowf" NL +".coneExpPowfFinished:" NL + + // Smoothing the cone edge if necessary. + "vcmp.f32 " COSINE_OF_ANGLE ", " CONE_FULL_LIGHT_S NL + "fmstat" NL + "bhi .cutOff" NL +".cutOffFinished:" NL + + "vmin.f32 " TMP3_D0 ", " TMP3_D0 ", " CONST_ONE_HI_D NL + "vmul.f32 " COLOR_Q ", " SPOT_COLOR_Q ", " TMP3_D0 "[1]" NL + +".endLight:" NL + // Summarize: + // r0 and r1 contains the normalVector. + // TMP1_Q contains the light vector and its length. + // COLOR_Q contains the color of the light vector. + + // Test whether both r0 and r1 are zero (Normal vector is (0, 0, 1)). + "orrs r2, r0, r1" NL + "bne .normalVectorIsNonZero" NL + + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPECULAR_LIGHT) NL + "bne .specularLight1" NL + + // Calculate diffuse light strength. + MULTIPLY_BY_DIFFUSE_CONST(TMP1_S2, TMP1_S3) + "b .lightStrengthCalculated" NL + +".specularLight1:" NL + // Calculating specular light strength. + "vadd.f32 " TMP1_S2 ", " TMP1_S2 ", " TMP1_S3 NL + GET_LENGTH(TMP1, TMP2) + + // When the exponent is 1, we don't need to call an expensive powf function. + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPECULAR_EXPONENT_IS_1) NL + "vdiveq.f32 " TMP2_S1 ", " TMP1_S2 ", " TMP1_S3 NL + "beq .specularExpPowf" NL + + MULTIPLY_BY_DIFFUSE_CONST(TMP1_S2, TMP1_S3) + "b .lightStrengthCalculated" NL + +".normalVectorIsNonZero:" NL + // Normal vector goes to TMP2, and its length is calculated as well. + "vmov.s32 " TMP2_S0 ", r0" NL + "vcvt.f32.s32 " TMP2_S0 ", " TMP2_S0 NL + "vmul.f32 " TMP2_S0 ", " TMP2_S0 ", " SCALE_DIV4_S NL + "vmov.s32 " TMP2_S1 ", r1" NL + "vcvt.f32.s32 " TMP2_S1 ", " TMP2_S1 NL + "vmul.f32 " TMP2_S1 ", " TMP2_S1 ", " SCALE_DIV4_S NL + "vmov.f32 " TMP2_S2 ", " CONST_ONE_S NL + GET_LENGTH(TMP2, TMP3) + + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPECULAR_LIGHT) NL + "bne .specularLight2" NL + + // Calculating diffuse light strength. + DOT_PRODUCT(TMP3, TMP2, TMP1) + MULTIPLY_BY_DIFFUSE_CONST(TMP3_S0, TMP3_S3) + "b .lightStrengthCalculated" NL + +".specularLight2:" NL + // Calculating specular light strength. + "vadd.f32 " TMP1_S2 ", " TMP1_S2 ", " TMP1_S3 NL + GET_LENGTH(TMP1, TMP3) + DOT_PRODUCT(TMP3, TMP2, TMP1) + + // When the exponent is 1, we don't need to call an expensive powf function. + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPECULAR_EXPONENT_IS_1) NL + "vdiveq.f32 " TMP2_S1 ", " TMP3_S0 ", " TMP3_S3 NL + "beq .specularExpPowf" NL + MULTIPLY_BY_DIFFUSE_CONST(TMP3_S0, TMP3_S3) + +".lightStrengthCalculated:" NL + // TMP2_S1 contains the light strength. Clamp it to [0, 1] + "vmax.f32 " TMP2_D0 ", " TMP2_D0 ", " CONST_ZERO_HI_D NL + "vmin.f32 " TMP2_D0 ", " TMP2_D0 ", " CONST_ONE_HI_D NL + "vmul.f32 " TMP3_Q ", " COLOR_Q ", " TMP2_D0 "[1]" NL + "vcvt.u32.f32 " TMP3_Q ", " TMP3_Q NL + "vmov.u32 r2, r3, " TMP3_S0 ", " TMP3_S1 NL + // The color values are stored in-place. + "strb r2, [" PIXELS_R ", #-11]" NL + "strb r3, [" PIXELS_R ", #-10]" NL + "vmov.u32 r2, " TMP3_S2 NL + "strb r2, [" PIXELS_R ", #-9]" NL + + // Continue to the next pixel. +".blackPixel:" NL + "vadd.f32 " POSITION_X_S ", " CONST_ONE_S NL + "mov r3, #1" NL + "subs " WIDTH_R ", " WIDTH_R ", #1" NL + "bne .scanline" NL + + // If the end of the scanline is reached, we continue + // to the next scanline. + "vadd.f32 " POSITION_Y_S ", " CONST_ONE_S NL + "mov " WIDTH_R ", " RESET_WIDTH_R NL + "subs " HEIGHT_R ", " HEIGHT_R ", #1" NL + "bne .mainLoop" NL + + // Return. + "vldmia sp!, {d8-d15}" NL + "ldmia sp!, {r4-r8, r10, r11, pc}" NL + +".distantLight:" NL + // In case of distant light, the light vector is constant, + // we simply copy it. + "vmov.f32 " TMP1_Q ", " LIGHT_Q NL + "b .visiblePixel" NL + +".cosineOfAngle:" NL + // If the pixel is outside of the cone angle, it is simply a black pixel. + DOT_PRODUCT(TMP3, TMP1, DIRECTION) + "vdiv.f32 " COSINE_OF_ANGLE ", " TMP3_S0 ", " TMP1_S3 NL + "vcmp.f32 " COSINE_OF_ANGLE ", " CONE_CUT_OFF_S NL + "fmstat" NL + "bls .visiblePixel" NL + "mov r0, #0" NL + "strh r0, [" PIXELS_R ", #-11]" NL + "strb r0, [" PIXELS_R ", #-9]" NL + "b .blackPixel" NL + +".cutOff:" NL + // Smoothing the light strength on the cone edge. + "vsub.f32 " TMP3_S0 ", " CONE_CUT_OFF_S ", " COSINE_OF_ANGLE NL + "vdiv.f32 " TMP3_S0 ", " TMP3_S0 ", " CONE_CUT_OFF_RANGE_S NL + "vmul.f32 " TMP3_S1 ", " TMP3_S1 ", " TMP3_S0 NL + "b .cutOffFinished" NL + +".coneExpPowf:" NL + POWF(TMP3_S1, CONE_EXPONENT_R) + "b .coneExpPowfFinished" NL + +".specularExpPowf:" NL + POWF(TMP2_S1, SPECULAR_EXPONENT_R) + "tst " FLAGS_R ", #" TOSTRING(FLAG_DIFFUSE_CONST_IS_1) NL + "vmuleq.f32 " TMP2_S1 ", " TMP2_S1 ", " DIFFUSE_CONST_S NL + "b .lightStrengthCalculated" NL +); // NOLINT + +int FELighting::getPowerCoefficients(float exponent) +{ + // Calling a powf function from the assembly code would require to save + // and reload a lot of NEON registers. Since the base is in range [0..1] + // and only 8 bit precision is required, we use our own powf function. + // This is probably not the best, but it uses only a few registers and + // gives us enough precision (modifying the exponent field directly would + // also be possible). + + // First, we limit the exponent to maximum of 64, which gives us enough + // precision. We split the exponent to an integer and fraction part, + // since a^x = (a^y)*(a^z) where x = y+z. The integer exponent of the + // power is estimated by square, and the fraction exponent of the power + // is estimated by square root assembly instructions. + int i, result; + + if (exponent < 0) + exponent = 1 / (-exponent); + + if (exponent > 63.99) + exponent = 63.99; + + exponent /= 64; + result = 0; + for (i = 11; i >= 0; --i) { + exponent *= 2; + if (exponent >= 1) { + result |= 1 << i; + exponent -= 1; + } + } + return result; +} + +} // namespace WebCore + +#endif // CPU(ARM_NEON) && COMPILER(GCC) diff --git a/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.h b/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.h new file mode 100644 index 000000000..9094153d7 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.h @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2011 University of Szeged + * Copyright (C) 2011 Zoltan Herczeg + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FELightingNeon_h +#define FELightingNeon_h + +#include <wtf/Platform.h> + +#if CPU(ARM_NEON) && COMPILER(GCC) + +#include "FELighting.h" +#include <wtf/Alignment.h> +#include <wtf/ParallelJobs.h> + +namespace WebCore { + +// Otherwise: Distant Light. +#define FLAG_POINT_LIGHT 0x01 +#define FLAG_SPOT_LIGHT 0x02 +#define FLAG_CONE_EXPONENT_IS_1 0x04 + +// Otherwise: Diffuse light. +#define FLAG_SPECULAR_LIGHT 0x10 +#define FLAG_DIFFUSE_CONST_IS_1 0x20 +#define FLAG_SPECULAR_EXPONENT_IS_1 0x40 + +// Must be aligned to 16 bytes. +struct FELightingFloatArgumentsForNeon { + float surfaceScale; + float minusSurfaceScaleDividedByFour; + float diffuseConstant; + float padding1; + + float coneCutOffLimit; + float coneFullLight; + float coneCutOffRange; + float constOne; + + float lightX; + float lightY; + float lightZ; + float padding2; + + float directionX; + float directionY; + float directionZ; + float padding3; + + float colorRed; + float colorGreen; + float colorBlue; + float padding4; +}; + +struct FELightingPaintingDataForNeon { + unsigned char* pixels; + float yStart; + int widthDecreasedByTwo; + int absoluteHeight; + // Combination of FLAG constants above. + int flags; + int specularExponent; + int coneExponent; + FELightingFloatArgumentsForNeon* floatArguments; + short* paintingConstants; +}; + +short* feLightingConstantsForNeon(); + +extern "C" { +void neonDrawLighting(FELightingPaintingDataForNeon*); +} + +inline void FELighting::platformApplyNeon(LightingData& data, LightSource::PaintingData& paintingData) +{ + WTF_ALIGNED(FELightingFloatArgumentsForNeon, floatArguments, 16); + + FELightingPaintingDataForNeon neonData = { + data.pixels->data(), + 1, + data.widthDecreasedByOne - 1, + data.heightDecreasedByOne - 1, + 0, + 0, + 0, + &floatArguments, + feLightingConstantsForNeon() + }; + + // Set light source arguments. + floatArguments.constOne = 1; + + floatArguments.colorRed = m_lightingColor.red(); + floatArguments.colorGreen = m_lightingColor.green(); + floatArguments.colorBlue = m_lightingColor.blue(); + floatArguments.padding4 = 0; + + if (m_lightSource->type() == LS_POINT) { + neonData.flags |= FLAG_POINT_LIGHT; + PointLightSource* pointLightSource = static_cast<PointLightSource*>(m_lightSource.get()); + floatArguments.lightX = pointLightSource->position().x(); + floatArguments.lightY = pointLightSource->position().y(); + floatArguments.lightZ = pointLightSource->position().z(); + floatArguments.padding2 = 0; + } else if (m_lightSource->type() == LS_SPOT) { + neonData.flags |= FLAG_SPOT_LIGHT; + SpotLightSource* spotLightSource = static_cast<SpotLightSource*>(m_lightSource.get()); + floatArguments.lightX = spotLightSource->position().x(); + floatArguments.lightY = spotLightSource->position().y(); + floatArguments.lightZ = spotLightSource->position().z(); + floatArguments.padding2 = 0; + + floatArguments.directionX = paintingData.directionVector.x(); + floatArguments.directionY = paintingData.directionVector.y(); + floatArguments.directionZ = paintingData.directionVector.z(); + floatArguments.padding3 = 0; + + floatArguments.coneCutOffLimit = paintingData.coneCutOffLimit; + floatArguments.coneFullLight = paintingData.coneFullLight; + floatArguments.coneCutOffRange = paintingData.coneCutOffLimit - paintingData.coneFullLight; + neonData.coneExponent = getPowerCoefficients(spotLightSource->specularExponent()); + if (spotLightSource->specularExponent() == 1) + neonData.flags |= FLAG_CONE_EXPONENT_IS_1; + } else { + ASSERT(m_lightSource->type() == LS_DISTANT); + floatArguments.lightX = paintingData.lightVector.x(); + floatArguments.lightY = paintingData.lightVector.y(); + floatArguments.lightZ = paintingData.lightVector.z(); + floatArguments.padding2 = 1; + } + + // Set lighting arguments. + floatArguments.surfaceScale = data.surfaceScale; + floatArguments.minusSurfaceScaleDividedByFour = -data.surfaceScale / 4; + if (m_lightingType == FELighting::DiffuseLighting) + floatArguments.diffuseConstant = m_diffuseConstant; + else { + neonData.flags |= FLAG_SPECULAR_LIGHT; + floatArguments.diffuseConstant = m_specularConstant; + neonData.specularExponent = getPowerCoefficients(m_specularExponent); + if (m_specularExponent == 1) + neonData.flags |= FLAG_SPECULAR_EXPONENT_IS_1; + } + if (floatArguments.diffuseConstant == 1) + neonData.flags |= FLAG_DIFFUSE_CONST_IS_1; + + int optimalThreadNumber = ((data.widthDecreasedByOne - 1) * (data.heightDecreasedByOne - 1)) / s_minimalRectDimension; + if (optimalThreadNumber > 1) { + // Initialize parallel jobs + ParallelJobs<FELightingPaintingDataForNeon> parallelJobs(&WebCore::FELighting::platformApplyNeonWorker, optimalThreadNumber); + + // Fill the parameter array + int job = parallelJobs.numberOfJobs(); + if (job > 1) { + int yStart = 1; + int yStep = (data.heightDecreasedByOne - 1) / job; + for (--job; job >= 0; --job) { + FELightingPaintingDataForNeon& params = parallelJobs.parameter(job); + params = neonData; + params.yStart = yStart; + params.pixels += (yStart - 1) * (data.widthDecreasedByOne + 1) * 4; + if (job > 0) { + params.absoluteHeight = yStep; + yStart += yStep; + } else + params.absoluteHeight = data.heightDecreasedByOne - yStart; + } + parallelJobs.execute(); + return; + } + } + + neonDrawLighting(&neonData); +} + +} // namespace WebCore + +#endif // CPU(ARM_NEON) && COMPILER(GCC) + +#endif // FELightingNeon_h diff --git a/Source/WebCore/platform/graphics/filters/skia/FEGaussianBlurSkia.cpp b/Source/WebCore/platform/graphics/filters/skia/FEGaussianBlurSkia.cpp new file mode 100644 index 000000000..ceb1146c7 --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/skia/FEGaussianBlurSkia.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#if USE(SKIA) +#include "FEGaussianBlur.h" + +#include "BitmapImageSingleFrameSkia.h" +#include "SkBlurImageFilter.h" + +namespace WebCore { + +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; +} + +}; +#endif |