1/*
2 * Copyright (C) 2012, 2013 Research In Motion Limited. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19#include "config.h"
20
21#if USE(ACCELERATED_COMPOSITING) && ENABLE(CSS_FILTERS)
22
23#include "LayerFilterRenderer.h"
24
25#include "FilterOperation.h"
26#include "LayerCompositingThread.h"
27#include "LayerRenderer.h"
28#include "NotImplemented.h"
29#include "TextureCacheCompositingThread.h"
30
31#include <BlackBerryPlatformGraphics.h>
32#include <BlackBerryPlatformLog.h>
33#include <Vector.h>
34
35#include <cstring>
36#include <limits>
37#include <wtf/text/WTFString.h>
38
39namespace WebCore {
40
41class SurfaceFunctor {
42public:
43    SurfaceFunctor(LayerRendererSurface* surface)
44        : m_surface(surface)
45    {
46    }
47
48protected:
49    LayerRendererSurface* m_surface;
50};
51
52class InverseSurfaceWidth : public SurfaceFunctor {
53public:
54    InverseSurfaceWidth(LayerRendererSurface* surface) : SurfaceFunctor(surface) { }
55
56    float operator() () { return 1.0f / m_surface->size().width(); }
57};
58
59class InverseSurfaceHeight : public SurfaceFunctor {
60public:
61    InverseSurfaceHeight(LayerRendererSurface* surface) : SurfaceFunctor(surface) { }
62
63    float operator() () { return 1.0f / m_surface->size().height(); }
64};
65
66static int operationTypeToProgramID(const FilterOperation::OperationType& t)
67{
68    switch (t) {
69    case FilterOperation::GRAYSCALE:
70        return LayerData::CSSFilterShaderGrayscale;
71    case FilterOperation::SEPIA:
72        return LayerData::CSSFilterShaderSepia;
73    case FilterOperation::SATURATE:
74        return LayerData::CSSFilterShaderSaturate;
75    case FilterOperation::HUE_ROTATE:
76        return LayerData::CSSFilterShaderHueRotate;
77    case FilterOperation::INVERT:
78        return LayerData::CSSFilterShaderInvert;
79    case FilterOperation::OPACITY:
80        return LayerData::CSSFilterShaderOpacity;
81    case FilterOperation::BRIGHTNESS:
82        return LayerData::CSSFilterShaderBrightness;
83    case FilterOperation::CONTRAST:
84        return LayerData::CSSFilterShaderContrast;
85    case FilterOperation::BLUR:
86        return LayerData::CSSFilterShaderBlurY;
87    case FilterOperation::DROP_SHADOW:
88        return LayerData::CSSFilterShaderShadow;
89#if ENABLE(CSS_SHADERS)
90    case FilterOperation::CUSTOM:
91        return LayerData::CSSFilterShaderCustom;
92#endif
93    default:
94        ASSERT_NOT_REACHED();
95        return -1;
96    }
97}
98
99Uniform::Uniform(int c_location)
100    : m_location(c_location)
101{
102}
103
104void Uniform1f::apply()
105{
106    glUniform1f(location(), m_val);
107}
108
109PassRefPtr<Uniform> Uniform1f::create(int location, float val)
110{
111    return adoptRef(new Uniform1f(location, val));
112}
113
114Uniform1f::Uniform1f(int c_location, float c_val)
115    : Uniform(c_location)
116    , m_val(c_val)
117{
118}
119
120void Uniform1i::apply()
121{
122    glUniform1i(location(), m_val);
123}
124
125PassRefPtr<Uniform> Uniform1i::create(int location, int val)
126{
127    return adoptRef(new Uniform1i(location, val));
128}
129
130Uniform1i::Uniform1i(int c_location, int c_val)
131    : Uniform(c_location)
132    , m_val(c_val)
133{
134}
135
136void Uniform2f::apply()
137{
138    glUniform2f(location(), m_val[0], m_val[1]);
139}
140
141PassRefPtr<Uniform> Uniform2f::create(int location, float val0, float val1)
142{
143    return adoptRef(new Uniform2f(location, val0, val1));
144}
145
146Uniform2f::Uniform2f(int c_location, float c_val0, float c_val1)
147    : Uniform(c_location)
148{
149    m_val[0] = c_val0;
150    m_val[1] = c_val1;
151}
152
153void Uniform3f::apply()
154{
155    glUniform3f(location(), m_val[0], m_val[1], m_val[2]);
156}
157
158PassRefPtr<Uniform> Uniform3f::create(int location, float val0, float val1, float val2)
159{
160    return adoptRef(new Uniform3f(location, val0, val1, val2));
161}
162
163Uniform3f::Uniform3f(int c_location, float c_val0, float c_val1, float c_val2)
164    : Uniform(c_location)
165{
166    m_val[0] = c_val0;
167    m_val[1] = c_val1;
168    m_val[2] = c_val2;
169}
170
171void Uniform4f::apply()
172{
173    glUniform4f(location(), m_val[0], m_val[1], m_val[2], m_val[3]);
174}
175
176PassRefPtr<Uniform> Uniform4f::create(int location, float val0, float val1, float val2, float val3)
177{
178    return adoptRef(new Uniform4f(location, val0, val1, val2, val3));
179}
180
181Uniform4f::Uniform4f(int c_location, float c_val0, float c_val1, float c_val2, float c_val3)
182    : Uniform(c_location)
183{
184    m_val[0] = c_val0;
185    m_val[1] = c_val1;
186    m_val[2] = c_val2;
187    m_val[3] = c_val3;
188}
189
190void Matrix4fv::apply()
191{
192    glUniformMatrix4fv(location(), m_size, m_transpose, m_array);
193}
194
195PassRefPtr<Parameter> Matrix4fv::create(GLint location, GLsizei size, GLboolean transpose, GLfloat* array)
196{
197    return adoptRef(new Matrix4fv(location, size, transpose, array));
198}
199
200Matrix4fv::Matrix4fv(GLint clocation, GLsizei size, GLboolean transpose, GLfloat* array)
201    : Uniform(clocation)
202    , m_size(size)
203    , m_transpose(transpose)
204    , m_array(0)
205{
206    m_array = new GLfloat[size * 4 * 4];
207    std::memcpy(m_array, array, size * 4 * 4 * sizeof(GLfloat));
208}
209
210Matrix4fv::~Matrix4fv()
211{
212    delete[] m_array;
213}
214
215void Buffer::apply()
216{
217    glBindBuffer(m_buffer, m_object);
218}
219
220void Buffer::restoreState()
221{
222    glBindBuffer(m_buffer, 0);
223}
224
225PassRefPtr<Parameter> Buffer::create(GLenum buffer, GLuint object)
226{
227    return adoptRef(new Buffer(buffer, object));
228}
229
230Buffer::Buffer(GLenum buffer, GLuint object)
231    : Parameter()
232    , m_buffer(buffer)
233    , m_object(object)
234{
235}
236
237void VertexAttribf::apply()
238{
239    glVertexAttribPointer(m_location, m_size, GL_FLOAT, false, m_bytesPerVertex, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(m_offset)));
240    glEnableVertexAttribArray(m_location);
241}
242
243void VertexAttribf::restoreState()
244{
245    glDisableVertexAttribArray(m_location);
246}
247
248PassRefPtr<Parameter> VertexAttribf::create(int location, int size, int bytesPerVertex, int offset)
249{
250    return adoptRef(new VertexAttribf(location, size, bytesPerVertex, offset));
251}
252
253
254VertexAttribf::VertexAttribf(int location, int size, int bytesPerVertex, int offset)
255    : Parameter()
256    , m_location(location)
257    , m_size(size)
258    , m_bytesPerVertex(bytesPerVertex)
259    , m_offset(offset)
260{
261}
262
263PassRefPtr<LayerFilterRendererAction> LayerFilterRendererAction::create(int programId)
264{
265    return adoptRef(new LayerFilterRendererAction(programId));
266}
267
268LayerFilterRendererAction::LayerFilterRendererAction(int c_programId)
269    : m_programId(c_programId)
270    , m_pushSnapshot(false)
271    , m_popSnapshot(false)
272    , m_drawingMode(DrawTriangleFanArrays)
273{
274}
275
276void LayerFilterRendererAction::useActionOn(LayerFilterRenderer* renderer)
277{
278    ASSERT(m_programId != -1);
279    if (m_programId == -1) {
280        glUseProgram(renderer->m_cssFilterProgramObject[LayerData::CSSFilterShaderPassthrough]);
281        return;
282    }
283    glUseProgram(renderer->m_cssFilterProgramObject[m_programId]);
284    for (unsigned i = 0; i < m_parameters.size(); ++i)
285        m_parameters[i]->apply();
286}
287
288void LayerFilterRendererAction::restoreState()
289{
290    for (unsigned i = 0; i < m_parameters.size(); ++i)
291        m_parameters[i]->restoreState();
292}
293
294PassOwnPtr<LayerFilterRenderer> LayerFilterRenderer::create(const int& positionLocation, const int& texCoordLocation)
295{
296    return adoptPtr(new LayerFilterRenderer(positionLocation, texCoordLocation));
297}
298
299LayerFilterRenderer::LayerFilterRenderer(const int& positionLocation, const int& texCoordLocation)
300    : m_positionLocation(positionLocation)
301    , m_texCoordLocation(texCoordLocation)
302{
303    // If you ever move this stuff, please make sure that
304    // everything in this constructor is called BEFORE actionsForOperations.
305
306    for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; ++i)
307        m_cssFilterProgramObject[i] = 0;
308
309    if (!(m_enabled = initializeSharedGLObjects()))
310        BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelWarn, "CSS Filters are not enabled due to failed initialization.");
311}
312
313// Binds the given attribute name to a common location across all programs
314// used by the compositor. This allows the code to bind the attributes only once
315// even when switching between programs.
316//
317// This is an extension of LayerRenderer::bindCommonAttribLocation and the locations
318// will match those of LayerRenderer. See LayerFilterRenderer::LayerFilterRenderer()
319void LayerFilterRenderer::bindCommonAttribLocation(int location, const char* attribName)
320{
321    for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; ++i)
322        glBindAttribLocation(m_cssFilterProgramObject[i], location, attribName);
323}
324
325bool LayerFilterRenderer::initializeSharedGLObjects()
326{
327    // See also TextureMapperShaderManager.cpp
328
329    char standardVertexShaderString[] =
330        "attribute vec4 a_position;   \n"
331        "attribute vec2 a_texCoord;   \n"
332        "varying vec2 v_texCoord;     \n"
333        "void main()                  \n"
334        "{                            \n"
335        "  gl_Position = a_position;  \n"
336        "  v_texCoord = a_texCoord;   \n"
337        "}                            \n";
338
339    char offsetVertexShaderString[] =
340        "attribute vec4 a_position;              \n"
341        "attribute vec2 a_texCoord;              \n"
342        "uniform mediump vec2 u_offset;          \n"
343        "varying vec2 v_texCoord;                \n"
344        "void main()                             \n"
345        "{                                       \n"
346        "  gl_Position = a_position;             \n"
347        "  v_texCoord = a_texCoord - u_offset;   \n"
348        "}                                       \n";
349
350#define STANDARD_FILTER(x...) \
351        "precision mediump float; \n"\
352        "\n"\
353        "varying mediump vec2 v_texCoord;\n"\
354        "uniform lowp sampler2D s_texture;\n"\
355        "uniform highp float u_amount;\n"\
356#x\
357        "void main(void)\n { gl_FragColor = shade(texture2D(s_texture, v_texCoord)); }"
358
359#define BLUR_FILTER(x...) \
360        "precision highp float; \n"\
361        "\n"\
362        "varying mediump vec2 v_texCoord;\n"\
363        "uniform lowp sampler2D s_texture;\n"\
364        "uniform highp float u_amount;\n"\
365        "uniform highp float u_blurSize;\n"\
366        "const float pi = 3.1415927;\n"\
367#x\
368        "void main(void)\n"\
369        "{\n"\
370        "vec3 incr;\n"\
371        "incr.x = 1.0 / (sqrt(2.0 * pi) * u_amount);\n"\
372        "incr.y = exp(-0.5 / (u_amount * u_amount));\n"\
373        "incr.z = incr.y * incr.y;\n"\
374        "\n"\
375        "vec4 avg = vec4(0.0, 0.0, 0.0, 0.0);\n"\
376        "float coefficientSum = 0.0;\n"\
377        "\n"\
378        "avg += texture2D(s_texture, v_texCoord.xy) * incr.x;\n"\
379        "coefficientSum += incr.x;\n"\
380        "incr.xy *= incr.yz;\n"\
381        "\n"\
382        "for (float i = 1.0; i <= u_amount; i++) {\n"\
383        "    avg += texture2D(s_texture, v_texCoord.xy - i * u_blurSize * blurMultiplyVec) * incr.x;\n"\
384        "    avg += texture2D(s_texture, v_texCoord.xy + i * u_blurSize * blurMultiplyVec) * incr.x;\n"\
385        "    coefficientSum += 2.0 * incr.x;\n"\
386        "    incr.xy *= incr.yz;\n"\
387        "}\n"\
388        "\n"\
389        "gl_FragColor = avg / coefficientSum;\n"\
390        "}"
391
392    const char* shaderStrs[LayerData::NumberOfCSSFilterShaders];
393
394    shaderStrs[LayerData::CSSFilterShaderGrayscale] = STANDARD_FILTER(
395        lowp vec4 shade(lowp vec4 color)
396        {
397            lowp float amount = 1.0 - u_amount;
398            return vec4((0.2126 + 0.7874 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b,
399                (0.2126 - 0.2126 * amount) * color.r + (0.7152 + 0.2848 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b,
400                (0.2126 - 0.2126 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 + 0.9278 * amount) * color.b,
401                color.a);
402        }
403    );
404
405    shaderStrs[LayerData::CSSFilterShaderSepia] = STANDARD_FILTER(
406        lowp vec4 shade(lowp vec4 color)
407        {
408            lowp float amount = 1.0 - u_amount;
409            return vec4((0.393 + 0.607 * amount) * color.r + (0.769 - 0.769 * amount) * color.g + (0.189 - 0.189 * amount) * color.b,
410                (0.349 - 0.349 * amount) * color.r + (0.686 + 0.314 * amount) * color.g + (0.168 - 0.168 * amount) * color.b,
411                (0.272 - 0.272 * amount) * color.r + (0.534 - 0.534 * amount) * color.g + (0.131 + 0.869 * amount) * color.b,
412                color.a);
413        }
414    );
415
416    shaderStrs[LayerData::CSSFilterShaderSaturate] = STANDARD_FILTER(
417        lowp vec4 shade(lowp vec4 color)
418        {
419            return vec4((0.213 + 0.787 * u_amount) * color.r + (0.715 - 0.715 * u_amount) * color.g + (0.072 - 0.072 * u_amount) * color.b,
420                (0.213 - 0.213 * u_amount) * color.r + (0.715 + 0.285 * u_amount) * color.g + (0.072 - 0.072 * u_amount) * color.b,
421                (0.213 - 0.213 * u_amount) * color.r + (0.715 - 0.715 * u_amount) * color.g + (0.072 + 0.928 * u_amount) * color.b,
422                color.a);
423        }
424    );
425
426    shaderStrs[LayerData::CSSFilterShaderHueRotate] = STANDARD_FILTER(
427        lowp vec4 shade(lowp vec4 color)
428        {
429            highp float pi = 3.14159265358979323846;
430            highp float c = cos(u_amount * pi / 180.0);
431            highp float s = sin(u_amount * pi / 180.0);
432            return vec4(color.r * (0.213 + c * 0.787 - s * 0.213) + color.g * (0.715 - c * 0.715 - s * 0.715) + color.b * (0.072 - c * 0.072 + s * 0.928),
433                color.r * (0.213 - c * 0.213 + s * 0.143) + color.g * (0.715 + c * 0.285 + s * 0.140) + color.b * (0.072 - c * 0.072 - s * 0.283),
434                color.r * (0.213 - c * 0.213 - s * 0.787) +  color.g * (0.715 - c * 0.715 + s * 0.715) + color.b * (0.072 + c * 0.928 + s * 0.072),
435                color.a);
436        }
437    );
438
439    shaderStrs[LayerData::CSSFilterShaderInvert] = STANDARD_FILTER(
440        lowp float invert(lowp float n) { return (1.0 - n) * u_amount + n * (1.0 - u_amount); }
441        lowp vec4 shade(lowp vec4 color)
442        {
443            return vec4(invert(color.r), invert(color.g), invert(color.b), color.a);
444        }
445    );
446
447    shaderStrs[LayerData::CSSFilterShaderBrightness] = STANDARD_FILTER(
448        lowp vec4 shade(lowp vec4 color)
449        {
450            return vec4(color.rgb * (1.0 + u_amount), color.a);
451        }
452    );
453
454    shaderStrs[LayerData::CSSFilterShaderContrast] = STANDARD_FILTER(
455        lowp float contrast(lowp float n) { return (n - 0.5) * u_amount + 0.5; }
456        lowp vec4 shade(lowp vec4 color)
457        {
458            return vec4(contrast(color.r), contrast(color.g), contrast(color.b), color.a);
459        }
460    );
461
462    shaderStrs[LayerData::CSSFilterShaderOpacity] = STANDARD_FILTER(
463        lowp vec4 shade(lowp vec4 color)
464        {
465            return vec4(color.r, color.g, color.b, color.a * u_amount);
466        }
467    );
468
469    shaderStrs[LayerData::CSSFilterShaderBlurX] = BLUR_FILTER(
470        const vec2  blurMultiplyVec      = vec2(1.0, 0.0);
471    );
472
473    shaderStrs[LayerData::CSSFilterShaderBlurY] = BLUR_FILTER(
474        const vec2  blurMultiplyVec      = vec2(0.0, 1.0);
475    );
476
477    shaderStrs[LayerData::CSSFilterShaderShadow] = STANDARD_FILTER(
478        uniform lowp vec3 u_color;
479        lowp vec4 shade(lowp vec4 color)
480        {
481            if (color.a > 0.5)
482                return vec4(u_color.r, u_color.g, u_color.b, color.a);
483            return color;
484        }
485    );
486
487    shaderStrs[LayerData::CSSFilterShaderPassthrough] = STANDARD_FILTER(
488        lowp vec4 shade(lowp vec4 color)
489        {
490            return color;
491        }
492    );
493
494    for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; i++) {
495        if (i == LayerData::CSSFilterShaderShadow)
496            m_cssFilterProgramObject[i] = LayerRenderer::loadShaderProgram(offsetVertexShaderString, shaderStrs[i]);
497        else
498            m_cssFilterProgramObject[i] = LayerRenderer::loadShaderProgram(standardVertexShaderString, shaderStrs[i]);
499        if (!m_cssFilterProgramObject[i]) {
500            BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelWarn, "Could not load CSS Filter Shader %i", i);
501            return false;
502        }
503    }
504
505    // Set ATTRIB locations - these will be the same as the programs in LayerRenderer.cpp
506    bindCommonAttribLocation(m_positionLocation, "a_position");
507    bindCommonAttribLocation(m_texCoordLocation, "a_texCoord");
508
509    // Re-link to take effect
510    for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; ++i)
511        glLinkProgram(m_cssFilterProgramObject[i]);
512
513    // Get UNIFORM locations
514    for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; ++i)
515        m_amountLocation[i] = glGetUniformLocation(m_cssFilterProgramObject[i], "u_amount");
516
517    m_blurAmountLocation[0] = glGetUniformLocation(m_cssFilterProgramObject[LayerData::CSSFilterShaderBlurY], "u_blurSize");
518    m_blurAmountLocation[1] = glGetUniformLocation(m_cssFilterProgramObject[LayerData::CSSFilterShaderBlurX], "u_blurSize");
519
520    m_shadowColorLocation = glGetUniformLocation(m_cssFilterProgramObject[LayerData::CSSFilterShaderShadow], "u_color");
521    m_offsetLocation = glGetUniformLocation(m_cssFilterProgramObject[LayerData::CSSFilterShaderShadow], "u_offset");
522
523    return true;
524}
525
526void LayerFilterRenderer::ping(LayerRendererSurface* surface)
527{
528    GLuint texid = m_texture->platformTexture();
529
530    glFramebufferTexture2D(
531        GL_FRAMEBUFFER,
532        GL_COLOR_ATTACHMENT0,
533        GL_TEXTURE_2D,
534        texid,
535        0
536    );
537    glBindTexture(
538        GL_TEXTURE_2D,
539        surface->texture()->platformTexture()
540    );
541}
542
543void LayerFilterRenderer::pong(LayerRendererSurface* surface)
544{
545    glFramebufferTexture2D(
546        GL_FRAMEBUFFER,
547        GL_COLOR_ATTACHMENT0,
548        GL_TEXTURE_2D,
549        surface->texture()->platformTexture(),
550        0
551    );
552    glBindTexture(
553        GL_TEXTURE_2D,
554        m_texture->platformTexture()
555    );
556}
557
558void LayerFilterRenderer::pushSnapshot(LayerRendererSurface* surface, int sourceId)
559{
560    GLuint texid = m_snapshotTexture->platformTexture();
561
562    glFramebufferTexture2D(
563        GL_FRAMEBUFFER,
564        GL_COLOR_ATTACHMENT0,
565        GL_TEXTURE_2D,
566        texid,
567        0
568    );
569
570    glBindTexture(GL_TEXTURE_2D, sourceId);
571    glClear(GL_COLOR_BUFFER_BIT); // to transparency
572
573    glViewport(0, 0, surface->size().width(), surface->size().height());
574
575    glUseProgram(m_cssFilterProgramObject[LayerData::CSSFilterShaderPassthrough]);
576    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
577}
578
579void LayerFilterRenderer::popSnapshot()
580{
581    // The name is slightly misleading.
582    // This DRAWS the previous texture using the current LayerFilterRendererAction, then sets the texture
583    // to the snapshot texture. Next time glDrawArrays is called, the snapshot will be drawn.
584
585    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
586    glBindTexture(
587        GL_TEXTURE_2D,
588        m_snapshotTexture->platformTexture()
589    );
590}
591
592Vector<RefPtr<LayerFilterRendererAction> > LayerFilterRenderer::actionsForOperations(LayerRendererSurface* surface, const Vector<RefPtr<FilterOperation> >& ops)
593{
594    Vector<RefPtr<LayerFilterRendererAction> > ret;
595    for (unsigned i = 0; i < ops.size(); ++i) {
596        const FilterOperation& operation = *ops[i].get();
597        if (operation.getOperationType() == FilterOperation::BLUR && static_cast<const BlurFilterOperation&>(operation).stdDeviation().value() < 0.1)
598            continue;
599
600        int programId = operationTypeToProgramID(operation.getOperationType());
601        ret.append(LayerFilterRendererAction::create(programId));
602
603        switch (operation.getOperationType()) {
604        case FilterOperation::GRAYSCALE:
605        case FilterOperation::SEPIA:
606        case FilterOperation::SATURATE:
607        case FilterOperation::HUE_ROTATE:
608            ret.last()->appendParameter(Uniform1f::create(m_amountLocation[programId]
609                , static_cast<const BasicColorMatrixFilterOperation&>(operation).amount()));
610            break;
611        case FilterOperation::INVERT:
612        case FilterOperation::BRIGHTNESS:
613        case FilterOperation::CONTRAST:
614        case FilterOperation::OPACITY:
615            ret.last()->appendParameter(Uniform1f::create(m_amountLocation[programId]
616                , static_cast<const BasicComponentTransferFilterOperation&>(operation).amount()));
617            break;
618        case FilterOperation::BLUR:
619            {
620            // Blur is a two-step process:
621            //     1. blur X
622            //     2. blur Y
623            // This way we can have 2n time instead of n^2 time)
624
625            double amount = static_cast<const BlurFilterOperation&>(operation).stdDeviation().value();
626
627            // BLUR Y:
628            ret.last()->appendParameter(Uniform1f::create(m_amountLocation[LayerData::CSSFilterShaderBlurY], amount));
629            ret.last()->appendParameter(Uniform1f::createWithFunctor(m_blurAmountLocation[0], InverseSurfaceHeight(surface)));
630
631            // BLUR X:
632            ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderBlurX));
633            ret.last()->appendParameter(Uniform1f::create(m_amountLocation[LayerData::CSSFilterShaderBlurX], amount));
634            ret.last()->appendParameter(Uniform1f::createWithFunctor(m_blurAmountLocation[1], InverseSurfaceWidth(surface)));
635
636            }
637            break;
638        case FilterOperation::DROP_SHADOW:
639            {
640            // Shadow is a four-step process:
641            //     1. capture snapshot
642            //        turn into a solid offset mask
643            //     2. blur X
644            //     3. blur Y
645            //     4. repaint original on top of mask
646            const DropShadowFilterOperation& dsfo = static_cast<const DropShadowFilterOperation&>(operation);
647            ret.last()->setPushSnapshot();
648            ret.last()->appendParameter(Uniform2f::create(m_offsetLocation
649                , float(dsfo.x()) / float(surface->size().width())
650                , float(dsfo.y()) / float(surface->size().height())));
651            ret.last()->appendParameter(Uniform3f::create(m_shadowColorLocation
652                , float(dsfo.color().red()) / 255.0f
653                , float(dsfo.color().green()) / 255.0f
654                , float(dsfo.color().blue()) / 255.0f));
655
656            // BLUR Y
657            ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderBlurY));
658            ret.last()->appendParameter(Uniform1f::create(m_amountLocation[LayerData::CSSFilterShaderBlurY]
659                , dsfo.stdDeviation()));
660            ret.last()->appendParameter(Uniform1f::createWithFunctor(m_blurAmountLocation[0], InverseSurfaceHeight(surface)));
661
662            // BLUR X
663            ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderBlurX));
664            ret.last()->appendParameter(Uniform1f::create(m_amountLocation[LayerData::CSSFilterShaderBlurX]
665                , dsfo.stdDeviation()));
666            ret.last()->appendParameter(Uniform1f::createWithFunctor(m_blurAmountLocation[1], InverseSurfaceWidth(surface)));
667
668            // Repaint original image
669            ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderPassthrough));
670            ret.last()->setPopSnapshot();
671            }
672            break;
673        default:
674            ASSERT_NOT_REACHED();
675            break;
676        }
677    }
678
679    if (ret.size() % 2) // We need an even number of actions. See ping-pong note in applyLayerFilters().
680        ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderPassthrough));
681
682    return ret;
683}
684
685void LayerFilterRenderer::applyActions(unsigned& fbo, LayerCompositingThread* layer, Vector<RefPtr<LayerFilterRendererAction> > actions)
686{
687    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
688    ASSERT(!(actions.size() % 2)); // See ping-ponging note below.
689
690    if (!m_enabled)
691        return;
692
693    if (!layer->filters().size())
694        return;
695
696    if (!m_texture)
697        m_texture = textureCacheCompositingThread()->createTexture();
698
699    bool requireSnapshot = false;
700    for (unsigned i = 0; i < actions.size(); ++i) {
701        if (actions[i]->shouldPushSnapshot())
702            requireSnapshot = true;
703    }
704
705    if (!m_snapshotTexture && requireSnapshot)
706        m_snapshotTexture = textureCacheCompositingThread()->createTexture();
707
708    LayerRendererSurface* surface = layer->layerRendererSurface();
709
710    // From the code in LayerRenderer, we see that the layer will have a trivial transform that will
711    // result in the transformed bounds being a polygon with 4 vertices, i.e. a quad.
712    // The LayerFilterRenderer depends on the layer being a quad, so assert to make sure.
713    ASSERT(layer->transformedBounds().size() == 4);
714    if (layer->transformedBounds().size() != 4)
715        return;
716
717    glVertexAttribPointer(m_positionLocation, 2, GL_FLOAT, GL_FALSE, 0, layer->transformedBounds().data());
718    glEnableVertexAttribArray(m_positionLocation);
719    glVertexAttribPointer(m_texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, layer->textureCoordinates().data());
720    glEnableVertexAttribArray(m_texCoordLocation);
721
722    m_texture->protect(surface->texture()->size(), BlackBerry::Platform::Graphics::AlwaysBacked);
723    if (requireSnapshot)
724        m_snapshotTexture->protect(surface->texture()->size(), BlackBerry::Platform::Graphics::AlwaysBacked);
725
726    if (!fbo)
727        glGenFramebuffers(1, &fbo);
728
729    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
730
731    for (unsigned i = 0; i < actions.size(); ++i) {
732        // NOTE ABOUT PING-PONGING
733        // =======================
734        // Under OpenGL ES 2.0, we cannot use the fbo we are writting to as a texture, so we need to play ping-pong:
735        //  1) Draw parent surface to our texture with effect.
736        //  2) Draw our surface to parent texture with effect.
737        //  3) Repeat.
738        // Because we eventually have to end on the parent texture, we need an even number of actions.
739        // actionsForOperations takes care of that.
740
741        if (actions[i]->shouldPushSnapshot()) {
742            RefPtr<LayerTexture> currentTexture = (!(i % 2) ? surface->texture() : m_texture);
743            pushSnapshot(surface, currentTexture->platformTexture());
744        }
745        if (!(i % 2))
746            ping(surface); // Set framebuffer to ours, and texture to parent
747        else
748            pong(surface); // Set texture to parent, and framebuffer to us
749
750        glClear(GL_COLOR_BUFFER_BIT); // to transparency
751        glViewport(0, 0, surface->size().width(), surface->size().height());
752
753        actions[i]->useActionOn(this);
754
755        if (actions[i]->shouldPopSnapshot())
756            popSnapshot();
757
758        switch (actions[i]->drawingMode()) {
759        case LayerFilterRendererAction::DrawTriangleFanArrays:
760            glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
761            break;
762        case LayerFilterRendererAction::DrawTriangleElementsUShort0:
763            glDrawElements(GL_TRIANGLES, actions[i]->drawingModeParameter(), GL_UNSIGNED_SHORT, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(0)));
764            break;
765        case LayerFilterRendererAction::NumberOfDrawingModes:
766            ASSERT_NOT_REACHED();
767            break;
768        }
769
770        actions[i]->restoreState();
771
772        glVertexAttribPointer(m_positionLocation, 2, GL_FLOAT, GL_FALSE, 0, layer->transformedBounds().data());
773        glEnableVertexAttribArray(m_positionLocation);
774        glVertexAttribPointer(m_texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, layer->textureCoordinates().data());
775        glEnableVertexAttribArray(m_texCoordLocation);
776    }
777
778    m_texture->unprotect();
779    if (requireSnapshot)
780        m_snapshotTexture->unprotect();
781    glBindTexture(GL_TEXTURE_2D, 0);
782
783    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
784}
785
786} // namespace WebCore
787
788#endif // USE(ACCELERATED_COMPOSITING) && USE(CSS_FILTERS)
789