diff options
Diffstat (limited to 'Source/WebKit2/UIProcess/qt/LayerTreeHostProxyQt.cpp')
-rw-r--r-- | Source/WebKit2/UIProcess/qt/LayerTreeHostProxyQt.cpp | 635 |
1 files changed, 635 insertions, 0 deletions
diff --git a/Source/WebKit2/UIProcess/qt/LayerTreeHostProxyQt.cpp b/Source/WebKit2/UIProcess/qt/LayerTreeHostProxyQt.cpp new file mode 100644 index 000000000..a1dd272a7 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/LayerTreeHostProxyQt.cpp @@ -0,0 +1,635 @@ +/* + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) +#include "LayerTreeHostProxy.h" + +#include "LayerTreeHostMessages.h" +#include "MainThread.h" +#include "MessageID.h" +#include "ShareableBitmap.h" +#include "TextureMapperGL.h" +#include "UpdateInfo.h" +#include "WebCoreArgumentCoders.h" +#include "WebLayerTreeInfo.h" +#include "WebPageProxy.h" +#include "WebProcessProxy.h" +#include "texmap/GraphicsLayerTextureMapper.h" +#include "texmap/TextureMapper.h" +#include "texmap/TextureMapperNode.h" +#include <QDateTime> +#include <cairo/OpenGLShims.h> + +namespace WebKit { + +class LayerTreeMessageToRenderer { +public: + enum Type { + DeleteLayer, + CreateTile, + RemoveTile, + UpdateTile, + CreateImage, + DestroyImage, + SyncLayerParameters, + FlushLayerChanges, + SetRootLayer + }; + virtual ~LayerTreeMessageToRenderer() { } + virtual Type type() const = 0; +}; + +template<class MessageData, LayerTreeMessageToRenderer::Type messageType> +class LayerTreeMessageToRendererWithData : public LayerTreeMessageToRenderer { +public: + virtual Type type() const { return messageType; } + + static PassOwnPtr<LayerTreeMessageToRenderer> create(const MessageData& data = MessageData()) + { + return adoptPtr(new LayerTreeMessageToRendererWithData(data)); + } + + const MessageData& data() const + { + return m_data; + } + +private: + LayerTreeMessageToRendererWithData(const MessageData& data) + : m_data(data) + { + } + + MessageData m_data; +}; + + +namespace { +struct CreateTileMessageData { + WebLayerID layerID; + int remoteTileID; + float scale; +}; + +struct UpdateTileMessageData { + WebLayerID layerID; + int remoteTileID; + IntRect sourceRect; + IntRect targetRect; + QImage image; +}; + +struct RemoveTileMessageData { + WebLayerID layerID; + int remoteTileID; +}; + +struct CreateImageMessageData { + int64_t imageID; + QImage image; +}; + +struct DestroyImageMessageData { + int64_t imageID; +}; + +struct SyncLayerParametersMessageData { + WebLayerInfo layerInfo; +}; + +struct EmptyMessageData { }; +struct DeleteLayerMessageData { + WebLayerID layerID; +}; +struct SetRootLayerMessageData { + WebLayerID layerID; +}; + +class CreateTileMessage + : public LayerTreeMessageToRendererWithData<CreateTileMessageData, LayerTreeMessageToRenderer::CreateTile> { }; +class UpdateTileMessage + : public LayerTreeMessageToRendererWithData<UpdateTileMessageData, LayerTreeMessageToRenderer::UpdateTile> { }; +class RemoveTileMessage + : public LayerTreeMessageToRendererWithData<RemoveTileMessageData, LayerTreeMessageToRenderer::RemoveTile> { }; +class CreateImageMessage + : public LayerTreeMessageToRendererWithData<CreateImageMessageData, LayerTreeMessageToRenderer::CreateImage> { }; +class DestroyImageMessage + : public LayerTreeMessageToRendererWithData<DestroyImageMessageData, LayerTreeMessageToRenderer::DestroyImage> { }; +class FlushLayerChangesMessage + : public LayerTreeMessageToRendererWithData<EmptyMessageData, LayerTreeMessageToRenderer::FlushLayerChanges> { }; +class SyncLayerParametersMessage + : public LayerTreeMessageToRendererWithData<SyncLayerParametersMessageData, LayerTreeMessageToRenderer::SyncLayerParameters> { }; +class DeleteLayerMessage + : public LayerTreeMessageToRendererWithData<DeleteLayerMessageData, LayerTreeMessageToRenderer::DeleteLayer> { }; +class SetRootLayerMessage + : public LayerTreeMessageToRendererWithData<SetRootLayerMessageData, LayerTreeMessageToRenderer::SetRootLayer> { }; +} + +PassOwnPtr<GraphicsLayer> LayerTreeHostProxy::createLayer(WebLayerID layerID) +{ + GraphicsLayer* newLayer = new GraphicsLayerTextureMapper(this); + TextureMapperNode* node = toTextureMapperNode(newLayer); + node->setID(layerID); + node->setTileOwnership(TextureMapperNode::ExternallyManagedTiles); + return adoptPtr(newLayer); +} + +LayerTreeHostProxy::LayerTreeHostProxy(DrawingAreaProxy* drawingAreaProxy) + : m_animationTimer(RunLoop::main(), this, &LayerTreeHostProxy::updateViewport) + , m_drawingAreaProxy(drawingAreaProxy) + , m_viewportUpdateTimer(this, &LayerTreeHostProxy::didFireViewportUpdateTimer) + , m_rootLayerID(0) +{ +} + +LayerTreeHostProxy::~LayerTreeHostProxy() +{ +} + +// This function needs to be reentrant. +void LayerTreeHostProxy::paintToCurrentGLContext(const TransformationMatrix& matrix, float opacity) +{ + if (!m_textureMapper) + m_textureMapper = TextureMapperGL::create(); + + syncRemoteContent(); + GraphicsLayer* currentRootLayer = rootLayer(); + if (!currentRootLayer) + return; + + TextureMapperNode* node = toTextureMapperNode(currentRootLayer); + + if (!node) + return; + + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + IntRect viewportRect(viewport[0], viewport[1], viewport[2], viewport[3]); + m_textureMapper->setViewportSize(IntSize(viewport[2], viewport[3])); + node->setTextureMapper(m_textureMapper.get()); + m_textureMapper->beginPainting(); + m_textureMapper->bindSurface(0); + + if (currentRootLayer->opacity() != opacity || currentRootLayer->transform() != matrix) { + currentRootLayer->setOpacity(opacity); + currentRootLayer->setTransform(matrix); + currentRootLayer->syncCompositingStateForThisLayerOnly(); + } + + TextureMapperNode::NodeRectMap nodeVisualContentsRectMap; + if (node->collectVisibleContentsRects(nodeVisualContentsRectMap, viewportRect)) { + TextureMapperNode::NodeRectMap::iterator endIterator = nodeVisualContentsRectMap.end(); + for (TextureMapperNode::NodeRectMap::iterator it = nodeVisualContentsRectMap.begin(); it != endIterator; ++it) { + WebLayerID layerID = it->first->id(); + // avoid updating non-synced root layer + if (!layerID) + continue; + IntRect visibleRect = IntRect(it->second); + setVisibleContentsRectForLayer(layerID, visibleRect); + } + } + node->paint(); + + m_textureMapper->endPainting(); + + if (node->descendantsOrSelfHaveRunningAnimations()) { + node->syncAnimationsRecursively(); + m_viewportUpdateTimer.startOneShot(0); + } +} + +void LayerTreeHostProxy::didFireViewportUpdateTimer(Timer<LayerTreeHostProxy>*) +{ + updateViewport(); +} + +void LayerTreeHostProxy::updateViewport() +{ + m_drawingAreaProxy->updateViewport(); +} + +void LayerTreeHostProxy::setVisibleContentsRectForLayer(WebLayerID layerID, const IntRect& rect) +{ + m_drawingAreaProxy->page()->process()->send(Messages::LayerTreeHost::SetVisibleContentRectForLayer(layerID, rect), m_drawingAreaProxy->page()->pageID()); +} + +int LayerTreeHostProxy::remoteTileIDToNodeTileID(int tileID) const +{ + HashMap<int, int>::const_iterator it = m_tileToNodeTile.find(tileID); + if (it == m_tileToNodeTile.end()) + return 0; + return it->second; +} + +void LayerTreeHostProxy::syncLayerParameters(const WebLayerInfo& layerInfo) +{ + WebLayerID id = layerInfo.id; + ensureLayer(id); + LayerMap::iterator it = m_layers.find(id); + GraphicsLayer* layer = it->second; + + layer->setName(layerInfo.name); + + layer->setReplicatedByLayer(layerByID(layerInfo.replica)); + layer->setMaskLayer(layerByID(layerInfo.mask)); + + layer->setPosition(layerInfo.pos); + layer->setSize(layerInfo.size); + layer->setTransform(layerInfo.transform); + layer->setAnchorPoint(layerInfo.anchorPoint); + layer->setChildrenTransform(layerInfo.childrenTransform); + layer->setBackfaceVisibility(layerInfo.backfaceVisible); + layer->setContentsOpaque(layerInfo.contentsOpaque); + layer->setContentsRect(layerInfo.contentsRect); + layer->setDrawsContent(layerInfo.drawsContent); + + if (layerInfo.imageIsUpdated) + assignImageToLayer(layer, layerInfo.imageBackingStoreID); + + // Never make the root layer clip. + layer->setMasksToBounds(layerInfo.isRootLayer ? false : layerInfo.masksToBounds); + layer->setOpacity(layerInfo.opacity); + layer->setPreserves3D(layerInfo.preserves3D); + Vector<GraphicsLayer*> children; + + for (size_t i = 0; i < layerInfo.children.size(); ++i) { + WebLayerID childID = layerInfo.children[i]; + GraphicsLayer* child = layerByID(childID); + if (!child) { + child = createLayer(childID).leakPtr(); + m_layers.add(childID, child); + } + children.append(child); + } + layer->setChildren(children); + + for (size_t i = 0; i < layerInfo.animations.size(); ++i) { + const WebKit::WebLayerAnimation anim = layerInfo.animations[i]; + + switch (anim.operation) { + case WebKit::WebLayerAnimation::AddAnimation: { + const IntSize boxSize = anim.boxSize; + layer->addAnimation(anim.keyframeList, boxSize, anim.animation.get(), anim.name, anim.startTime); + break; + } + case WebKit::WebLayerAnimation::RemoveAnimation: + layer->removeAnimation(anim.name); + break; + case WebKit::WebLayerAnimation::PauseAnimation: + double offset = WTF::currentTime() - anim.startTime; + layer->pauseAnimation(anim.name, offset); + break; + } + } + + if (layerInfo.isRootLayer && m_rootLayerID != id) + setRootLayerID(id); +} + +void LayerTreeHostProxy::deleteLayer(WebLayerID layerID) +{ + GraphicsLayer* layer = layerByID(layerID); + if (!layer) + return; + + layer->removeFromParent(); + m_layers.remove(layerID); + delete layer; +} + + +void LayerTreeHostProxy::ensureLayer(WebLayerID id) +{ + // We have to leak the new layer's pointer and manage it ourselves, + // because OwnPtr is not copyable. + if (m_layers.find(id) == m_layers.end()) + m_layers.add(id, createLayer(id).leakPtr()); +} + +void LayerTreeHostProxy::setRootLayerID(WebLayerID layerID) +{ + if (layerID == m_rootLayerID) + return; + + m_rootLayerID = layerID; + + m_rootLayer->removeAllChildren(); + + if (!layerID) + return; + + GraphicsLayer* layer = layerByID(layerID); + if (!layer) + return; + + m_rootLayer->addChild(layer); +} + +void LayerTreeHostProxy::createTile(WebLayerID layerID, int tileID, float scale) +{ + ensureLayer(layerID); + TextureMapperNode* node = toTextureMapperNode(layerByID(layerID)); + + int nodeTileID = node->createContentsTile(scale); + m_tileToNodeTile.add(tileID, nodeTileID); +} + +void LayerTreeHostProxy::removeTile(WebLayerID layerID, int tileID) +{ + TextureMapperNode* node = toTextureMapperNode(layerByID(layerID)); + if (!node) + return; + + int nodeTileID = remoteTileIDToNodeTileID(tileID); + if (!nodeTileID) + return; + + node->removeContentsTile(nodeTileID); + m_tileToNodeTile.remove(tileID); +} + +void LayerTreeHostProxy::updateTile(WebLayerID layerID, int tileID, const IntRect& sourceRect, const IntRect& targetRect, const QImage& image) +{ + ensureLayer(layerID); + TextureMapperNode* node = toTextureMapperNode(layerByID(layerID)); + if (!node) + return; + + int nodeTileID = remoteTileIDToNodeTileID(tileID); + if (!nodeTileID) + return; + + QImage imageRef(image); + node->setTextureMapper(m_textureMapper.get()); + node->setContentsTileBackBuffer(nodeTileID, sourceRect, targetRect, imageRef.bits(), BitmapTexture::BGRAFormat); +} + +void LayerTreeHostProxy::createImage(int64_t imageID, const QImage& image) +{ + TiledImage tiledImage; + static const int TileDimension = 1024; + bool imageHasAlpha = image.hasAlphaChannel(); + IntRect imageRect(0, 0, image.width(), image.height()); + for (int y = 0; y < image.height(); y += TileDimension) { + for (int x = 0; x < image.width(); x += TileDimension) { + QImage subImage; + IntRect rect(x, y, TileDimension, TileDimension); + rect.intersect(imageRect); + if (QSize(rect.size()) == image.size()) + subImage = image; + else + subImage = image.copy(rect); + RefPtr<BitmapTexture> texture = m_textureMapper->createTexture(); + texture->reset(rect.size(), !imageHasAlpha); + texture->updateContents(imageHasAlpha ? BitmapTexture::BGRAFormat : BitmapTexture::BGRFormat, IntRect(IntPoint::zero(), rect.size()), subImage.bits()); + tiledImage.add(rect.location(), texture); + } + } + + m_directlyCompositedImages.remove(imageID); + m_directlyCompositedImages.add(imageID, tiledImage); +} + +void LayerTreeHostProxy::destroyImage(int64_t imageID) +{ + m_directlyCompositedImages.remove(imageID); +} + +void LayerTreeHostProxy::assignImageToLayer(GraphicsLayer* layer, int64_t imageID) +{ + TextureMapperNode* node = toTextureMapperNode(layer); + if (!node) + return; + + if (!imageID) { + node->clearAllDirectlyCompositedImageTiles(); + return; + } + + FloatSize size(layer->size()); + FloatRect contentsRect(layer->contentsRect()); + float horizontalFactor = contentsRect.width() / size.width(); + float verticalFactor = contentsRect.height() / size.height(); + HashMap<int64_t, TiledImage>::iterator it = m_directlyCompositedImages.find(imageID); + if (it == m_directlyCompositedImages.end()) + return; + + TiledImage::iterator endTileIterator = it->second.end(); + for (TiledImage::iterator tileIt = it->second.begin(); tileIt != endTileIterator; ++tileIt) { + FloatRect sourceRect(FloatPoint(tileIt->first), FloatSize(tileIt->second->size())); + FloatRect targetRect(sourceRect.x() * horizontalFactor + contentsRect.x(), + sourceRect.y() * verticalFactor + contentsRect.y(), + sourceRect.width() * horizontalFactor, + sourceRect.height() * verticalFactor); + int newTileID = node->createContentsTile(1.0); + node->setTileBackBufferTextureForDirectlyCompositedImage(newTileID, IntRect(sourceRect), targetRect, tileIt->second.get()); + } +} + +void LayerTreeHostProxy::flushLayerChanges() +{ + m_rootLayer->syncCompositingState(FloatRect()); +} + +void LayerTreeHostProxy::ensureRootLayer() +{ + if (m_rootLayer) + return; + m_rootLayer = createLayer(InvalidWebLayerID); + m_rootLayer->setMasksToBounds(false); + m_rootLayer->setDrawsContent(false); + m_rootLayer->setAnchorPoint(FloatPoint3D(0, 0, 0)); + + // The root layer should not have zero size, or it would be optimized out. + m_rootLayer->setSize(FloatSize(1.0, 1.0)); + m_textureMapper = TextureMapperGL::create(); + toTextureMapperNode(m_rootLayer.get())->setTextureMapper(m_textureMapper.get()); +} + +void LayerTreeHostProxy::syncRemoteContent() +{ + // We enqueue messages and execute them during paint, as they require an active GL context. + ensureRootLayer(); + + while (OwnPtr<LayerTreeMessageToRenderer> nextMessage = m_messagesToRenderer.tryGetMessage()) { + switch (nextMessage->type()) { + case LayerTreeMessageToRenderer::SetRootLayer: { + const SetRootLayerMessageData& data = static_cast<SetRootLayerMessage*>(nextMessage.get())->data(); + setRootLayerID(data.layerID); + break; + } + + case LayerTreeMessageToRenderer::DeleteLayer: { + const DeleteLayerMessageData& data = static_cast<DeleteLayerMessage*>(nextMessage.get())->data(); + deleteLayer(data.layerID); + break; + } + + case LayerTreeMessageToRenderer::SyncLayerParameters: { + const SyncLayerParametersMessageData& data = static_cast<SyncLayerParametersMessage*>(nextMessage.get())->data(); + syncLayerParameters(data.layerInfo); + break; + } + + case LayerTreeMessageToRenderer::CreateTile: { + const CreateTileMessageData& data = static_cast<CreateTileMessage*>(nextMessage.get())->data(); + createTile(data.layerID, data.remoteTileID, data.scale); + break; + } + + case LayerTreeMessageToRenderer::RemoveTile: { + const RemoveTileMessageData& data = static_cast<RemoveTileMessage*>(nextMessage.get())->data(); + removeTile(data.layerID, data.remoteTileID); + break; + } + + case LayerTreeMessageToRenderer::UpdateTile: { + const UpdateTileMessageData& data = static_cast<UpdateTileMessage*>(nextMessage.get())->data(); + updateTile(data.layerID, data.remoteTileID, data.sourceRect, data.targetRect, data.image); + break; + } + + case LayerTreeMessageToRenderer::CreateImage: { + const CreateImageMessageData& data = static_cast<CreateImageMessage*>(nextMessage.get())->data(); + createImage(data.imageID, data.image); + break; + } + + case LayerTreeMessageToRenderer::DestroyImage: { + const CreateImageMessageData& data = static_cast<CreateImageMessage*>(nextMessage.get())->data(); + destroyImage(data.imageID); + break; + } + + case LayerTreeMessageToRenderer::FlushLayerChanges: + flushLayerChanges(); + break; + } + } +} + +void LayerTreeHostProxy::pushUpdateToQueue(PassOwnPtr<LayerTreeMessageToRenderer> message) +{ + m_messagesToRenderer.append(message); + updateViewport(); +} + +void LayerTreeHostProxy::createTileForLayer(int layerID, int tileID, const WebKit::UpdateInfo& updateInfo) +{ + CreateTileMessageData data; + data.layerID = layerID; + data.remoteTileID = tileID; + data.scale = updateInfo.updateScaleFactor; + pushUpdateToQueue(CreateTileMessage::create(data)); + updateTileForLayer(layerID, tileID, updateInfo); +} + +void LayerTreeHostProxy::updateTileForLayer(int layerID, int tileID, const WebKit::UpdateInfo& updateInfo) +{ + UpdateTileMessageData data; + data.layerID = layerID; + data.remoteTileID = tileID; + RefPtr<ShareableBitmap> bitmap = ShareableBitmap::create(updateInfo.bitmapHandle); + data.image = bitmap->createQImage().copy(); + data.sourceRect = IntRect(IntPoint::zero(), updateInfo.updateRectBounds.size()); + data.targetRect = updateInfo.updateRectBounds; + pushUpdateToQueue(UpdateTileMessage::create(data)); +} + +void LayerTreeHostProxy::removeTileForLayer(int layerID, int tileID) +{ + RemoveTileMessageData data; + data.layerID = layerID; + data.remoteTileID = tileID; + pushUpdateToQueue(RemoveTileMessage::create(data)); +} + + +void LayerTreeHostProxy::deleteCompositingLayer(WebLayerID id) +{ + DeleteLayerMessageData data; + data.layerID = id; + pushUpdateToQueue(DeleteLayerMessage::create(data)); +} + +void LayerTreeHostProxy::setRootCompositingLayer(WebLayerID id) +{ + SetRootLayerMessageData data; + data.layerID = id; + pushUpdateToQueue(SetRootLayerMessage::create(data)); +} + +void LayerTreeHostProxy::syncCompositingLayerState(const WebLayerInfo& info) +{ + SyncLayerParametersMessageData data; + data.layerInfo = info; + pushUpdateToQueue(SyncLayerParametersMessage::create(data)); +} + +void LayerTreeHostProxy::didRenderFrame() +{ + m_drawingAreaProxy->page()->process()->send(Messages::LayerTreeHost::RenderNextFrame(), m_drawingAreaProxy->page()->pageID()); + pushUpdateToQueue(FlushLayerChangesMessage::create()); + updateViewport(); +} + +void LayerTreeHostProxy::createDirectlyCompositedImage(int64_t key, const WebKit::ShareableBitmap::Handle& handle) +{ + CreateImageMessageData data; + RefPtr<ShareableBitmap> bitmap = ShareableBitmap::create(handle); + data.imageID = key; + data.image = bitmap->createQImage().copy(); + pushUpdateToQueue(CreateImageMessage::create(data)); +} + +void LayerTreeHostProxy::destroyDirectlyCompositedImage(int64_t key) +{ + DestroyImageMessageData data; + data.imageID = key; + pushUpdateToQueue(DestroyImageMessage::create(data)); +} + +void LayerTreeHostProxy::setVisibleContentRectTrajectoryVector(const FloatPoint& trajectoryVector) +{ + m_drawingAreaProxy->page()->process()->send(Messages::LayerTreeHost::SetVisibleContentRectTrajectoryVector(trajectoryVector), m_drawingAreaProxy->page()->pageID()); +} + +void LayerTreeHostProxy::setVisibleContentsRectAndScale(const IntRect& rect, float scale) +{ + m_visibleContentsRect = rect; + m_contentsScale = scale; + m_drawingAreaProxy->page()->process()->send(Messages::LayerTreeHost::SetVisibleContentRectAndScale(rect, scale), m_drawingAreaProxy->page()->pageID()); +} + +void LayerTreeHostProxy::purgeGLResources() +{ + TextureMapperNode* node = toTextureMapperNode(rootLayer()); + + node->purgeNodeTexturesRecursive(); + m_directlyCompositedImages.clear(); + + m_textureMapper.clear(); + + m_drawingAreaProxy->page()->process()->send(Messages::LayerTreeHost::PurgeBackingStores(), m_drawingAreaProxy->page()->pageID()); +} + +} +#endif |