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