123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- /*
- * Copyright (C) 2010, 2011, 2012, 2013 Research In Motion Limited. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- #include "config.h"
- #include "WebPageCompositor.h"
- #if USE(ACCELERATED_COMPOSITING)
- #include "BackingStore_p.h"
- #include "LayerWebKitThread.h"
- #include "WebOverlay_p.h"
- #include "WebPageCompositorClient.h"
- #include "WebPageCompositor_p.h"
- #include "WebPage_p.h"
- #include <BlackBerryPlatformDebugMacros.h>
- #include <BlackBerryPlatformExecutableMessage.h>
- #include <BlackBerryPlatformMessage.h>
- #include <BlackBerryPlatformMessageClient.h>
- #include <BlackBerryPlatformViewportAccessor.h>
- #include <GenericTimerClient.h>
- #include <ThreadTimerClient.h>
- #include <wtf/CurrentTime.h>
- using namespace WebCore;
- namespace BlackBerry {
- namespace WebKit {
- WebPageCompositorPrivate::WebPageCompositorPrivate(WebPagePrivate* page, WebPageCompositorClient* client)
- : m_client(client)
- , m_webPage(page)
- , m_context(0)
- , m_drawsRootLayer(false)
- , m_childWindowPlacement(WebPageCompositor::DocumentCoordinates)
- {
- ASSERT(m_webPage);
- setOneShot(true); // one-shot animation client
- }
- WebPageCompositorPrivate::~WebPageCompositorPrivate()
- {
- detach();
- }
- void WebPageCompositorPrivate::detach()
- {
- if (m_webPage)
- Platform::AnimationFrameRateController::instance()->removeClient(this);
- m_webPage = 0;
- detachOverlays();
- }
- void WebPageCompositorPrivate::setPage(WebPagePrivate *p)
- {
- if (p == m_webPage)
- return;
- ASSERT(p);
- ASSERT(m_webPage); // if this is null, we have a bug and we need to re-add.
- m_webPage = p;
- attachOverlays();
- }
- void WebPageCompositorPrivate::attachOverlays(LayerCompositingThread* overlayRoot, WebPagePrivate* page)
- {
- if (!overlayRoot)
- return;
- const Vector<RefPtr<LayerCompositingThread> >& overlays = overlayRoot->sublayers();
- for (size_t i = 0; i < overlays.size(); ++i) {
- LayerCompositingThread* overlay = overlays[i].get();
- if (LayerCompositingThreadClient* client = overlay->client()) {
- if (WebOverlayPrivate* webOverlay = static_cast<WebOverlayLayerCompositingThreadClient*>(client)->overlay())
- webOverlay->setPage(page);
- }
- }
- }
- void WebPageCompositorPrivate::setContext(Platform::Graphics::GLES2Context* context)
- {
- if (m_context == context)
- return;
- // LayerRenderer needs to clean up using the previous context.
- if (!context)
- m_layerRenderer.clear();
- m_context = context;
- }
- void WebPageCompositorPrivate::setRootLayer(LayerCompositingThread* rootLayer)
- {
- m_rootLayer = rootLayer;
- }
- void WebPageCompositorPrivate::setOverlayLayer(LayerCompositingThread* overlayLayer)
- {
- m_overlayLayer = overlayLayer;
- }
- void WebPageCompositorPrivate::prepareFrame(double animationTime)
- {
- if (!m_context)
- return;
- // The LayerRenderer is involved in rendering the BackingStore when
- // WebPageCompositor is used to render the web page. The presence of a
- // WebPageCompositorClient (m_client) indicates this is the case, so
- // create a LayerRenderer if there are layers or if there's a client.
- if (!m_rootLayer && !m_overlayLayer && !m_compositingThreadOverlayLayer && !m_client)
- return;
- if (!m_layerRenderer) {
- m_layerRenderer = LayerRenderer::create(this);
- if (!m_layerRenderer->hardwareCompositing()) {
- m_layerRenderer.clear();
- return;
- }
- }
- // Unfortunately, we have to use currentTime() because the animations are
- // started in that time coordinate system.
- animationTime = currentTime();
- if (m_rootLayer)
- m_layerRenderer->prepareFrame(animationTime, m_rootLayer.get());
- if (m_overlayLayer)
- m_layerRenderer->prepareFrame(animationTime, m_overlayLayer.get());
- if (m_compositingThreadOverlayLayer)
- m_layerRenderer->prepareFrame(animationTime, m_compositingThreadOverlayLayer.get());
- }
- void WebPageCompositorPrivate::render(const IntRect& targetRect, const IntRect& clipRect, const TransformationMatrix& transformIn, const FloatRect& documentSrcRect)
- {
- // m_layerRenderer should have been created in prepareFrame
- if (!m_layerRenderer)
- return;
- // It's not safe to call into the BackingStore if the compositor hasn't been set yet.
- // For thread safety, we have to do it using a round-trip to the WebKit thread, so the
- // embedder might call this before the round-trip to WebPagePrivate::setCompositor() is
- // done.
- if (!m_webPage || m_webPage->compositor() != this)
- return;
- m_layerRenderer->setViewport(targetRect, clipRect, documentSrcRect, m_layoutRect, m_documentRect.size());
- TransformationMatrix transform(transformIn);
- transform.translate(-m_documentRect.x(), -m_documentRect.y());
- if (!drawsRootLayer())
- m_webPage->m_backingStore->d->compositeContents(m_layerRenderer.get(), transform, documentSrcRect, !m_backgroundColor.hasAlpha());
- compositeLayers(transform);
- }
- void WebPageCompositorPrivate::compositeLayers(const TransformationMatrix& transform)
- {
- if (m_rootLayer)
- m_layerRenderer->compositeLayers(transform, m_rootLayer.get());
- if (m_overlayLayer)
- m_layerRenderer->compositeLayers(transform, m_overlayLayer.get());
- if (m_compositingThreadOverlayLayer)
- m_layerRenderer->compositeLayers(transform, m_compositingThreadOverlayLayer.get());
- m_lastCompositingResults = m_layerRenderer->lastRenderingResults();
- if (m_lastCompositingResults.needsAnimationFrame) {
- Platform::AnimationFrameRateController::instance()->addClient(this);
- m_webPage->updateDelegatedOverlays();
- }
- }
- bool WebPageCompositorPrivate::drawsRootLayer() const
- {
- return m_rootLayer && m_drawsRootLayer;
- }
- bool WebPageCompositorPrivate::drawLayers(const IntRect& dstRect, const FloatRect& contents)
- {
- // Is there anything to draw?
- if (!m_rootLayer && !m_overlayLayer && !m_compositingThreadOverlayLayer)
- return false;
- // prepareFrame creates the LayerRenderer if needed
- prepareFrame(currentTime());
- if (!m_layerRenderer)
- return false;
- // OpenGL window coordinates origin is at the lower left corner of the surface while
- // WebKit uses upper left as the origin of the window coordinate system. The passed in 'dstRect'
- // is in WebKit window coordinate system. Here we setup the viewport to the corresponding value
- // in OpenGL window coordinates.
- int viewportY = std::max(0, m_context->surfaceSize().height() - dstRect.maxY());
- IntRect viewport = IntRect(dstRect.x(), viewportY, dstRect.width(), dstRect.height());
- m_layerRenderer->setViewport(viewport, viewport, contents, m_layoutRect, m_documentRect.size());
- // WebKit uses row vectors which are multiplied by the matrix on the left (i.e. v*M)
- // Transformations are composed on the left so that M1.xform(M2) means M2*M1
- // We therefore start with our (othogonal) projection matrix, which will be applied
- // as the last transformation.
- TransformationMatrix transform = LayerRenderer::orthoMatrix(0, contents.width(), contents.height(), 0, -1000, 1000);
- transform.translate3d(-contents.x() - m_documentRect.x(), -contents.y() - m_documentRect.y(), 0);
- compositeLayers(transform);
- return true;
- }
- void WebPageCompositorPrivate::setBackgroundColor(const Color& color)
- {
- m_backgroundColor = color;
- }
- void WebPageCompositorPrivate::releaseLayerResources()
- {
- if (m_layerRenderer)
- m_layerRenderer->releaseLayerResources();
- }
- bool WebPageCompositorPrivate::shouldChildWindowsUseDocumentCoordinates()
- {
- return m_childWindowPlacement == WebPageCompositor::DocumentCoordinates;
- }
- void WebPageCompositorPrivate::animationFrameChanged()
- {
- BackingStore* backingStore = m_webPage->m_backingStore;
- if (!backingStore) {
- Platform::ViewportAccessor* viewportAccessor = m_webPage->client()->userInterfaceViewportAccessor();
- const Platform::IntRect dstRect = viewportAccessor->destinationSurfaceRect();
- const Platform::FloatRect srcRect = viewportAccessor->documentViewportRect();
- drawLayers(dstRect, srcRect);
- return;
- }
- if (!m_webPage->needsOneShotDrawingSynchronization())
- backingStore->blitVisibleContents();
- }
- void WebPageCompositorPrivate::compositorDestroyed()
- {
- if (m_client)
- m_client->compositorDestroyed();
- m_client = 0;
- }
- void WebPageCompositorPrivate::addOverlay(LayerCompositingThread* layer)
- {
- if (!m_compositingThreadOverlayLayer)
- m_compositingThreadOverlayLayer = LayerCompositingThread::create(LayerData::CustomLayer, 0);
- m_compositingThreadOverlayLayer->addSublayer(layer);
- }
- void WebPageCompositorPrivate::removeOverlay(LayerCompositingThread* layer)
- {
- if (layer->superlayer() != m_compositingThreadOverlayLayer)
- return;
- layer->removeFromSuperlayer();
- if (m_compositingThreadOverlayLayer && m_compositingThreadOverlayLayer->sublayers().isEmpty())
- m_compositingThreadOverlayLayer.clear();
- }
- void WebPageCompositorPrivate::findFixedElementRect(LayerCompositingThread* layer, WebCore::IntRect& fixedElementRect)
- {
- if ((layer->hasFixedContainer() || layer->isFixedPosition() || layer->hasFixedAncestorInDOMTree()) && layer->layerRenderer()) {
- IntRect fixedRect = layer->layerRenderer()->toPixelViewportCoordinates(layer->boundingBox());
- // FIXME: It's possible that the rects don't intersect now, but will be connected by a fixed rect found later.
- // We need to handle it as well.
- if (fixedElementRect.isEmpty() || fixedElementRect.intersects(fixedRect)) // Unite rects if they intersect each other.
- fixedElementRect.unite(fixedRect);
- else if (fixedRect.y() < fixedElementRect.y()) // Replace the fixedElementRect with fixedRect if fixedRect is above it (closer to top).
- fixedElementRect = fixedRect;
- }
- const Vector<RefPtr<LayerCompositingThread> >& sublayers = layer->sublayers();
- for (size_t i = 0; i < sublayers.size(); i++)
- findFixedElementRect(sublayers[i].get(), fixedElementRect);
- }
- WebPageCompositor::WebPageCompositor(WebPage* page, WebPageCompositorClient* client)
- {
- using namespace BlackBerry::Platform;
- RefPtr<WebPageCompositorPrivate> tmp = WebPageCompositorPrivate::create(page->d, client);
- // FIXME: For legacy reasons, the internal default is to use document coordinates.
- // Use window coordinates for new clients.
- tmp->setChildWindowPlacement(WindowCoordinates);
- // Keep one ref ourselves...
- d = tmp.get();
- d->ref();
- // ...And pass one ref to the web page.
- // This ensures that the compositor will be around for as long as it's
- // needed. Unfortunately RefPtr<T> is not public, so we have declare to
- // resort to manual refcounting.
- webKitThreadMessageClient()->dispatchMessage(createMethodCallMessage(&WebPagePrivate::setCompositor, d->page(), tmp));
- }
- WebPageCompositor::~WebPageCompositor()
- {
- using namespace BlackBerry::Platform;
- // If we're being destroyed before the page, send a message to disconnect us
- if (d->page())
- webKitThreadMessageClient()->dispatchMessage(createMethodCallMessage(&WebPagePrivate::setCompositor, d->page(), PassRefPtr<WebPageCompositorPrivate>(0)));
- d->compositorDestroyed();
- d->deref();
- }
- WebPageCompositorClient* WebPageCompositor::client() const
- {
- return d->client();
- }
- void WebPageCompositor::setChildWindowPlacement(ChildWindowPlacement placement)
- {
- d->setChildWindowPlacement(placement);
- }
- void WebPageCompositor::prepareFrame(Platform::Graphics::GLES2Context* context, double animationTime)
- {
- d->setContext(context);
- d->prepareFrame(animationTime);
- }
- void WebPageCompositor::render(Platform::Graphics::GLES2Context* context, const Platform::IntRect& targetRect, const Platform::IntRect& clipRect, const Platform::TransformationMatrix& transform, const Platform::FloatRect& documentSrcRect)
- {
- d->setContext(context);
- d->render(targetRect, clipRect, TransformationMatrix(reinterpret_cast<const TransformationMatrix&>(transform)), documentSrcRect);
- }
- void WebPageCompositor::cleanup(Platform::Graphics::GLES2Context*)
- {
- d->setContext(0);
- }
- void WebPageCompositor::contextLost()
- {
- // This method needs to delete the compositor in a way that not tries to
- // use any OpenGL calls (the context is gone, so we can't and don't need to
- // free any OpenGL resources.
- notImplemented();
- }
- } // namespace WebKit
- } // namespace BlackBerry
- #else // USE(ACCELERATED_COMPOSITING)
- namespace BlackBerry {
- namespace WebKit {
- WebPageCompositor::WebPageCompositor(WebPage*, WebPageCompositorClient*)
- : d(0)
- {
- }
- WebPageCompositor::~WebPageCompositor()
- {
- }
- WebPageCompositorClient* WebPageCompositor::client() const
- {
- return 0;
- }
- void WebPageCompositor::setChildWindowPlacement(ChildWindowPlacement)
- {
- }
- void WebPageCompositor::prepareFrame(Platform::Graphics::GLES2Context*, double)
- {
- }
- void WebPageCompositor::render(Platform::Graphics::GLES2Context*,
- const Platform::IntRect&,
- const Platform::IntRect&,
- const Platform::TransformationMatrix&,
- const Platform::FloatRect&)
- {
- }
- void WebPageCompositor::cleanup(Platform::Graphics::GLES2Context*)
- {
- }
- void WebPageCompositor::contextLost()
- {
- }
- } // namespace WebKit
- } // namespace BlackBerry
- #endif // USE(ACCELERATED_COMPOSITING)
|