WebPageCompositor.cpp [plain text]
#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); }
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); 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;
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;
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;
}
}
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)
{
if (!m_layerRenderer)
return;
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)
{
if (!m_rootLayer && !m_overlayLayer && !m_compositingThreadOverlayLayer)
return false;
prepareFrame(currentTime());
if (!m_layerRenderer)
return false;
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());
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());
if (fixedElementRect.isEmpty() || fixedElementRect.intersects(fixedRect)) fixedElementRect.unite(fixedRect);
else if (fixedRect.y() < fixedElementRect.y()) 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);
tmp->setChildWindowPlacement(WindowCoordinates);
d = tmp.get();
d->ref();
webKitThreadMessageClient()->dispatchMessage(createMethodCallMessage(&WebPagePrivate::setCompositor, d->page(), tmp));
}
WebPageCompositor::~WebPageCompositor()
{
using namespace BlackBerry::Platform;
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()
{
notImplemented();
}
} }
#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()
{
}
} }
#endif // USE(ACCELERATED_COMPOSITING)