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 * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following disclaimer 14 * in the documentation and/or other materials provided with the 15 * distribution. 16 * * Neither the name of Google Inc. nor the names of its 17 * contributors may be used to endorse or promote products derived from 18 * this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include "config.h" 34 35#if USE(ACCELERATED_COMPOSITING) 36 37#include "LayerCompositingThread.h" 38 39#include "LayerCompositingThreadClient.h" 40#include "LayerMessage.h" 41#include "LayerRenderer.h" 42#include "LayerRendererClient.h" 43#include "LayerUtilities.h" 44#include "LayerWebKitThread.h" 45#if ENABLE(VIDEO) 46#include "MediaPlayer.h" 47#include "MediaPlayerPrivateBlackBerry.h" 48#endif 49#include "PluginView.h" 50#include "StdLibExtras.h" 51#include "TextureCacheCompositingThread.h" 52 53#include <BlackBerryPlatformGLES2ContextState.h> 54#include <BlackBerryPlatformGraphics.h> 55#include <BlackBerryPlatformLog.h> 56#include <wtf/Assertions.h> 57 58using BlackBerry::Platform::Graphics::GLES2Program; 59 60namespace WebCore { 61 62void LayerOverride::removeAnimation(const String& name) 63{ 64 for (size_t i = 0; i < m_animations.size(); ++i) { 65 if (m_animations[i]->name() == name) { 66 m_animations.remove(i); 67 return; 68 } 69 } 70} 71 72PassRefPtr<LayerCompositingThread> LayerCompositingThread::create(LayerType type, LayerCompositingThreadClient* client) 73{ 74 return adoptRef(new LayerCompositingThread(type, client)); 75} 76 77LayerCompositingThread::LayerCompositingThread(LayerType type, LayerCompositingThreadClient* client) 78 : LayerData(type) 79 , m_layerRenderer(0) 80 , m_superlayer(0) 81 , m_centerW(0) 82 , m_pluginBuffer(0) 83 , m_drawOpacity(0) 84 , m_visible(false) 85 , m_commitScheduled(false) 86 , m_client(client) 87#if ENABLE(CSS_FILTERS) 88 , m_filterOperationsChanged(false) 89#endif 90{ 91} 92 93LayerCompositingThread::~LayerCompositingThread() 94{ 95 ASSERT(isCompositingThread()); 96 97 ASSERT(!superlayer()); 98 99 // Remove the superlayer reference from all sublayers. 100 while (m_sublayers.size()) 101 m_sublayers[0]->removeFromSuperlayer(); 102 103 // Delete all allocated textures 104 deleteTextures(); 105 106 // We just deleted all our textures, no need for the 107 // layer renderer to track us anymore 108 if (m_layerRenderer) 109 m_layerRenderer->removeLayer(this); 110 111 if (m_client) 112 m_client->layerCompositingThreadDestroyed(this); 113} 114 115void LayerCompositingThread::setLayerRenderer(LayerRenderer* renderer) 116{ 117 // It's not expected that layers will ever switch renderers. 118 ASSERT(!renderer || !m_layerRenderer || renderer == m_layerRenderer); 119 120 m_layerRenderer = renderer; 121 if (m_layerRenderer) 122 m_layerRenderer->addLayer(this); 123} 124 125void LayerCompositingThread::deleteTextures() 126{ 127 releaseTextureResources(); 128 129 if (m_client) 130 m_client->deleteTextures(this); 131} 132 133void LayerCompositingThread::setDrawTransform(double scale, const TransformationMatrix& matrix, const TransformationMatrix& projectionMatrix) 134{ 135 m_drawTransform = projectionMatrix * matrix; 136 137 FloatRect boundsRect(-origin(), bounds()); 138 139 if (sizeIsScaleInvariant()) 140 boundsRect.scale(1 / scale); 141 142 m_centerW = 0; 143 m_transformedBounds.clear(); 144 m_ws.clear(); 145 m_textureCoordinates.clear(); 146 if (matrix.hasPerspective() && !m_layerRendererSurface) { 147 // Perform processing according to http://www.w3.org/TR/css3-transforms 6.2 148 // If w < 0 for all four corners of the transformed box, the box is not rendered. 149 // If w < 0 for one to three corners of the transformed box, the box 150 // must be replaced by a polygon that has any parts with w < 0 cut out. 151 // If w = 0, (x′, y′, z′) = (x ⋅ n, y ⋅ n, z ⋅ n) 152 // We implement this by intersecting with the image plane, i.e. the last row of the column-major matrix. 153 // To avoid problems with w close to 0, we use w = epsilon as the near plane by subtracting epsilon from matrix.m44(). 154 const float epsilon = 1e-3; 155 Vector<FloatPoint3D, 4> quad = toVector<FloatPoint3D, 4>(boundsRect); 156 Vector<FloatPoint3D, 4> polygon = intersect(quad, LayerClipPlane(FloatPoint3D(matrix.m14(), matrix.m24(), matrix.m34()), matrix.m44() - epsilon)); 157 158 // Compute the clipped texture coordinates. 159 if (polygon != quad) { 160 for (size_t i = 0; i < polygon.size(); ++i) { 161 FloatPoint3D& p = polygon[i]; 162 m_textureCoordinates.append(FloatPoint(p.x() / boundsRect.width() + 0.5f, p.y() / boundsRect.height() + 0.5f)); 163 } 164 } 165 166 // If w > 0, (x′, y′, z′) = (x/w, y/w, z/w) 167 for (size_t i = 0; i < polygon.size(); ++i) { 168 float w; 169 FloatPoint3D p = multVecMatrix(matrix, polygon[i], w); 170 if (w != 1) { 171 p.setX(p.x() / w); 172 p.setY(p.y() / w); 173 p.setZ(p.z() / w); 174 } 175 176 FloatPoint3D q = projectionMatrix.mapPoint(p); 177 m_transformedBounds.append(FloatPoint(q.x(), q.y())); 178 m_ws.append(w); 179 } 180 181 m_centerW = matrix.m44(); 182 } else 183 m_transformedBounds = toVector<FloatPoint, 4>(m_drawTransform.mapQuad(boundsRect)); 184 185 m_boundingBox = WebCore::boundingBox(m_transformedBounds); 186} 187 188const Vector<FloatPoint>& LayerCompositingThread::textureCoordinates(TextureCoordinateOrientation orientation) const 189{ 190 if (m_textureCoordinates.size()) { 191 if (orientation == UpsideDown) { 192 static Vector<FloatPoint> upsideDownCoordinates; 193 upsideDownCoordinates = m_textureCoordinates; 194 for (size_t i = 0; i < upsideDownCoordinates.size(); ++i) 195 upsideDownCoordinates[i].setY(1 - upsideDownCoordinates[i].y()); 196 return upsideDownCoordinates; 197 } 198 199 return m_textureCoordinates; 200 } 201 202 if (orientation == UpsideDown) { 203 static FloatPoint data[4] = { FloatPoint(0, 1), FloatPoint(1, 1), FloatPoint(1, 0), FloatPoint(0, 0) }; 204 static Vector<FloatPoint>* upsideDownCoordinates = 0; 205 if (!upsideDownCoordinates) { 206 upsideDownCoordinates = new Vector<FloatPoint>(); 207 upsideDownCoordinates->append(data, 4); 208 } 209 return *upsideDownCoordinates; 210 } 211 212 static FloatPoint data[4] = { FloatPoint(0, 0), FloatPoint(1, 0), FloatPoint(1, 1), FloatPoint(0, 1) }; 213 static Vector<FloatPoint>* coordinates = 0; 214 if (!coordinates) { 215 coordinates = new Vector<FloatPoint>(); 216 coordinates->append(data, 4); 217 } 218 return *coordinates; 219} 220 221FloatQuad LayerCompositingThread::transformedHolePunchRect() const 222{ 223 FloatRect holePunchRect(m_holePunchRect); 224 holePunchRect.moveBy(-origin()); 225 return m_drawTransform.mapQuad(holePunchRect); 226} 227 228void LayerCompositingThread::drawTextures(const GLES2Program& program, double scale, const FloatRect& visibleRect, const FloatRect& clipRect) 229{ 230 if (m_pluginView) { 231 if (m_isVisible) { 232 // The layer contains Flash, video, or other plugin contents. 233 m_pluginBuffer = m_pluginView->lockFrontBufferForRead(); 234 235 if (!m_pluginBuffer) 236 return; 237 238 if (!BlackBerry::Platform::Graphics::lockAndBindBufferGLTexture(m_pluginBuffer, GL_TEXTURE_2D)) { 239 m_pluginView->unlockFrontBuffer(); 240 return; 241 } 242 243 m_layerRenderer->addLayerToReleaseTextureResourcesList(this); 244 245 glEnable(GL_BLEND); 246 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 247 glUniform1f(program.opacityLocation(), drawOpacity()); 248 glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, m_transformedBounds.data()); 249 glVertexAttribPointer(program.texCoordLocation(), 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates().data()); 250 glDrawArrays(GL_TRIANGLE_FAN, 0, m_transformedBounds.size()); 251 } 252 return; 253 } 254#if ENABLE(VIDEO) 255 if (m_mediaPlayer) { 256 if (m_isVisible) { 257 IntRect paintRect; 258 if (m_layerRenderer->client()->shouldChildWindowsUseDocumentCoordinates()) { 259 // We need to specify the media player location in contents coordinates. The 'visibleRect' 260 // specifies the content region covered by our viewport. So we transform from our 261 // normalized device coordinates [-1, 1] to the 'visibleRect'. 262 float vrw2 = visibleRect.width() / 2.0; 263 float vrh2 = visibleRect.height() / 2.0; 264 FloatPoint p(m_transformedBounds[0].x() * vrw2 + vrw2 + visibleRect.x(), 265 -m_transformedBounds[0].y() * vrh2 + vrh2 + visibleRect.y()); 266 paintRect = IntRect(roundedIntPoint(p), m_bounds); 267 } else 268 paintRect = m_layerRenderer->toWindowCoordinates(m_boundingBox); 269 270 m_mediaPlayer->paint(0, paintRect); 271 MediaPlayerPrivate* mpp = static_cast<MediaPlayerPrivate*>(m_mediaPlayer->platformMedia().media.qnxMediaPlayer); 272 mpp->drawBufferingAnimation(m_drawTransform, program); 273 } 274 return; 275 } 276#endif 277 278 if (m_client) 279 m_client->drawTextures(this, program, scale, clipRect); 280} 281 282void LayerCompositingThread::drawSurface(const GLES2Program& program, const TransformationMatrix& drawTransform, LayerCompositingThread* mask) 283{ 284 using namespace BlackBerry::Platform::Graphics; 285 286 if (m_layerRenderer->layerAlreadyOnSurface(this)) { 287 LayerTexture* surfaceTexture = layerRendererSurface()->texture(); 288 if (!surfaceTexture) { 289 ASSERT_NOT_REACHED(); 290 return; 291 } 292 textureCacheCompositingThread()->textureAccessed(layerRendererSurface()->texture()); 293 GLuint surfaceTexID = surfaceTexture->platformTexture(); 294 295 if (!surfaceTexID) { 296 ASSERT_NOT_REACHED(); 297 return; 298 } 299 300 if (mask) { 301 if (LayerTexture* maskTexture = mask->contentsTexture()) { 302 GLuint maskTexID = maskTexture->platformTexture(); 303 304 glActiveTexture(GL_TEXTURE1); 305 glBindTexture(GL_TEXTURE_2D, maskTexID); 306 glActiveTexture(GL_TEXTURE0); 307 } 308 } 309 310 glEnable(GL_BLEND); 311 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 312 glBindTexture(GL_TEXTURE_2D, surfaceTexID); 313 314 FloatQuad surfaceQuad = drawTransform.mapQuad(FloatRect(-origin(), bounds())); 315 glUniform1f(program.opacityLocation(), layerRendererSurface()->drawOpacity()); 316 glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, &surfaceQuad); 317 318 static float texcoords[4 * 2] = { 0, 0, 1, 0, 1, 1, 0, 1 }; 319 glVertexAttribPointer(program.texCoordLocation(), 2, GL_FLOAT, GL_FALSE, 0, texcoords); 320 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 321 } 322} 323 324void LayerCompositingThread::releaseTextureResources() 325{ 326 if (m_pluginView && m_pluginBuffer) { 327 BlackBerry::Platform::Graphics::releaseBufferGLTexture(m_pluginBuffer); 328 m_pluginBuffer = 0; 329 m_pluginView->unlockFrontBuffer(); 330 } 331} 332 333void LayerCompositingThread::setPluginView(PluginView* pluginView) 334{ 335 if (!isCompositingThread()) { 336 dispatchSyncCompositingMessage(BlackBerry::Platform::createMethodCallMessage( 337 &LayerCompositingThread::setPluginView, 338 this, 339 pluginView)); 340 return; 341 } 342 343 m_pluginView = pluginView; 344} 345 346#if ENABLE(VIDEO) 347void LayerCompositingThread::setMediaPlayer(MediaPlayer* mediaPlayer) 348{ 349 if (!isCompositingThread()) { 350 dispatchSyncCompositingMessage(BlackBerry::Platform::createMethodCallMessage( 351 &LayerCompositingThread::setMediaPlayer, 352 this, 353 mediaPlayer)); 354 return; 355 } 356 357 m_mediaPlayer = mediaPlayer; 358} 359#endif 360 361void LayerCompositingThread::removeSublayer(LayerCompositingThread* sublayer) 362{ 363 ASSERT(isCompositingThread()); 364 365 int foundIndex = indexOfSublayer(sublayer); 366 if (foundIndex == -1) 367 return; 368 369 sublayer->setSuperlayer(0); 370 m_sublayers.remove(foundIndex); 371} 372 373int LayerCompositingThread::indexOfSublayer(const LayerCompositingThread* reference) 374{ 375 for (size_t i = 0; i < m_sublayers.size(); i++) { 376 if (m_sublayers[i] == reference) 377 return i; 378 } 379 return -1; 380} 381 382const LayerCompositingThread* LayerCompositingThread::rootLayer() const 383{ 384 const LayerCompositingThread* layer = this; 385 for (LayerCompositingThread* superlayer = layer->superlayer(); superlayer; layer = superlayer, superlayer = superlayer->superlayer()) { } 386 return layer; 387} 388 389void LayerCompositingThread::addSublayer(LayerCompositingThread* layer) 390{ 391 layer->removeFromSuperlayer(); 392 layer->setSuperlayer(this); 393 m_sublayers.append(layer); 394} 395 396void LayerCompositingThread::removeFromSuperlayer() 397{ 398 if (m_superlayer) 399 m_superlayer->removeSublayer(this); 400} 401 402void LayerCompositingThread::setSublayers(const Vector<RefPtr<LayerCompositingThread> >& sublayers) 403{ 404 if (sublayers == m_sublayers) 405 return; 406 407 while (m_sublayers.size()) { 408 RefPtr<LayerCompositingThread> layer = m_sublayers[0].get(); 409 ASSERT(layer->superlayer()); 410 layer->removeFromSuperlayer(); 411 } 412 413 m_sublayers.clear(); 414 415 size_t listSize = sublayers.size(); 416 for (size_t i = 0; i < listSize; i++) { 417 RefPtr<LayerCompositingThread> sublayer = sublayers[i]; 418 sublayer->removeFromSuperlayer(); 419 sublayer->setSuperlayer(this); 420 m_sublayers.insert(i, sublayer); 421 } 422} 423 424void LayerCompositingThread::updateTextureContentsIfNeeded() 425{ 426 if (m_client) 427 m_client->uploadTexturesIfNeeded(this); 428} 429 430LayerTexture* LayerCompositingThread::contentsTexture() 431{ 432 if (m_client) 433 return m_client->contentsTexture(this); 434 435 return 0; 436} 437 438void LayerCompositingThread::setVisible(bool visible) 439{ 440 if (visible == m_visible) 441 return; 442 443 m_visible = visible; 444 445 if (m_client) 446 m_client->layerVisibilityChanged(this, visible); 447} 448 449void LayerCompositingThread::setNeedsCommit() 450{ 451 if (m_layerRenderer) 452 m_layerRenderer->setNeedsCommit(); 453} 454 455void LayerCompositingThread::scheduleCommit() 456{ 457 if (!m_client) 458 return; 459 460 if (!isWebKitThread()) { 461 if (m_commitScheduled) 462 return; 463 464 m_commitScheduled = true; 465 466 dispatchWebKitMessage(BlackBerry::Platform::createMethodCallMessage(&LayerCompositingThread::scheduleCommit, this)); 467 return; 468 } 469 470 m_commitScheduled = false; 471 472 m_client->scheduleCommit(); 473} 474 475void LayerCompositingThread::commitPendingTextureUploads() 476{ 477 if (m_client) 478 m_client->commitPendingTextureUploads(this); 479} 480 481bool LayerCompositingThread::updateAnimations(double currentTime) 482{ 483 // The commit mechanism always overwrites our state with state from the 484 // WebKit thread. This means we have to restore the last animated value for 485 // suspended animations. 486 for (size_t i = 0; i < m_suspendedAnimations.size(); ++i) { 487 LayerAnimation* animation = m_suspendedAnimations[i].get(); 488 // From looking at the WebCore code, it appears that when the animation 489 // is paused, the timeOffset is modified so it will be an appropriate 490 // elapsedTime. 491 double elapsedTime = animation->timeOffset(); 492 animation->apply(this, elapsedTime); 493 } 494 495 bool allAnimationsFinished = true; 496 for (size_t i = 0; i < m_runningAnimations.size(); ++i) { 497 LayerAnimation* animation = m_runningAnimations[i].get(); 498 double elapsedTime = (m_suspendTime ? m_suspendTime : currentTime) - animation->startTime() + animation->timeOffset(); 499 animation->apply(this, elapsedTime); 500 if (!animation->finished()) 501 allAnimationsFinished = false; 502 } 503 504 // If there are any overrides, apply them 505 if (m_override) { 506 if (m_override->isPositionSet()) 507 m_position = m_override->position(); 508 if (m_override->isAnchorPointSet()) 509 m_anchorPoint = m_override->anchorPoint(); 510 if (m_override->isBoundsSet()) 511 m_bounds = m_override->bounds(); 512 if (m_override->isTransformSet()) 513 m_transform = m_override->transform(); 514 if (m_override->isOpacitySet()) 515 m_opacity = m_override->opacity(); 516 517 for (size_t i = 0; i < m_override->animations().size(); ++i) { 518 LayerAnimation* animation = m_override->animations()[i].get(); 519 double elapsedTime = (m_suspendTime ? m_suspendTime : currentTime) - animation->startTime() + animation->timeOffset(); 520 animation->apply(this, elapsedTime); 521 if (!animation->finished()) 522 allAnimationsFinished = false; 523 } 524 } 525 526 return !allAnimationsFinished; 527} 528 529bool LayerCompositingThread::hasVisibleHolePunchRect() const 530{ 531 if (m_pluginView && !m_isVisible) 532 return false; 533 534#if ENABLE(VIDEO) 535 if (m_mediaPlayer && !m_isVisible) 536 return false; 537#endif 538 539 return hasHolePunchRect(); 540} 541 542void LayerCompositingThread::createLayerRendererSurface() 543{ 544 ASSERT(!m_layerRendererSurface); 545 m_layerRendererSurface = adoptPtr(new LayerRendererSurface(m_layerRenderer, this)); 546} 547 548void LayerCompositingThread::removeAnimation(const String& name) 549{ 550 for (size_t i = 0; i < m_runningAnimations.size(); ++i) { 551 if (m_runningAnimations[i]->name() == name) { 552 m_runningAnimations.remove(i); 553 return; 554 } 555 } 556} 557 558LayerOverride* LayerCompositingThread::override() 559{ 560 if (!m_override) 561 m_override = LayerOverride::create(); 562 return m_override.get(); 563} 564 565void LayerCompositingThread::clearOverride() 566{ 567 m_override.clear(); 568} 569 570} 571 572#endif // USE(ACCELERATED_COMPOSITING) 573