[BlackBerry] compositing/iframes/scroll-fixed-transformed-element.html fails in manua...
[WebKit-https.git] / Source / WebCore / platform / graphics / blackberry / LayerRenderer.cpp
1 /*
2  * Copyright (C) 2010, 2011, 2012, 2013 Research In Motion Limited. All rights reserved.
3  * Copyright (C) 2010 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32
33 #include "config.h"
34
35 #if USE(ACCELERATED_COMPOSITING)
36
37 #include "LayerRenderer.h"
38 #include "LayerRendererClient.h"
39
40 #include "LayerCompositingThread.h"
41 #include "LayerFilterRenderer.h"
42 #include "TextureCacheCompositingThread.h"
43
44 #include <BlackBerryPlatformGraphics.h>
45 #include <BlackBerryPlatformLog.h>
46 #include <EGL/egl.h>
47 #include <limits>
48 #include <wtf/text/CString.h>
49 #include <wtf/text/WTFString.h>
50
51 #define DEBUG_LAYER_ANIMATIONS 0 // Show running animations as green.
52 #define DEBUG_CLIPPING 0
53
54 using BlackBerry::Platform::Graphics::GLES2Context;
55 using BlackBerry::Platform::Graphics::GLES2Program;
56 using namespace std;
57
58 namespace WebCore {
59
60 #ifndef NDEBUG
61 #define checkGLError() \
62 { \
63     if (GLenum error = glGetError()) \
64         BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelCritical, "%s:%d GL Error: 0x%x ", __FILE__, __LINE__, error); \
65 }
66 #else
67 #define checkGLError()
68 #endif
69
70 GLuint LayerRenderer::loadShader(GLenum type, const char* shaderSource)
71 {
72     GLuint shader = glCreateShader(type);
73     if (!shader)
74         return 0;
75     glShaderSource(shader, 1, &shaderSource, 0);
76     glCompileShader(shader);
77     GLint compiled;
78     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
79     if (!compiled) {
80         char infoLog[2048];
81         GLsizei length;
82         glGetShaderInfoLog(shader, 2048, &length, infoLog);
83         BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelCritical, "Failed to compile shader:\n%s\nlog: %s", shaderSource, infoLog);
84         glDeleteShader(shader);
85         return 0;
86     }
87     return shader;
88 }
89
90 GLuint LayerRenderer::loadShaderProgram(const char* vertexShaderSource, const char* fragmentShaderSource)
91 {
92     GLuint vertexShader;
93     GLuint fragmentShader;
94     GLuint programObject;
95     GLint linked;
96     vertexShader = loadShader(GL_VERTEX_SHADER, vertexShaderSource);
97     if (!vertexShader)
98         return 0;
99     fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
100     if (!fragmentShader) {
101         glDeleteShader(vertexShader);
102         return 0;
103     }
104     programObject = glCreateProgram();
105     if (programObject) {
106         glAttachShader(programObject, vertexShader);
107         glAttachShader(programObject, fragmentShader);
108         glLinkProgram(programObject);
109         glGetProgramiv(programObject, GL_LINK_STATUS, &linked);
110         if (!linked) {
111             glDeleteProgram(programObject);
112             programObject = 0;
113         }
114     }
115     glDeleteShader(vertexShader);
116     glDeleteShader(fragmentShader);
117     return programObject;
118 }
119
120 TransformationMatrix LayerRenderer::orthoMatrix(float left, float right, float bottom, float top, float nearZ, float farZ)
121 {
122     float deltaX = right - left;
123     float deltaY = top - bottom;
124     float deltaZ = farZ - nearZ;
125     TransformationMatrix ortho;
126     if (!deltaX || !deltaY || !deltaZ)
127         return ortho;
128     ortho.setM11(2.0f / deltaX);
129     ortho.setM41(-(right + left) / deltaX);
130     ortho.setM22(2.0f / deltaY);
131     ortho.setM42(-(top + bottom) / deltaY);
132     ortho.setM33(-2.0f / deltaZ);
133     ortho.setM43(-(nearZ + farZ) / deltaZ);
134     return ortho;
135 }
136
137 static Vector<LayerCompositingThread*> rawPtrVectorFromRefPtrVector(const Vector<RefPtr<LayerCompositingThread> >& sublayers)
138 {
139     Vector<LayerCompositingThread*> sublayerList;
140     for (size_t i = 0; i < sublayers.size(); i++)
141         sublayerList.append(sublayers[i].get());
142
143     return sublayerList;
144 }
145
146 PassOwnPtr<LayerRenderer> LayerRenderer::create(LayerRendererClient* client)
147 {
148     return adoptPtr(new LayerRenderer(client));
149 }
150
151 LayerRenderer::LayerRenderer(LayerRendererClient* client)
152     : m_client(client)
153     , m_scale(1.0)
154     , m_animationTime(-numeric_limits<double>::infinity())
155     , m_fbo(0)
156     , m_currentLayerRendererSurface(0)
157     , m_isRobustnessSupported(false)
158     , m_needsCommit(false)
159     , m_stencilCleared(false)
160 {
161     // We're now initializing lazily, so a check if the context can be made current
162     // will have to suffice to determine if hardware compositing is possible.
163     m_hardwareCompositing = makeContextCurrent();
164     if (m_hardwareCompositing) {
165         m_isRobustnessSupported = String(reinterpret_cast<const char*>(::glGetString(GL_EXTENSIONS))).contains("GL_EXT_robustness");
166         if (m_isRobustnessSupported)
167             m_glGetGraphicsResetStatusEXT = reinterpret_cast<PFNGLGETGRAPHICSRESETSTATUSEXTPROC>(eglGetProcAddress("glGetGraphicsResetStatusEXT"));
168     }
169 }
170
171 LayerRenderer::~LayerRenderer()
172 {
173     if (m_hardwareCompositing) {
174         makeContextCurrent();
175         if (m_fbo)
176             glDeleteFramebuffers(1, &m_fbo);
177
178         for (size_t i = 0; i < NumberOfPrograms; ++i)
179             glDeleteProgram(m_programs[i].m_program);
180
181         // Free up all GL textures.
182         while (m_layers.begin() != m_layers.end()) {
183             LayerSet::iterator iter = m_layers.begin();
184             (*iter)->deleteTextures();
185             (*iter)->setLayerRenderer(0);
186             removeLayer(*iter);
187         }
188
189         textureCacheCompositingThread()->clear();
190     }
191 }
192
193 void LayerRenderer::releaseLayerResources()
194 {
195     if (m_hardwareCompositing) {
196         makeContextCurrent();
197         // Free up all GL textures.
198         for (LayerSet::iterator iter = m_layers.begin(); iter != m_layers.end(); ++iter)
199             (*iter)->deleteTextures();
200
201         textureCacheCompositingThread()->clear();
202     }
203 }
204
205 static inline bool compareLayerZ(const LayerCompositingThread* a, const LayerCompositingThread* b)
206 {
207     const TransformationMatrix& transformA = a->drawTransform();
208     const TransformationMatrix& transformB = b->drawTransform();
209
210     return transformA.m43() < transformB.m43();
211 }
212
213 void LayerRenderer::prepareFrame(double animationTime, LayerCompositingThread* rootLayer)
214 {
215     if (animationTime != m_animationTime) {
216         m_animationTime = animationTime;
217
218         // Aha, new frame! Reset rendering results.
219         bool wasEmpty = m_lastRenderingResults.isEmpty();
220         m_lastRenderingResults = LayerRenderingResults();
221         m_lastRenderingResults.wasEmpty = wasEmpty;
222     }
223
224     if (!rootLayer)
225         return;
226
227     bool isContextCurrent = makeContextCurrent();
228     prepareFrameRecursive(rootLayer, animationTime, isContextCurrent);
229 }
230
231 void LayerRenderer::setViewport(const IntRect& targetRect, const IntRect& clipRect, const FloatRect& visibleRect, const IntRect& layoutRect, const IntSize& contentsSize)
232 {
233     // These parameters are used to calculate position of fixed position elements
234     m_visibleRect = visibleRect;
235     m_layoutRect = layoutRect;
236     m_contentsSize = contentsSize;
237
238     m_viewport = targetRect;
239     m_scissorRect = clipRect;
240
241     // The clipRect parameter uses render target coordinates, map to normalized device coordinates
242     m_clipRect = clipRect;
243     m_clipRect.intersect(targetRect);
244     m_clipRect = FloatRect(-1 + 2 * (m_clipRect.x() - targetRect.x()) / targetRect.width(),
245                            -1 + 2 * (m_clipRect.y() - targetRect.y()) / targetRect.height(),
246                            2 * m_clipRect.width() / targetRect.width(),
247                            2 * m_clipRect.height() / targetRect.height());
248
249 #if DEBUG_CLIPPING
250     printf("LayerRenderer::setViewport() m_visibleRect=(%.2f,%.2f %.2fx%.2f), m_layoutRect=(%d,%d %dx%d), m_contentsSize=(%dx%d), m_viewport=(%d,%d %dx%d), m_scissorRect=(%d,%d %dx%d), m_clipRect=(%.2f,%.2f %.2fx%.2f)\n",
251         m_visibleRect.x(), m_visibleRect.y(), m_visibleRect.width(), m_visibleRect.height(),
252         m_layoutRect.x(), m_layoutRect.y(), m_layoutRect.width(), m_layoutRect.height(),
253         m_contentsSize.width(), m_contentsSize.height(),
254         m_viewport.x(), m_viewport.y(), m_viewport.width(), m_viewport.height(),
255         m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height(),
256         m_clipRect.x(), m_clipRect.y(), m_clipRect.width(), m_clipRect.height());
257     fflush(stdout);
258 #endif
259
260     if (!m_hardwareCompositing)
261         return;
262
263     // Okay, we're going to do some drawing.
264     if (!makeContextCurrent())
265         return;
266
267     // Get rid of any bound buffer that might affect the interpretation of our
268     // glVertexAttribPointer calls.
269     glBindBuffer(GL_ARRAY_BUFFER, 0);
270     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
271
272     glActiveTexture(GL_TEXTURE0);
273     glDisable(GL_DEPTH_TEST);
274     glDisable(GL_CULL_FACE);
275     glDisable(GL_STENCIL_TEST);
276
277     // If culling is enabled then we will cull the backface.
278     glCullFace(GL_BACK);
279
280     // The BlackBerry::Platform::GraphicsContext uses OpenGL conventions, so everything is upside down
281     glFrontFace(GL_CW);
282
283     checkGLError();
284
285     glViewport(m_viewport.x(), m_viewport.y(), m_viewport.width(), m_viewport.height());
286
287     glEnable(GL_SCISSOR_TEST);
288 #if DEBUG_CLIPPING
289     printf("LayerRenderer::compositeLayers(): clipping to (%d,%d %dx%d)\n", m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height());
290     fflush(stdout);
291 #endif
292     glScissor(m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height());
293
294     if (m_client->shouldClearSurfaceBeforeCompositing()) {
295         glClearColor(0, 0, 0, 0);
296         glClear(GL_COLOR_BUFFER_BIT);
297     }
298     m_stencilCleared = false;
299 }
300
301 void LayerRenderer::compositeLayers(const TransformationMatrix& matrix, LayerCompositingThread* rootLayer)
302 {
303     ASSERT(m_hardwareCompositing);
304     if (!m_hardwareCompositing)
305         return;
306
307     if (!rootLayer)
308         return;
309
310     // Used to draw scale invariant layers. We assume uniform scale.
311     // The matrix maps to normalized device coordinates, a system that maps the
312     // viewport to the interval -1 to 1.
313     // So it has to scale down by a factor equal to one half the viewport.
314     m_scale = matrix.m11() * m_viewport.width() / 2;
315
316     Vector<RefPtr<LayerCompositingThread> > surfaceLayers;
317     const Vector<RefPtr<LayerCompositingThread> >& sublayers = rootLayer->getSublayers();
318     for (size_t i = 0; i < sublayers.size(); i++) {
319         float opacity = 1;
320         FloatRect clipRect(m_clipRect);
321         updateLayersRecursive(sublayers[i].get(), matrix, surfaceLayers, opacity, clipRect);
322     }
323
324     // Decompose the dirty rect into a set of non-overlaping rectangles
325     // (they need to not overlap so that the blending code doesn't draw any region twice).
326     for (int i = 0; i < LayerRenderingResults::NumberOfDirtyRects; ++i) {
327         BlackBerry::Platform::IntRectRegion region(BlackBerry::Platform::IntRect(m_lastRenderingResults.dirtyRect(i)));
328         m_lastRenderingResults.dirtyRegion = BlackBerry::Platform::IntRectRegion::unionRegions(m_lastRenderingResults.dirtyRegion, region);
329     }
330
331     // If we won't draw anything, don't touch the OpenGL APIs.
332     if (m_lastRenderingResults.isEmpty() && m_lastRenderingResults.wasEmpty)
333         return;
334
335     // Okay, we're going to do some drawing.
336     if (!makeContextCurrent())
337         return;
338
339     // If some layers should be drawed on temporary surfaces, we should do it first.
340     drawLayersOnSurfaces(surfaceLayers);
341
342     // Don't render the root layer, the BlackBerry port uses the BackingStore to draw the
343     // root layer.
344     for (size_t i = 0; i < sublayers.size(); i++) {
345         int currentStencilValue = 0;
346         FloatRect clipRect(m_clipRect);
347         compositeLayersRecursive(sublayers[i].get(), currentStencilValue, clipRect);
348     }
349
350     // We need to make sure that all texture resource usage is finished before
351     // unlocking the texture resources, so force a glFinish() in that case.
352     if (m_layersLockingTextureResources.size())
353         glFinish();
354
355     m_client->context()->swapBuffers();
356
357     glDisable(GL_SCISSOR_TEST);
358     glDisable(GL_STENCIL_TEST);
359
360     // PR 147254, the EGL implementation crashes when the last bound texture
361     // was an EGLImage, and you try to bind another texture and the pixmap
362     // backing the EGLImage was deleted in between. Make this easier for the
363     // driver by unbinding early (when the pixmap is hopefully still around).
364     glBindTexture(GL_TEXTURE_2D, 0);
365
366     LayerSet::iterator iter = m_layersLockingTextureResources.begin();
367     for (; iter != m_layersLockingTextureResources.end(); ++iter)
368         (*iter)->releaseTextureResources();
369
370     m_layersLockingTextureResources.clear();
371
372     if (m_needsCommit) {
373         m_needsCommit = false;
374         rootLayer->scheduleCommit();
375     }
376
377     textureCacheCompositingThread()->collectGarbage();
378 }
379
380 static float texcoords[4 * 2] = { 0, 0,  0, 1,  1, 1,  1, 0 };
381
382 void LayerRenderer::compositeBuffer(const TransformationMatrix& transform, const FloatRect& contents, BlackBerry::Platform::Graphics::Buffer* buffer, bool contentsOpaque, float opacity)
383 {
384     if (!buffer)
385         return;
386
387     FloatQuad vertices(transform.mapPoint(contents.minXMinYCorner()),
388                        transform.mapPoint(contents.minXMaxYCorner()),
389                        transform.mapPoint(contents.maxXMaxYCorner()),
390                        transform.mapPoint(contents.maxXMinYCorner()));
391
392     if (!vertices.boundingBox().intersects(m_clipRect))
393         return;
394
395     if (!contentsOpaque || opacity < 1.0f) {
396         glEnable(GL_BLEND);
397         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
398     } else {
399         glDisable(GL_BLEND);
400     }
401
402     if (BlackBerry::Platform::Graphics::lockAndBindBufferGLTexture(buffer, GL_TEXTURE_2D)) {
403         const GLES2Program& program = useProgram(LayerProgramRGBA);
404         glUniform1f(program.opacityLocation(), opacity);
405
406         glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, &vertices);
407         glVertexAttribPointer(program.texCoordLocation(), 2, GL_FLOAT, GL_FALSE, 0, texcoords);
408
409         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
410         BlackBerry::Platform::Graphics::releaseBufferGLTexture(buffer);
411     }
412 }
413
414 void LayerRenderer::drawColor(const TransformationMatrix& transform, const FloatRect& contents, const Color& color)
415 {
416     FloatQuad vertices(transform.mapPoint(contents.minXMinYCorner()),
417                        transform.mapPoint(contents.minXMaxYCorner()),
418                        transform.mapPoint(contents.maxXMaxYCorner()),
419                        transform.mapPoint(contents.maxXMinYCorner()));
420
421     if (!vertices.boundingBox().intersects(m_clipRect))
422         return;
423
424     const GLES2Program& program = useProgram(ColorProgram);
425
426     if (color.alpha() < 255) {
427         glEnable(GL_BLEND);
428         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
429     } else
430         glDisable(GL_BLEND);
431
432     glUniform4f(m_colorColorLocation, color.red() / 255.0, color.green() / 255.0, color.blue() / 255.0, color.alpha() / 255.0);
433     glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, &vertices);
434
435     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
436 }
437
438 bool LayerRenderer::useSurface(LayerRendererSurface* surface)
439 {
440     if (m_currentLayerRendererSurface == surface)
441         return true;
442
443     m_currentLayerRendererSurface = surface;
444     if (!surface) {
445         glBindFramebuffer(GL_FRAMEBUFFER, 0);
446         glViewport(m_viewport.x(), m_viewport.y(), m_viewport.width(), m_viewport.height());
447         return true;
448     }
449
450     surface->ensureTexture();
451
452     GLuint texid = reinterpret_cast<GLuint>(platformBufferHandle(surface->texture()->textureId()));
453     if (!texid) {
454         BlackBerry::Platform::Graphics::lockAndBindBufferGLTexture(surface->texture()->textureId(), GL_TEXTURE_2D);
455         texid = reinterpret_cast<GLuint>(platformBufferHandle(surface->texture()->textureId()));
456     }
457
458     if (!m_fbo)
459         glGenFramebuffers(1, &m_fbo);
460     glBindTexture(GL_TEXTURE_2D, 0);
461     glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
462     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texid, 0);
463
464 #ifndef NDEBUG
465     GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
466     if (status != GL_FRAMEBUFFER_COMPLETE) {
467         fprintf(stderr, "glCheckFramebufferStatus error %x\n", status);
468         return false;
469     }
470 #endif
471
472     glViewport(0, 0, surface->size().width(), surface->size().height());
473     return true;
474 }
475
476 void LayerRenderer::drawLayersOnSurfaces(const Vector<RefPtr<LayerCompositingThread> >& surfaceLayers)
477 {
478     for (int i = surfaceLayers.size() - 1; i >= 0; i--) {
479         LayerCompositingThread* layer = surfaceLayers[i].get();
480         LayerRendererSurface* surface = layer->layerRendererSurface();
481         if (!surface || !useSurface(surface))
482             continue;
483
484         glDisable(GL_SCISSOR_TEST);
485         glClearColor(0, 0, 0, 0);
486         glClear(GL_COLOR_BUFFER_BIT);
487
488         int currentStencilValue = 0;
489         FloatRect clipRect(-1, -1, 2, 2);
490         compositeLayersRecursive(surfaceLayers[i].get(), currentStencilValue, clipRect);
491
492 #if ENABLE(CSS_FILTERS)
493         if (!m_filterRenderer)
494             m_filterRenderer = LayerFilterRenderer::create(GLES2Program::PositionAttributeIndex, GLES2Program::TexCoordAttributeIndex);
495         if (layer->filterOperationsChanged()) {
496             layer->setFilterOperationsChanged(false);
497             layer->setFilterActions(m_filterRenderer->actionsForOperations(surface, layer->filters().operations()));
498         }
499         m_filterRenderer->applyActions(m_fbo, layer, layer->filterActions());
500         glClearColor(0, 0, 0, 0);
501 #endif
502     }
503
504     // If there are layers drawed on surfaces, we need to switch to default framebuffer.
505     // Otherwise, we just need to set viewport.
506     if (surfaceLayers.size()) {
507         useSurface(0);
508         glEnable(GL_SCISSOR_TEST);
509         glScissor(m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height());
510     }
511 }
512
513 void LayerRenderer::addLayer(LayerCompositingThread* layer)
514 {
515     m_layers.add(layer);
516 }
517
518 bool LayerRenderer::removeLayer(LayerCompositingThread* layer)
519 {
520     LayerSet::iterator iter = m_layers.find(layer);
521     if (iter == m_layers.end())
522         return false;
523     m_layers.remove(layer);
524     return true;
525 }
526
527 void LayerRenderer::addLayerToReleaseTextureResourcesList(LayerCompositingThread* layer)
528 {
529     m_layersLockingTextureResources.add(layer);
530 }
531
532 static int glRound(float f)
533 {
534     return floorf(f + 0.5f);
535 }
536
537 // Transform normalized device coordinates to window coordinates
538 // as specified in the OpenGL ES 2.0 spec section 2.12.1.
539 IntRect LayerRenderer::toOpenGLWindowCoordinates(const FloatRect& r) const
540 {
541     float vw2 = m_viewport.width() / 2.0;
542     float vh2 = m_viewport.height() / 2.0;
543     float ox = m_viewport.x() + vw2;
544     float oy = m_viewport.y() + vh2;
545     return IntRect(glRound(r.x() * vw2 + ox), glRound(r.y() * vh2 + oy), glRound(r.width() * vw2), glRound(r.height() * vh2));
546 }
547
548 // Transform normalized device coordinates to window coordinates as WebKit understands them.
549 //
550 // The OpenGL surface may be larger than the WebKit window, and OpenGL window coordinates
551 // have origin in bottom left while WebKit window coordinates origin is in top left.
552 // The viewport is setup to cover the upper portion of the larger OpenGL surface.
553 IntRect LayerRenderer::toWebKitWindowCoordinates(const FloatRect& r) const
554 {
555     float vw2 = m_viewport.width() / 2.0;
556     float vh2 = m_viewport.height() / 2.0;
557     float ox = m_viewport.x() + vw2;
558     float oy = m_client->context()->surfaceSize().height() - (m_viewport.y() + vh2);
559     return enclosingIntRect(FloatRect(r.x() * vw2 + ox, -(r.y()+r.height()) * vh2 + oy, r.width() * vw2, r.height() * vh2));
560 }
561
562 // Similar to toWebKitWindowCoordinates except that this also takes any zoom into account.
563 IntRect LayerRenderer::toWebKitDocumentCoordinates(const FloatRect& r) const
564 {
565     // The zoom is the ratio between visibleRect (or layoutRect) and dstRect parameters which are passed to drawLayers
566     float zoom = m_visibleRect.width() / m_viewport.width();
567     // Could assert here that it doesn't matter whether we choose width or height in the above statement:
568     // because both rectangles should have very similar shapes (subject only to pixel rounding error).
569
570     IntRect result = toWebKitWindowCoordinates(r);
571     result.scale(zoom);
572     return result;
573 }
574
575 // Draws a debug border around the layer's bounds.
576 void LayerRenderer::drawDebugBorder(LayerCompositingThread* layer)
577 {
578     Color borderColor = layer->borderColor();
579
580 #if DEBUG_LAYER_ANIMATIONS
581     if (layer->hasRunningAnimations())
582         borderColor =  Color(0x00, 0xFF, 0x00, 0xFF);
583 #endif
584
585     if (!borderColor.alpha())
586         return;
587
588     if (borderColor.alpha() < 255) {
589         glEnable(GL_BLEND);
590         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
591     } else
592         glDisable(GL_BLEND);
593
594     const GLES2Program& program = useProgram(ColorProgram);
595     glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, &layer->getTransformedBounds());
596     glUniform4f(m_colorColorLocation, borderColor.red() / 255.0, borderColor.green() / 255.0, borderColor.blue() / 255.0, 1);
597
598     glLineWidth(std::max(1.0f, layer->borderWidth()));
599     glDrawArrays(GL_LINE_LOOP, 0, 4);
600 }
601
602 // Clears a rectangle inside the layer's bounds.
603 void LayerRenderer::drawHolePunchRect(LayerCompositingThread* layer)
604 {
605     const GLES2Program& program = useProgram(ColorProgram);
606     glUniform4f(m_colorColorLocation, 0, 0, 0, 0);
607
608     glEnable(GL_BLEND);
609     glBlendFunc(GL_ONE, GL_ZERO);
610     FloatQuad hole = layer->getTransformedHolePunchRect();
611     glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, &hole);
612     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
613     checkGLError();
614 }
615
616 void LayerRenderer::prepareFrameRecursive(LayerCompositingThread* layer, double animationTime, bool isContextCurrent)
617 {
618     // This might cause the layer to recompute some attributes.
619     m_lastRenderingResults.needsAnimationFrame |= layer->updateAnimations(animationTime);
620
621     if (isContextCurrent) {
622         // Even non-visible layers need to perform their texture jobs, or they will
623         // pile up and waste memory.
624         if (layer->needsTexture())
625             layer->updateTextureContentsIfNeeded();
626         if (layer->maskLayer() && layer->maskLayer()->needsTexture())
627             layer->maskLayer()->updateTextureContentsIfNeeded();
628         if (layer->replicaLayer()) {
629             LayerCompositingThread* replica = layer->replicaLayer();
630             if (replica->needsTexture())
631                 replica->updateTextureContentsIfNeeded();
632             if (replica->maskLayer() && replica->maskLayer()->needsTexture())
633                 replica->maskLayer()->updateTextureContentsIfNeeded();
634         }
635     }
636
637     const Vector<RefPtr<LayerCompositingThread> >& sublayers = layer->getSublayers();
638     for (size_t i = 0; i < sublayers.size(); i++)
639         prepareFrameRecursive(sublayers[i].get(), animationTime, isContextCurrent);
640 }
641
642 void LayerRenderer::updateLayersRecursive(LayerCompositingThread* layer, const TransformationMatrix& matrix, Vector<RefPtr<LayerCompositingThread> >& surfaceLayers, float opacity, FloatRect clipRect)
643 {
644     // The contract for LayerCompositingThread::setLayerRenderer is it must be set if the layer has been rendered.
645     // So do it now, before we render it in compositeLayersRecursive.
646     layer->setLayerRenderer(this);
647     if (layer->maskLayer())
648         layer->maskLayer()->setLayerRenderer(this);
649     if (layer->replicaLayer()) {
650         LayerCompositingThread* replica = layer->replicaLayer();
651         replica->setLayerRenderer(this);
652         if (replica->maskLayer())
653             replica->maskLayer()->setLayerRenderer(this);
654     }
655
656     // Compute the new matrix transformation that will be applied to this layer and
657     // all its sublayers. It's important to remember that the layer's position
658     // is the position of the layer's anchor point. Also, the coordinate system used
659     // assumes that the origin is at the lower left even though the coordinates the browser
660     // gives us for the layers are for the upper left corner. The Y flip happens via
661     // the orthographic projection applied at render time.
662     // The transformation chain for the layer is (using the Matrix x Vector order):
663     // M = M[p] * Tr[l] * M[l] * Tr[c]
664     // Where M[p] is the parent matrix passed down to the function
665     //       Tr[l] is the translation matrix locating the layer's anchor point
666     //       Tr[c] is the translation offset between the anchor point and the center of the layer
667     //       M[l] is the layer's matrix (applied at the anchor point)
668     // This transform creates a coordinate system whose origin is the center of the layer.
669     // Note that the final matrix used by the shader for the layer is P * M * S . This final product
670     // is computed in drawTexturedQuad().
671     // Where: P is the projection matrix
672     //        M is the layer's matrix computed above
673     //        S is the scale adjustment (to scale up to the layer size)
674     FloatSize bounds = layer->bounds();
675     if (layer->sizeIsScaleInvariant())
676         bounds.scale(1.0 / m_scale);
677     FloatPoint anchorPoint = layer->anchorPoint();
678     FloatPoint position = layer->position();
679
680     // Layer whose hasFixedContainer is true will get scrolled relative to
681     // the fixed positioned parent.
682     if (!layer->hasFixedContainer() && (layer->isFixedPosition() || layer->hasFixedAncestorInDOMTree())) {
683         FloatRect layoutRect = m_layoutRect;
684         FloatSize contentsSize = m_contentsSize;
685         FloatRect visibleRect = m_visibleRect;
686         for (LayerCompositingThread* curr = layer->superlayer(); curr; curr = curr->superlayer()) {
687
688             if (curr->isContainerForFixedPositionLayers()) {
689                 layoutRect = curr->frameVisibleRect();
690                 contentsSize = curr->frameContentsSize();
691
692                 // If we reach a container for fixed position layers, and it has its override's position set, it means it is a scrollable iframe
693                 // currently being scrolled. Otherwise, use the WebKit-thread scroll position stored in frameVisibleRect().
694                 if (curr->override()->isPositionSet()) {
695                     // Inverted logic of
696                     // FloatPoint layerPosition(-scrollPosition.x() + anchor.x() * bounds.width(),
697                     //                          -scrollPosition.y() + anchor.y() * bounds.height());
698                     FloatPoint scrollPosition(
699                         -(curr->override()->position().x() - (curr->anchorPoint().x() * curr->bounds().width())),
700                         -(curr->override()->position().y() - (curr->anchorPoint().y() * curr->bounds().height())));
701                     visibleRect = FloatRect(scrollPosition, layoutRect.size());
702                 } else
703                     visibleRect = layoutRect;
704
705                 break;
706             }
707         }
708
709         FloatPoint maximumScrollPosition = FloatPoint(0, 0) + (contentsSize - visibleRect.size());
710         FloatPoint maximumLayoutScrollPosition = FloatPoint(0, 0) + (contentsSize - layoutRect.size());
711
712         // The basic idea here is to set visible x/y to the value we want, and
713         // layout x/y to the value WebCore layouted the fixed element to.
714         float visibleY;
715         float layoutY;
716         if (layer->isFixedToTop()) {
717             visibleY = max(0.0f, min(maximumScrollPosition.y(), visibleRect.y()));
718             layoutY = max(0.0f, min(maximumLayoutScrollPosition.y(), layoutRect.y()));
719         } else {
720             visibleY = min(contentsSize.height(), visibleRect.y() + visibleRect.height());
721             layoutY = min(contentsSize.height(), max(0.0f, layoutRect.y()) + layoutRect.height());
722         }
723         position.setY(position.y() + (visibleY - layoutY));
724
725         float visibleX;
726         float layoutX;
727         if (layer->isFixedToLeft()) {
728             visibleX = max(0.0f, min(maximumScrollPosition.x(), visibleRect.x()));
729             layoutX = max(0.0f, min(maximumLayoutScrollPosition.x(), layoutRect.x()));
730         } else {
731             visibleX = min(contentsSize.width(), visibleRect.x() + visibleRect.width());
732             layoutX = min(contentsSize.width(), max(0.0f, layoutRect.x()) + layoutRect.width());
733         }
734         position.setX(position.x() + (visibleX - layoutX));
735     }
736
737     // Offset between anchor point and the center of the quad.
738     float centerOffsetX = (0.5 - anchorPoint.x()) * bounds.width();
739     float centerOffsetY = (0.5 - anchorPoint.y()) * bounds.height();
740
741     // M = M[p]
742     TransformationMatrix localMatrix = matrix;
743     // M = M[p] * Tr[l]
744     localMatrix.translate3d(position.x(), position.y(), layer->anchorPointZ());
745     // M = M[p] * Tr[l] * M[l]
746     localMatrix.multiply(layer->transform());
747     // M = M[p] * Tr[l] * M[l] * Tr[c]
748     localMatrix.translate3d(centerOffsetX, centerOffsetY, -layer->anchorPointZ());
749
750     // Calculate the layer's opacity.
751     opacity *= layer->opacity();
752
753 #if ENABLE(CSS_FILTERS)
754     bool useLayerRendererSurface = layer->maskLayer() || layer->replicaLayer() || layer->filters().size();
755 #else
756     bool useLayerRendererSurface = layer->maskLayer() || layer->replicaLayer();
757 #endif
758     if (!useLayerRendererSurface) {
759         layer->setDrawOpacity(opacity);
760         layer->clearLayerRendererSurface();
761     } else {
762         if (!layer->layerRendererSurface())
763             layer->createLayerRendererSurface();
764
765         LayerRendererSurface* surface = layer->layerRendererSurface();
766
767         layer->setDrawOpacity(1.0);
768         surface->setDrawOpacity(opacity);
769
770         surface->setDrawTransform(localMatrix);
771         if (layer->replicaLayer()) {
772             TransformationMatrix replicaMatrix = localMatrix;
773             replicaMatrix.translate3d(-0.5 * bounds.width(), -0.5 * bounds.height(), 0);
774             replicaMatrix.translate3d(layer->replicaLayer()->position().x(), layer->replicaLayer()->position().y(), 0);
775             replicaMatrix.multiply(layer->replicaLayer()->transform());
776             replicaMatrix.translate3d(centerOffsetX, centerOffsetY, 0);
777             surface->setReplicaDrawTransform(replicaMatrix);
778         }
779
780         IntRect drawRect = enclosingIntRect(FloatRect(FloatPoint(), bounds));
781         surface->setContentRect(drawRect);
782
783         TransformationMatrix projectionMatrix = orthoMatrix(drawRect.x(), drawRect.maxX(), drawRect.y(), drawRect.maxY(), -1000, 1000);
784         // The origin of the new surface is the upper left corner of the layer.
785         TransformationMatrix drawTransform;
786         drawTransform.translate3d(0.5 * bounds.width(), 0.5 * bounds.height(), 0);
787         // This layer will start using new transformation.
788         localMatrix = projectionMatrix * drawTransform;
789
790         surfaceLayers.append(layer);
791     }
792
793     layer->setDrawTransform(m_scale, localMatrix);
794
795 #if ENABLE(VIDEO)
796     bool layerVisible = clipRect.intersects(layer->getDrawRect()) || layer->mediaPlayer();
797 #else
798     bool layerVisible = clipRect.intersects(layer->getDrawRect());
799 #endif
800
801     if (layer->needsTexture() && layerVisible) {
802         IntRect dirtyRect = toWebKitWindowCoordinates(intersection(layer->getDrawRect(), clipRect));
803         m_lastRenderingResults.addDirtyRect(dirtyRect);
804     }
805
806     if (layer->masksToBounds())
807         clipRect.intersect(layer->getDrawRect());
808
809     // Flatten to 2D if the layer doesn't preserve 3D.
810     if (!layer->preserves3D()) {
811         localMatrix.setM13(0);
812         localMatrix.setM23(0);
813         localMatrix.setM31(0);
814         localMatrix.setM32(0);
815         // This corresponds to the depth range specified in the original orthographic projection matrix
816         localMatrix.setM33(0.001);
817         localMatrix.setM34(0);
818         localMatrix.setM43(0);
819     }
820
821     // Apply the sublayer transform.
822     localMatrix.multiply(layer->sublayerTransform());
823
824     // The origin of the sublayers is actually the bottom left corner of the layer
825     // (or top left when looking it it from the browser's pespective) instead of the center.
826     // The matrix passed down to the sublayers is therefore:
827     // M[s] = M * Tr[-center]
828     localMatrix.translate3d(-bounds.width() * 0.5, -bounds.height() * 0.5, 0);
829
830     const Vector<RefPtr<LayerCompositingThread> >& sublayers = layer->getSublayers();
831     for (size_t i = 0; i < sublayers.size(); i++)
832         updateLayersRecursive(sublayers[i].get(), localMatrix, surfaceLayers, opacity, clipRect);
833 }
834
835 static bool hasRotationalComponent(const TransformationMatrix& m)
836 {
837     return m.m12() || m.m13() || m.m23() || m.m21() || m.m31() || m.m32();
838 }
839
840 bool LayerRenderer::layerAlreadyOnSurface(LayerCompositingThread* layer) const
841 {
842     return layer->layerRendererSurface() && layer->layerRendererSurface() != m_currentLayerRendererSurface;
843 }
844
845 static void collect3DPreservingLayers(Vector<LayerCompositingThread*>& layers)
846 {
847     for (size_t i = 0; i < layers.size(); ++i) {
848         LayerCompositingThread* layer = layers[i];
849         if (!layer->preserves3D() || !layer->getSublayers().size())
850             continue;
851
852         Vector<LayerCompositingThread*> sublayers = rawPtrVectorFromRefPtrVector(layer->getSublayers());
853         collect3DPreservingLayers(sublayers);
854         layers.insert(i+1, sublayers);
855         i += sublayers.size();
856     }
857 }
858
859 void LayerRenderer::compositeLayersRecursive(LayerCompositingThread* layer, int stencilValue, FloatRect clipRect)
860 {
861     FloatRect rect;
862     if (layerAlreadyOnSurface(layer))
863         rect = layer->layerRendererSurface()->drawRect();
864     else
865         rect = layer->getDrawRect();
866
867 #if ENABLE(VIDEO)
868     bool layerVisible = clipRect.intersects(rect) || layer->mediaPlayer();
869 #else
870     bool layerVisible = clipRect.intersects(rect);
871 #endif
872
873     layer->setVisible(layerVisible);
874
875     // Note that there are two types of layers:
876     // 1. Layers that have their own GraphicsContext and can draw their contents on demand (layer->drawsContent() == true).
877     // 2. Layers that are just containers of images/video/etc that don't own a GraphicsContext (layer->contents() == true).
878
879     if ((layer->needsTexture() || layer->layerRendererSurface()) && layerVisible) {
880         updateScissorIfNeeded(clipRect);
881
882         if (stencilValue) {
883             glStencilFunc(GL_EQUAL, stencilValue, 0xff);
884             glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
885         }
886
887         if (layer->doubleSided())
888             glDisable(GL_CULL_FACE);
889         else
890             glEnable(GL_CULL_FACE);
891
892         if (layer->hasVisibleHolePunchRect())
893             drawHolePunchRect(layer);
894
895         // Draw the surface onto another surface or screen.
896         bool drawSurface = layerAlreadyOnSurface(layer);
897         // The texture format for the surface is RGBA.
898         LayerData::LayerProgram layerProgram = drawSurface ? LayerData::LayerProgramRGBA : layer->layerProgram();
899
900         if (!drawSurface) {
901             const GLES2Program& program = useLayerProgram(layerProgram);
902             layer->drawTextures(m_scale, program, m_visibleRect);
903         } else {
904             // Draw the reflection if it exists.
905             if (layer->replicaLayer()) {
906                 // If this layer and its reflection both have mask, we need another temporary surface.
907                 // Since this use case should be rare, currently it's not handled and the mask for
908                 // the reflection is applied only when this layer has no mask.
909                 LayerCompositingThread* mask = layer->maskLayer();
910                 if (!mask && layer->replicaLayer())
911                     mask = layer->replicaLayer()->maskLayer();
912
913                 const GLES2Program& program = useLayerProgram(layerProgram, mask);
914                 layer->drawSurface(layer->layerRendererSurface()->replicaDrawTransform(), mask, program);
915             }
916
917             const GLES2Program& program = useLayerProgram(layerProgram, layer->maskLayer());
918             layer->drawSurface(layer->layerRendererSurface()->drawTransform(), layer->maskLayer(), program);
919         }
920     }
921
922     // Draw the debug border if there is one.
923     drawDebugBorder(layer);
924
925     // The texture for the LayerRendererSurface can be released after the surface was drawed on another surface.
926     if (layerAlreadyOnSurface(layer)) {
927         layer->layerRendererSurface()->releaseTexture();
928         return;
929     }
930
931     // If we need to mask to bounds but the transformation has a rotational component
932     // to it, scissoring is not enough and we need to use the stencil buffer for clipping.
933     bool stencilClip = layer->masksToBounds() && hasRotationalComponent(layer->drawTransform());
934
935     if (stencilClip) {
936         if (!m_stencilCleared) {
937             glStencilMask(0xffffffff);
938             glClearStencil(0);
939             glClear(GL_STENCIL_BUFFER_BIT);
940             m_stencilCleared = true;
941         }
942
943         glEnable(GL_STENCIL_TEST);
944         glStencilFunc(GL_EQUAL, stencilValue, 0xff);
945         glStencilOp(GL_KEEP, GL_INCR, GL_INCR);
946
947         updateScissorIfNeeded(clipRect);
948         const GLES2Program& program = useProgram(ColorProgram);
949         glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
950         glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, &layer->getTransformedBounds());
951         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
952         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
953     }
954
955     if (layer->masksToBounds())
956         clipRect.intersect(layer->getDrawRect());
957
958     // Here, we need to sort the whole subtree of layers with preserve-3d. It
959     // affects all children, and the children of any children with preserve-3d,
960     // and so on.
961     Vector<LayerCompositingThread*> sublayers = rawPtrVectorFromRefPtrVector(layer->getSublayers());
962
963     bool preserves3D = layer->preserves3D();
964     bool superlayerPreserves3D = layer->superlayer() && layer->superlayer()->preserves3D();
965
966     // Collect and render all sublayers with preserves-3D.
967     // If the superlayer preserves 3D, we've already collected and rendered its
968     // children, so bail.
969     if (preserves3D && !superlayerPreserves3D) {
970         collect3DPreservingLayers(sublayers);
971         std::stable_sort(sublayers.begin(), sublayers.end(), compareLayerZ);
972     }
973
974     int newStencilValue = stencilClip ? stencilValue+1 : stencilValue;
975     for (size_t i = 0; i < sublayers.size(); i++) {
976         LayerCompositingThread* sublayer = sublayers[i];
977         // The root of the 3d-preserving subtree has collected all
978         // 3d-preserving layers and their children and will render them all in
979         // the right order.
980         if (preserves3D && superlayerPreserves3D)
981             continue;
982
983          compositeLayersRecursive(sublayer, newStencilValue, clipRect);
984     }
985
986     if (stencilClip) {
987         glStencilFunc(GL_LEQUAL, stencilValue, 0xff);
988         glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
989
990         updateScissorIfNeeded(clipRect);
991         const GLES2Program& program = useProgram(ColorProgram);
992         glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
993         glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, &layer->getTransformedBounds());
994         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
995         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
996
997         if (!stencilValue)
998             glDisable(GL_STENCIL_TEST);
999     }
1000 }
1001
1002 void LayerRenderer::updateScissorIfNeeded(const FloatRect& clipRect)
1003 {
1004 #if DEBUG_CLIPPING
1005     printf("LayerRenderer::updateScissorIfNeeded(): clipRect=(%.2f,%.2f %.2fx%.2f)\n", clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height());
1006     fflush(stdout);
1007 #endif
1008     IntRect clipRectWC = toOpenGLWindowCoordinates(clipRect);
1009     if (m_scissorRect == clipRectWC)
1010         return;
1011
1012     m_scissorRect = clipRectWC;
1013 #if DEBUG_CLIPPING
1014     printf("LayerRenderer::updateScissorIfNeeded(): clipping to (%d,%d %dx%d)\n", m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height());
1015     fflush(stdout);
1016 #endif
1017     glScissor(m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height());
1018 }
1019
1020 bool LayerRenderer::makeContextCurrent()
1021 {
1022     bool ret = m_client->context()->makeCurrent();
1023     if (ret && m_isRobustnessSupported) {
1024         if (m_glGetGraphicsResetStatusEXT() != GL_NO_ERROR) {
1025             BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelCritical, "Robust OpenGL context has been reset. Aborting.");
1026             CRASH();
1027         }
1028     }
1029     return ret;
1030 }
1031
1032 bool LayerRenderer::createProgram(ProgramIndex program)
1033 {
1034     // Shaders for drawing the layer contents.
1035     const char* vertexShaderString =
1036         "attribute vec4 a_position;   \n"
1037         "attribute vec2 a_texCoord;   \n"
1038         "varying vec2 v_texCoord;     \n"
1039         "void main()                  \n"
1040         "{                            \n"
1041         "  gl_Position = a_position;  \n"
1042         "  v_texCoord = a_texCoord;   \n"
1043         "}                            \n";
1044
1045     const char* fragmentShaderStringRGBA =
1046         "varying mediump vec2 v_texCoord;                           \n"
1047         "uniform lowp sampler2D s_texture;                          \n"
1048         "uniform lowp float alpha;                                  \n"
1049         "void main()                                                \n"
1050         "{                                                          \n"
1051         "  gl_FragColor = texture2D(s_texture, v_texCoord) * alpha; \n"
1052         "}                                                          \n";
1053
1054     const char* fragmentShaderStringBGRA =
1055         "varying mediump vec2 v_texCoord;                                \n"
1056         "uniform lowp sampler2D s_texture;                               \n"
1057         "uniform lowp float alpha;                                       \n"
1058         "void main()                                                     \n"
1059         "{                                                               \n"
1060         "  gl_FragColor = texture2D(s_texture, v_texCoord).bgra * alpha; \n"
1061         "}                                                               \n";
1062
1063     const char* fragmentShaderStringMaskRGBA =
1064         "varying mediump vec2 v_texCoord;                           \n"
1065         "uniform lowp sampler2D s_texture;                          \n"
1066         "uniform lowp sampler2D s_mask;                             \n"
1067         "uniform lowp float alpha;                                  \n"
1068         "void main()                                                \n"
1069         "{                                                          \n"
1070         "  lowp vec4 texColor = texture2D(s_texture, v_texCoord);   \n"
1071         "  lowp vec4 maskColor = texture2D(s_mask, v_texCoord);     \n"
1072         "  gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha * maskColor.w;           \n"
1073         "}                                                          \n";
1074
1075     const char* fragmentShaderStringMaskBGRA =
1076         "varying mediump vec2 v_texCoord;                                \n"
1077         "uniform lowp sampler2D s_texture;                               \n"
1078         "uniform lowp sampler2D s_mask;                                  \n"
1079         "uniform lowp float alpha;                                       \n"
1080         "void main()                                                     \n"
1081         "{                                                               \n"
1082         "  lowp vec4 texColor = texture2D(s_texture, v_texCoord).bgra;             \n"
1083         "  lowp vec4 maskColor = texture2D(s_mask, v_texCoord).bgra;          \n"
1084         "  gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha * maskColor.w;         \n"
1085         "}                                                               \n";
1086
1087     // Shaders for drawing the debug borders around the layers.
1088     const char* colorVertexShaderString =
1089         "attribute vec4 a_position;   \n"
1090         "void main()                  \n"
1091         "{                            \n"
1092         "   gl_Position = a_position; \n"
1093         "}                            \n";
1094
1095     const char* colorFragmentShaderString =
1096         "uniform lowp vec4 color;     \n"
1097         "void main()                  \n"
1098         "{                            \n"
1099         "  gl_FragColor = color;      \n"
1100         "}                            \n";
1101
1102     const char* vertexShader = 0;
1103     const char* fragmentShader = 0;
1104
1105     switch (program) {
1106     case LayerProgramRGBA:
1107     case LayerProgramBGRA:
1108     case LayerMaskProgramRGBA:
1109     case LayerMaskProgramBGRA:
1110         vertexShader = vertexShaderString;
1111         break;
1112     case ColorProgram:
1113         vertexShader = colorVertexShaderString;
1114         break;
1115     case NumberOfPrograms:
1116         return false;
1117     }
1118
1119     switch (program) {
1120     case LayerProgramRGBA:
1121         fragmentShader = fragmentShaderStringRGBA;
1122         break;
1123     case LayerProgramBGRA:
1124         fragmentShader = fragmentShaderStringBGRA;
1125         break;
1126     case LayerMaskProgramRGBA:
1127         fragmentShader = fragmentShaderStringMaskRGBA;
1128         break;
1129     case LayerMaskProgramBGRA:
1130         fragmentShader = fragmentShaderStringMaskBGRA;
1131         break;
1132     case ColorProgram:
1133         fragmentShader = colorFragmentShaderString;
1134         break;
1135     case NumberOfPrograms:
1136         return false;
1137     }
1138
1139     if (!vertexShader || !fragmentShader)
1140         return false;
1141
1142     GLuint programObject = loadShaderProgram(vertexShader, fragmentShader);
1143     if (!programObject) {
1144         LOG_ERROR("Failed to create program %u", program);
1145         return false;
1146     }
1147
1148     m_programs[program].m_program = programObject;
1149
1150     // Binds the given attribute name to a common location across all programs
1151     // used by the compositor. This allows the code to bind the attributes only once
1152     // even when switching between programs.
1153     glBindAttribLocation(programObject, GLES2Program::PositionAttributeIndex, "a_position");
1154     glBindAttribLocation(programObject, GLES2Program::TexCoordAttributeIndex, "a_texCoord");
1155
1156     checkGLError();
1157
1158     // Re-link the shader to get the new attrib location to take effect.
1159     glLinkProgram(programObject);
1160
1161     checkGLError();
1162
1163     // Get locations of uniforms for the layer content shader program.
1164     m_programs[program].m_locations[GLES2Program::OpacityUniform] = glGetUniformLocation(programObject, "alpha");
1165     switch (program) {
1166     case LayerProgramRGBA:
1167     case LayerProgramBGRA: {
1168         GLint samplerLocation = glGetUniformLocation(programObject, "s_texture");
1169         glUseProgram(programObject);
1170         glUniform1i(samplerLocation, 0);
1171         break;
1172     }
1173     case LayerMaskProgramRGBA:
1174     case LayerMaskProgramBGRA: {
1175         GLint maskSamplerLocation = glGetUniformLocation(programObject, "s_texture");
1176         GLint maskSamplerLocationMask = glGetUniformLocation(programObject, "s_mask");
1177         glUseProgram(programObject);
1178         glUniform1i(maskSamplerLocation, 0);
1179         glUniform1i(maskSamplerLocationMask, 1);
1180         break;
1181     }
1182     case ColorProgram:
1183         // Get locations of uniforms for the debug border shader program.
1184         m_colorColorLocation = glGetUniformLocation(programObject, "color");
1185         break;
1186     case NumberOfPrograms:
1187         return false;
1188     }
1189
1190     return true;
1191 }
1192
1193 const GLES2Program& LayerRenderer::useProgram(ProgramIndex index)
1194 {
1195     ASSERT(index < NumberOfPrograms);
1196     const GLES2Program& program = m_programs[index];
1197     if (!program.isValid() && !createProgram(index))
1198         return program;
1199
1200     glUseProgram(program.m_program);
1201
1202     glEnableVertexAttribArray(program.positionLocation());
1203     if (index != ColorProgram)
1204         glEnableVertexAttribArray(program.texCoordLocation());
1205
1206     return program;
1207 }
1208
1209 const GLES2Program& LayerRenderer::useLayerProgram(LayerData::LayerProgram layerProgram, bool isMask /* = false */)
1210 {
1211     int program = layerProgram;
1212     if (isMask)
1213         program += MaskPrograms;
1214     return useProgram(static_cast<ProgramIndex>(program));
1215 }
1216
1217 void LayerRenderingResults::addDirtyRect(const IntRect& rect)
1218 {
1219     IntRect dirtyUnion[NumberOfDirtyRects];
1220     int smallestIncrease = INT_MAX;
1221     int modifiedRect = 0;
1222     for (int i = 0; i < NumberOfDirtyRects; ++i) {
1223         dirtyUnion[i] = m_dirtyRects[i];
1224         dirtyUnion[i].unite(rect);
1225         int increase = dirtyUnion[i].width()*dirtyUnion[i].height() - m_dirtyRects[i].width()*m_dirtyRects[i].height();
1226         if (increase < smallestIncrease) {
1227             smallestIncrease = increase;
1228             modifiedRect = i;
1229         }
1230     }
1231
1232     m_dirtyRects[modifiedRect] = dirtyUnion[modifiedRect];
1233 }
1234
1235 bool LayerRenderingResults::isEmpty() const
1236 {
1237     for (int i = 0; i < NumberOfDirtyRects; ++i) {
1238         if (!m_dirtyRects[i].isEmpty())
1239             return false;
1240     }
1241     return true;
1242 }
1243
1244 } // namespace WebCore
1245
1246 #endif // USE(ACCELERATED_COMPOSITING)