diff options
Diffstat (limited to 'Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics')
11 files changed, 1991 insertions, 0 deletions
diff --git a/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/AreaAllocator.cpp b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/AreaAllocator.cpp new file mode 100644 index 000000000..a9ece1290 --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/AreaAllocator.cpp @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2012 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 "AreaAllocator.h" + +#if USE(COORDINATED_GRAPHICS) + +using namespace WebCore; + +namespace WebKit { + +AreaAllocator::AreaAllocator(const IntSize& size) + : m_size(size) + , m_minAlloc(1, 1) + , m_margin(0, 0) +{ +} + +AreaAllocator::~AreaAllocator() +{ +} + +void AreaAllocator::expand(const IntSize& size) +{ + m_size = m_size.expandedTo(size); +} + +void AreaAllocator::expandBy(const IntSize& size) +{ + m_size += size; +} + +void AreaAllocator::release(const IntRect&) +{ +} + +int AreaAllocator::overhead() const +{ + return 0; +} + +IntSize AreaAllocator::roundAllocation(const IntSize& size) const +{ + int width = size.width() + m_margin.width(); + int height = size.height() + m_margin.height(); + int extra = width % m_minAlloc.width(); + if (extra) + width += m_minAlloc.width() - extra; + extra = height % m_minAlloc.height(); + if (extra) + height += m_minAlloc.height() - extra; + + return IntSize(width, height); +} + +GeneralAreaAllocator::GeneralAreaAllocator(const IntSize& size) + : AreaAllocator(nextPowerOfTwo(size)) +{ + m_root = new Node(); + m_root->rect = IntRect(0, 0, m_size.width(), m_size.height()); + m_root->largestFree = m_size; + m_nodeCount = 1; + setMinimumAllocation(IntSize(8, 8)); +} + +GeneralAreaAllocator::~GeneralAreaAllocator() +{ + freeNode(m_root); +} + +void GeneralAreaAllocator::freeNode(Node* node) +{ + if (node) { + freeNode(node->left); + freeNode(node->right); + } + delete node; +} + +void GeneralAreaAllocator::expand(const IntSize& size) +{ + AreaAllocator::expand(nextPowerOfTwo(size)); + + if (m_root->rect.size() == m_size) + return; // No change. + + if (!m_root->left && m_root->largestFree.width() > 0) { + // No allocations have occurred, so just adjust the root size. + m_root->rect = IntRect(0, 0, m_size.width(), m_size.height()); + m_root->largestFree = m_size; + return; + } + + // Add extra nodes above the current root to expand the tree. + Node* oldRoot = m_root; + Split split; + if (m_size.width() >= m_size.height()) + split = SplitOnX; + else + split = SplitOnY; + + while (m_root->rect.size() != m_size) { + if (m_root->rect.width() == m_size.width()) + split = SplitOnY; + else if (m_root->rect.height() == m_size.height()) + split = SplitOnX; + Node* parent = new Node(); + Node* right = new Node(); + m_nodeCount += 2; + m_root->parent = parent; + parent->parent = nullptr; + parent->left = m_root; + parent->right = right; + parent->largestFree = m_root->rect.size(); + right->parent = parent; + right->left = nullptr; + right->right = nullptr; + right->largestFree = m_root->rect.size(); + if (split == SplitOnX) { + parent->rect = IntRect(m_root->rect.x(), m_root->rect.y(), + m_root->rect.width() * 2, m_root->rect.height()); + right->rect = IntRect(m_root->rect.x() + m_root->rect.width(), m_root->rect.y(), + m_root->rect.width(), m_root->rect.height()); + } else { + parent->rect = IntRect(m_root->rect.x(), m_root->rect.y(), + m_root->rect.width(), m_root->rect.height() * 2); + right->rect = IntRect(m_root->rect.x(), m_root->rect.y() + m_root->rect.width(), + m_root->rect.width(), m_root->rect.height()); + } + split = (split == SplitOnX ? SplitOnY : SplitOnX); + m_root = parent; + } + updateLargestFree(oldRoot); +} + +static inline bool fitsWithin(const IntSize& size1, const IntSize& size2) +{ + return size1.width() <= size2.width() && size1.height() <= size2.height(); +} + +IntRect GeneralAreaAllocator::allocate(const IntSize& size) +{ + IntSize rounded = roundAllocation(size); + rounded = nextPowerOfTwo(rounded); + if (rounded.width() <= 0 || rounded.width() > m_size.width() + || rounded.height() <= 0 || rounded.height() > m_size.height()) + return IntRect(); + + IntPoint point = allocateFromNode(rounded, m_root); + if (point.x() >= 0) + return IntRect(point, size); + return IntRect(); +} + +IntPoint GeneralAreaAllocator::allocateFromNode(const IntSize& size, Node* node) +{ + // Find the best node to insert into, which should be + // a node with the least amount of unused space that is + // big enough to contain the requested size. + while (node) { + // Go down a level and determine if the left or right + // sub-tree contains the best chance of allocation. + Node* left = node->left; + Node* right = node->right; + if (left && fitsWithin(size, left->largestFree)) { + if (right && fitsWithin(size, right->largestFree)) { + if (left->largestFree.width() < right->largestFree.width() + || left->largestFree.height() < right->largestFree.height()) { + // The largestFree values may be a little oversized, + // so try the left sub-tree and then the right sub-tree. + IntPoint point = allocateFromNode(size, left); + if (point.x() >= 0) + return point; + return allocateFromNode(size, right); + } + node = right; + } else + node = left; + } else if (right && fitsWithin(size, right->largestFree)) + node = right; + else if (left || right) { + // Neither sub-node has enough space to allocate from. + return IntPoint(-1, -1); + } else if (fitsWithin(size, node->largestFree)) { + // Do we need to split this node into smaller pieces? + Split split; + if (fitsWithin(IntSize(size.width() * 2, size.height() * 2), node->largestFree)) { + // Split in either direction: choose the inverse of + // the parent node's split direction to try to balance + // out the wasted space as further subdivisions happen. + if (node->parent + && node->parent->left->rect.x() == node->parent->right->rect.x()) + split = SplitOnX; + else if (node->parent) + split = SplitOnY; + else if (node->rect.width() >= node->rect.height()) + split = SplitOnX; + else + split = SplitOnY; + } else if (fitsWithin(IntSize(size.width() * 2, size.height()), node->largestFree)) { + // Split along the X direction. + split = SplitOnX; + } else if (fitsWithin(IntSize(size.width(), size.height() * 2), node->largestFree)) { + // Split along the Y direction. + split = SplitOnY; + } else { + // Cannot split further - allocate this node. + node->largestFree = IntSize(0, 0); + updateLargestFree(node); + return node->rect.location(); + } + + // Split the node, then go around again using the left sub-tree. + node = splitNode(node, split); + } else { + // Cannot possibly fit into this node. + break; + } + } + return IntPoint(-1, -1); +} + +GeneralAreaAllocator::Node* GeneralAreaAllocator::splitNode(Node* node, Split split) +{ + Node* left = new Node(); + left->parent = node; + Node* right = new Node(); + right->parent = node; + node->left = left; + node->right = right; + m_nodeCount += 2; + + if (split == SplitOnX) { + left->rect = IntRect(node->rect.x(), node->rect.y(), + node->rect.width() / 2, node->rect.height()); + right->rect = IntRect(left->rect.maxX(), node->rect.y(), + node->rect.width() / 2, node->rect.height()); + } else { + left->rect = IntRect(node->rect.x(), node->rect.y(), + node->rect.width(), node->rect.height() / 2); + right->rect = IntRect(node->rect.x(), left->rect.maxY(), + node->rect.width(), node->rect.height() / 2); + } + + left->largestFree = left->rect.size(); + right->largestFree = right->rect.size(); + node->largestFree = right->largestFree; + return left; +} + +void GeneralAreaAllocator::updateLargestFree(Node* node) +{ + while ((node = node->parent)) { + node->largestFree = IntSize( + std::max(node->left->largestFree.width(), node->right->largestFree.width()), + std::max(node->left->largestFree.height(), node->right->largestFree.height()) + ); + } +} + +void GeneralAreaAllocator::release(const IntRect& rect) +{ + // Locate the node that contains the allocated region. + Node* node = m_root; + IntPoint point = rect.location(); + while (node) { + if (node->left && node->left->rect.contains(point)) + node = node->left; + else if (node->right && node->right->rect.contains(point)) + node = node->right; + else if (node->rect.contains(point)) + break; + else + return; // Point is completely outside the tree. + } + if (!node) + return; + + // Mark the node as free and then work upwards through the tree + // recombining and deleting nodes until we reach a sibling + // that is still allocated. + node->largestFree = node->rect.size(); + while (node->parent) { + if (node->parent->left == node) { + if (node->parent->right->largestFree != node->parent->right->rect.size()) + break; + } else { + if (node->parent->left->largestFree != node->parent->left->rect.size()) + break; + } + node = node->parent; + freeNode(node->left); + freeNode(node->right); + m_nodeCount -= 2; + node->left = nullptr; + node->right = nullptr; + node->largestFree = node->rect.size(); + } + + // Make the rest of our ancestors have the correct "largest free size". + updateLargestFree(node); +} + +int GeneralAreaAllocator::overhead() const +{ + return m_nodeCount * sizeof(Node); +} + +} // namespace WebKit + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/AreaAllocator.h b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/AreaAllocator.h new file mode 100644 index 000000000..20cadd613 --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/AreaAllocator.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2012 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * + */ + +#ifndef AreaAllocator_h +#define AreaAllocator_h + +#if USE(COORDINATED_GRAPHICS) + +#include <WebCore/IntPoint.h> +#include <WebCore/IntRect.h> +#include <WebCore/IntSize.h> + +namespace WebKit { + +inline int nextPowerOfTwo(int number) +{ + // This is a fast trick to get nextPowerOfTwo for an integer. + --number; + number |= number >> 1; + number |= number >> 2; + number |= number >> 4; + number |= number >> 8; + number |= number >> 16; + number++; + return number; +} + +inline WebCore::IntSize nextPowerOfTwo(const WebCore::IntSize& size) +{ + return WebCore::IntSize(nextPowerOfTwo(size.width()), nextPowerOfTwo(size.height())); +} + +class AreaAllocator { + WTF_MAKE_FAST_ALLOCATED; +public: + explicit AreaAllocator(const WebCore::IntSize&); + virtual ~AreaAllocator(); + + WebCore::IntSize size() const { return m_size; } + + WebCore::IntSize minimumAllocation() const { return m_minAlloc; } + void setMinimumAllocation(const WebCore::IntSize& size) { m_minAlloc = size; } + + WebCore::IntSize margin() const { return m_margin; } + void setMargin(const WebCore::IntSize &margin) { m_margin = margin; } + + virtual void expand(const WebCore::IntSize&); + void expandBy(const WebCore::IntSize&); + + virtual WebCore::IntRect allocate(const WebCore::IntSize&) = 0; + virtual void release(const WebCore::IntRect&); + + virtual int overhead() const; + +protected: + WebCore::IntSize m_size; + WebCore::IntSize m_minAlloc; + WebCore::IntSize m_margin; + + WebCore::IntSize roundAllocation(const WebCore::IntSize&) const; +}; + +class GeneralAreaAllocator final : public AreaAllocator { + WTF_MAKE_FAST_ALLOCATED; +public: + explicit GeneralAreaAllocator(const WebCore::IntSize&); + virtual ~GeneralAreaAllocator(); + + void expand(const WebCore::IntSize&) override; + WebCore::IntRect allocate(const WebCore::IntSize&) override; + void release(const WebCore::IntRect&) override; + int overhead() const override; + +private: + enum Split { SplitOnX, SplitOnY }; + + struct Node { + WTF_MAKE_FAST_ALLOCATED; + public: + WebCore::IntRect rect; + WebCore::IntSize largestFree; + Node* parent { nullptr }; + Node* left { nullptr }; + Node* right { nullptr }; + }; + + Node* m_root; + int m_nodeCount; + + static void freeNode(Node*); + WebCore::IntPoint allocateFromNode(const WebCore::IntSize&, Node*); + Node* splitNode(Node*, Split); + static void updateLargestFree(Node*); +}; + +} // namespace WebKit + +#endif // USE(COORDINATED_GRAPHICS) +#endif // AreaAllocator_h diff --git a/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/CompositingCoordinator.cpp b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/CompositingCoordinator.cpp new file mode 100644 index 000000000..19fed7ece --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/CompositingCoordinator.cpp @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2013 Company 100, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CompositingCoordinator.h" + +#if USE(COORDINATED_GRAPHICS) + +#include <WebCore/DOMWindow.h> +#include <WebCore/Document.h> +#include <WebCore/FrameView.h> +#include <WebCore/GraphicsContext.h> +#include <WebCore/InspectorController.h> +#include <WebCore/MainFrame.h> +#include <WebCore/MemoryPressureHandler.h> +#include <WebCore/Page.h> +#include <wtf/SetForScope.h> + +using namespace WebCore; + +namespace WebKit { + +CompositingCoordinator::CompositingCoordinator(Page* page, CompositingCoordinator::Client& client) + : m_page(page) + , m_client(client) + , m_releaseInactiveAtlasesTimer(*this, &CompositingCoordinator::releaseInactiveAtlasesTimerFired) +{ +} + +CompositingCoordinator::~CompositingCoordinator() +{ + m_isDestructing = true; + + purgeBackingStores(); + + for (auto& registeredLayer : m_registeredLayers.values()) + registeredLayer->setCoordinator(nullptr); +} + +void CompositingCoordinator::invalidate() +{ + m_rootLayer = nullptr; + purgeBackingStores(); +} + +void CompositingCoordinator::setRootCompositingLayer(GraphicsLayer* graphicsLayer) +{ + if (m_rootCompositingLayer == graphicsLayer) + return; + + if (m_rootCompositingLayer) + m_rootCompositingLayer->removeFromParent(); + + m_rootCompositingLayer = graphicsLayer; + if (m_rootCompositingLayer) + m_rootLayer->addChildAtIndex(m_rootCompositingLayer, 0); +} + +void CompositingCoordinator::setViewOverlayRootLayer(GraphicsLayer* graphicsLayer) +{ + if (m_overlayCompositingLayer == graphicsLayer) + return; + + if (m_overlayCompositingLayer) + m_overlayCompositingLayer->removeFromParent(); + + m_overlayCompositingLayer = graphicsLayer; + if (m_overlayCompositingLayer) + m_rootLayer->addChild(m_overlayCompositingLayer); +} + +void CompositingCoordinator::sizeDidChange(const IntSize& newSize) +{ + m_rootLayer->setSize(newSize); + notifyFlushRequired(m_rootLayer.get()); +} + +bool CompositingCoordinator::flushPendingLayerChanges() +{ + SetForScope<bool> protector(m_isFlushingLayerChanges, true); + + initializeRootCompositingLayerIfNeeded(); + + m_rootLayer->flushCompositingStateForThisLayerOnly(); + m_client.didFlushRootLayer(m_visibleContentsRect); + + if (m_overlayCompositingLayer) + m_overlayCompositingLayer->flushCompositingState(FloatRect(FloatPoint(), m_rootLayer->size())); + + bool didSync = m_page->mainFrame().view()->flushCompositingStateIncludingSubframes(); + + auto& coordinatedLayer = downcast<CoordinatedGraphicsLayer>(*m_rootLayer); + coordinatedLayer.updateContentBuffersIncludingSubLayers(); + coordinatedLayer.syncPendingStateChangesIncludingSubLayers(); + + flushPendingImageBackingChanges(); + + if (m_shouldSyncFrame) { + didSync = true; + + if (m_rootCompositingLayer) { + m_state.contentsSize = roundedIntSize(m_rootCompositingLayer->size()); + if (CoordinatedGraphicsLayer* contentsLayer = mainContentsLayer()) + m_state.coveredRect = contentsLayer->coverRect(); + } + m_state.scrollPosition = m_visibleContentsRect.location(); + + m_client.commitSceneState(m_state); + + clearPendingStateChanges(); + m_shouldSyncFrame = false; + } + + return didSync; +} + +double CompositingCoordinator::timestamp() const +{ + auto* document = m_page->mainFrame().document(); + if (!document) + return 0; + return document->domWindow() ? document->domWindow()->nowTimestamp() : document->monotonicTimestamp(); +} + +void CompositingCoordinator::syncDisplayState() +{ +#if !USE(REQUEST_ANIMATION_FRAME_TIMER) && !USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) + // Make sure that any previously registered animation callbacks are being executed before we flush the layers. + m_lastAnimationServiceTime = timestamp(); + m_page->mainFrame().view()->serviceScriptedAnimations(); +#endif + m_page->mainFrame().view()->updateLayoutAndStyleIfNeededRecursive(); +} + +double CompositingCoordinator::nextAnimationServiceTime() const +{ + // According to the requestAnimationFrame spec, rAF callbacks should not be faster than 60FPS. + static const double MinimalTimeoutForAnimations = 1. / 60.; + return std::max<double>(0., MinimalTimeoutForAnimations - timestamp() + m_lastAnimationServiceTime); +} + +void CompositingCoordinator::clearPendingStateChanges() +{ + m_state.layersToCreate.clear(); + m_state.layersToUpdate.clear(); + m_state.layersToRemove.clear(); + + m_state.imagesToCreate.clear(); + m_state.imagesToRemove.clear(); + m_state.imagesToUpdate.clear(); + m_state.imagesToClear.clear(); + + m_state.updateAtlasesToCreate.clear(); + m_state.updateAtlasesToRemove.clear(); +} + +void CompositingCoordinator::initializeRootCompositingLayerIfNeeded() +{ + if (m_didInitializeRootCompositingLayer) + return; + + m_state.rootCompositingLayer = downcast<CoordinatedGraphicsLayer>(*m_rootLayer).id(); + m_didInitializeRootCompositingLayer = true; + m_shouldSyncFrame = true; +} + +void CompositingCoordinator::createRootLayer(const IntSize& size) +{ + ASSERT(!m_rootLayer); + // Create a root layer. + m_rootLayer = GraphicsLayer::create(this, *this); +#ifndef NDEBUG + m_rootLayer->setName("CompositingCoordinator root layer"); +#endif + m_rootLayer->setDrawsContent(false); + m_rootLayer->setSize(size); +} + +void CompositingCoordinator::syncLayerState(CoordinatedLayerID id, CoordinatedGraphicsLayerState& state) +{ + m_shouldSyncFrame = true; + m_state.layersToUpdate.append(std::make_pair(id, state)); +} + +Ref<CoordinatedImageBacking> CompositingCoordinator::createImageBackingIfNeeded(Image* image) +{ + CoordinatedImageBackingID imageID = CoordinatedImageBacking::getCoordinatedImageBackingID(image); + auto addResult = m_imageBackings.ensure(imageID, [this, image] { + return CoordinatedImageBacking::create(this, image); + }); + return *addResult.iterator->value; +} + +void CompositingCoordinator::createImageBacking(CoordinatedImageBackingID imageID) +{ + m_state.imagesToCreate.append(imageID); +} + +void CompositingCoordinator::updateImageBacking(CoordinatedImageBackingID imageID, RefPtr<CoordinatedSurface>&& coordinatedSurface) +{ + m_shouldSyncFrame = true; + m_state.imagesToUpdate.append(std::make_pair(imageID, WTFMove(coordinatedSurface))); +} + +void CompositingCoordinator::clearImageBackingContents(CoordinatedImageBackingID imageID) +{ + m_shouldSyncFrame = true; + m_state.imagesToClear.append(imageID); +} + +void CompositingCoordinator::removeImageBacking(CoordinatedImageBackingID imageID) +{ + if (m_isPurging) + return; + + ASSERT(m_imageBackings.contains(imageID)); + m_imageBackings.remove(imageID); + + m_state.imagesToRemove.append(imageID); + + size_t imageIDPosition = m_state.imagesToClear.find(imageID); + if (imageIDPosition != notFound) + m_state.imagesToClear.remove(imageIDPosition); +} + +void CompositingCoordinator::flushPendingImageBackingChanges() +{ + for (auto& imageBacking : m_imageBackings.values()) + imageBacking->update(); +} + +void CompositingCoordinator::notifyAnimationStarted(const GraphicsLayer*, const String&, double /* time */) +{ +} + +void CompositingCoordinator::notifyFlushRequired(const GraphicsLayer*) +{ + if (!m_isDestructing && !isFlushingLayerChanges()) + m_client.notifyFlushRequired(); +} + +void CompositingCoordinator::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& graphicsContext, GraphicsLayerPaintingPhase, const FloatRect& clipRect) +{ + m_client.paintLayerContents(graphicsLayer, graphicsContext, enclosingIntRect(clipRect)); +} + +std::unique_ptr<GraphicsLayer> CompositingCoordinator::createGraphicsLayer(GraphicsLayer::Type layerType, GraphicsLayerClient& client) +{ + CoordinatedGraphicsLayer* layer = new CoordinatedGraphicsLayer(layerType, client); + layer->setCoordinator(this); + m_registeredLayers.add(layer->id(), layer); + m_state.layersToCreate.append(layer->id()); + layer->setNeedsVisibleRectAdjustment(); + notifyFlushRequired(layer); + return std::unique_ptr<GraphicsLayer>(layer); +} + +float CompositingCoordinator::deviceScaleFactor() const +{ + return m_page->deviceScaleFactor(); +} + +float CompositingCoordinator::pageScaleFactor() const +{ + return m_page->pageScaleFactor(); +} + +void CompositingCoordinator::createUpdateAtlas(uint32_t atlasID, RefPtr<CoordinatedSurface>&& coordinatedSurface) +{ + m_state.updateAtlasesToCreate.append(std::make_pair(atlasID, WTFMove(coordinatedSurface))); +} + +void CompositingCoordinator::removeUpdateAtlas(uint32_t atlasID) +{ + if (m_isPurging) + return; + m_state.updateAtlasesToRemove.append(atlasID); +} + +FloatRect CompositingCoordinator::visibleContentsRect() const +{ + return m_visibleContentsRect; +} + +CoordinatedGraphicsLayer* CompositingCoordinator::mainContentsLayer() +{ + if (!is<CoordinatedGraphicsLayer>(m_rootCompositingLayer)) + return nullptr; + + return downcast<CoordinatedGraphicsLayer>(*m_rootCompositingLayer).findFirstDescendantWithContentsRecursively(); +} + +void CompositingCoordinator::setVisibleContentsRect(const FloatRect& rect, const FloatPoint& trajectoryVector) +{ + // A zero trajectoryVector indicates that tiles all around the viewport are requested. + if (CoordinatedGraphicsLayer* contentsLayer = mainContentsLayer()) + contentsLayer->setVisibleContentRectTrajectoryVector(trajectoryVector); + + bool contentsRectDidChange = rect != m_visibleContentsRect; + if (contentsRectDidChange) { + m_visibleContentsRect = rect; + + for (auto& registeredLayer : m_registeredLayers.values()) + registeredLayer->setNeedsVisibleRectAdjustment(); + } + + FrameView* view = m_page->mainFrame().view(); + if (view->useFixedLayout() && contentsRectDidChange) { + // Round the rect instead of enclosing it to make sure that its size stays + // the same while panning. This can have nasty effects on layout. + view->setFixedVisibleContentRect(roundedIntRect(rect)); + } +} + +void CompositingCoordinator::deviceOrPageScaleFactorChanged() +{ + m_rootLayer->deviceOrPageScaleFactorChanged(); +} + +void CompositingCoordinator::detachLayer(CoordinatedGraphicsLayer* layer) +{ + if (m_isPurging) + return; + + m_registeredLayers.remove(layer->id()); + + size_t index = m_state.layersToCreate.find(layer->id()); + if (index != notFound) { + m_state.layersToCreate.remove(index); + return; + } + + m_state.layersToRemove.append(layer->id()); + notifyFlushRequired(layer); +} + +void CompositingCoordinator::commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset) +{ + if (auto* layer = m_registeredLayers.get(layerID)) + layer->commitScrollOffset(offset); +} + +void CompositingCoordinator::renderNextFrame() +{ + for (auto& atlas : m_updateAtlases) + atlas->didSwapBuffers(); +} + +void CompositingCoordinator::purgeBackingStores() +{ + SetForScope<bool> purgingToggle(m_isPurging, true); + + for (auto& registeredLayer : m_registeredLayers.values()) + registeredLayer->purgeBackingStores(); + + m_imageBackings.clear(); + m_updateAtlases.clear(); +} + +bool CompositingCoordinator::paintToSurface(const IntSize& size, CoordinatedSurface::Flags flags, uint32_t& atlasID, IntPoint& offset, CoordinatedSurface::Client& client) +{ + for (auto& updateAtlas : m_updateAtlases) { + UpdateAtlas* atlas = updateAtlas.get(); + if (atlas->supportsAlpha() == (flags & CoordinatedSurface::SupportsAlpha)) { + // This will be false if there is no available buffer space. + if (atlas->paintOnAvailableBuffer(size, atlasID, offset, client)) + return true; + } + } + + static const int ScratchBufferDimension = 1024; // Should be a power of two. + m_updateAtlases.append(std::make_unique<UpdateAtlas>(*this, ScratchBufferDimension, flags)); + scheduleReleaseInactiveAtlases(); + return m_updateAtlases.last()->paintOnAvailableBuffer(size, atlasID, offset, client); +} + +const double ReleaseInactiveAtlasesTimerInterval = 0.5; + +void CompositingCoordinator::scheduleReleaseInactiveAtlases() +{ + if (!m_releaseInactiveAtlasesTimer.isActive()) + m_releaseInactiveAtlasesTimer.startRepeating(ReleaseInactiveAtlasesTimerInterval); +} + +void CompositingCoordinator::releaseInactiveAtlasesTimerFired() +{ + releaseAtlases(MemoryPressureHandler::singleton().isUnderMemoryPressure() ? ReleaseUnused : ReleaseInactive); +} + +void CompositingCoordinator::releaseAtlases(ReleaseAtlasPolicy policy) +{ + // We always want to keep one atlas for root contents layer. + std::unique_ptr<UpdateAtlas> atlasToKeepAnyway; + bool foundActiveAtlasForRootContentsLayer = false; + for (int i = m_updateAtlases.size() - 1; i >= 0; --i) { + UpdateAtlas* atlas = m_updateAtlases[i].get(); + bool inUse = atlas->isInUse(); + if (!inUse) + atlas->addTimeInactive(ReleaseInactiveAtlasesTimerInterval); + bool usableForRootContentsLayer = !atlas->supportsAlpha(); + if (atlas->isInactive() || (!inUse && policy == ReleaseUnused)) { + if (!foundActiveAtlasForRootContentsLayer && !atlasToKeepAnyway && usableForRootContentsLayer) + atlasToKeepAnyway = WTFMove(m_updateAtlases[i]); + m_updateAtlases.remove(i); + } else if (usableForRootContentsLayer) + foundActiveAtlasForRootContentsLayer = true; + } + + if (!foundActiveAtlasForRootContentsLayer && atlasToKeepAnyway) + m_updateAtlases.append(atlasToKeepAnyway.release()); + + m_updateAtlases.shrinkToFit(); + + if (m_updateAtlases.size() <= 1) + m_releaseInactiveAtlasesTimer.stop(); +} + +} // namespace WebKit + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/CompositingCoordinator.h b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/CompositingCoordinator.h new file mode 100644 index 000000000..eb214cf65 --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/CompositingCoordinator.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2013 Company 100, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CompositingCoordinator_h +#define CompositingCoordinator_h + +#if USE(COORDINATED_GRAPHICS) + +#include "UpdateAtlas.h" +#include <WebCore/CoordinatedGraphicsLayer.h> +#include <WebCore/CoordinatedGraphicsState.h> +#include <WebCore/CoordinatedImageBacking.h> +#include <WebCore/FloatPoint.h> +#include <WebCore/GraphicsLayerClient.h> +#include <WebCore/GraphicsLayerFactory.h> +#include <WebCore/IntRect.h> +#include <WebCore/Timer.h> + +namespace WebCore { +class Page; +class GraphicsContext; +class GraphicsLayer; +class CoordinatedSurface; +} + +namespace WebKit { + +class CompositingCoordinator final : public WebCore::GraphicsLayerClient + , public WebCore::CoordinatedGraphicsLayerClient + , public WebCore::CoordinatedImageBacking::Client + , public UpdateAtlas::Client + , public WebCore::GraphicsLayerFactory { + WTF_MAKE_NONCOPYABLE(CompositingCoordinator); +public: + class Client { + public: + virtual void didFlushRootLayer(const WebCore::FloatRect& visibleContentRect) = 0; + virtual void notifyFlushRequired() = 0; + virtual void commitSceneState(const WebCore::CoordinatedGraphicsState&) = 0; + virtual void paintLayerContents(const WebCore::GraphicsLayer*, WebCore::GraphicsContext&, const WebCore::IntRect& clipRect) = 0; + }; + + CompositingCoordinator(WebCore::Page*, CompositingCoordinator::Client&); + virtual ~CompositingCoordinator(); + + void invalidate(); + + void setRootCompositingLayer(WebCore::GraphicsLayer*); + void setViewOverlayRootLayer(WebCore::GraphicsLayer*); + void sizeDidChange(const WebCore::IntSize&); + void deviceOrPageScaleFactorChanged(); + + void setVisibleContentsRect(const WebCore::FloatRect&, const WebCore::FloatPoint&); + void renderNextFrame(); + void commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset); + + void createRootLayer(const WebCore::IntSize&); + WebCore::GraphicsLayer* rootLayer() const { return m_rootLayer.get(); } + WebCore::GraphicsLayer* rootCompositingLayer() const { return m_rootCompositingLayer; } + WebCore::CoordinatedGraphicsLayer* mainContentsLayer(); + + bool flushPendingLayerChanges(); + WebCore::CoordinatedGraphicsState& state() { return m_state; } + + void syncDisplayState(); + + double nextAnimationServiceTime() const; + +private: + enum ReleaseAtlasPolicy { + ReleaseInactive, + ReleaseUnused + }; + + // GraphicsLayerClient + void notifyAnimationStarted(const WebCore::GraphicsLayer*, const String&, double time) override; + void notifyFlushRequired(const WebCore::GraphicsLayer*) override; + void paintContents(const WebCore::GraphicsLayer*, WebCore::GraphicsContext&, WebCore::GraphicsLayerPaintingPhase, const WebCore::FloatRect& clipRect) override; + float deviceScaleFactor() const override; + float pageScaleFactor() const override; + + // CoordinatedImageBacking::Client + void createImageBacking(WebCore::CoordinatedImageBackingID) override; + void updateImageBacking(WebCore::CoordinatedImageBackingID, RefPtr<WebCore::CoordinatedSurface>&&) override; + void clearImageBackingContents(WebCore::CoordinatedImageBackingID) override; + void removeImageBacking(WebCore::CoordinatedImageBackingID) override; + + // CoordinatedGraphicsLayerClient + bool isFlushingLayerChanges() const override { return m_isFlushingLayerChanges; } + WebCore::FloatRect visibleContentsRect() const override; + Ref<WebCore::CoordinatedImageBacking> createImageBackingIfNeeded(WebCore::Image*) override; + void detachLayer(WebCore::CoordinatedGraphicsLayer*) override; + bool paintToSurface(const WebCore::IntSize&, WebCore::CoordinatedSurface::Flags, uint32_t& /* atlasID */, WebCore::IntPoint&, WebCore::CoordinatedSurface::Client&) override; + void syncLayerState(WebCore::CoordinatedLayerID, WebCore::CoordinatedGraphicsLayerState&) override; + + // UpdateAtlas::Client + void createUpdateAtlas(uint32_t atlasID, RefPtr<WebCore::CoordinatedSurface>&&) override; + void removeUpdateAtlas(uint32_t atlasID) override; + + // GraphicsLayerFactory + std::unique_ptr<WebCore::GraphicsLayer> createGraphicsLayer(WebCore::GraphicsLayer::Type, WebCore::GraphicsLayerClient&) override; + + void initializeRootCompositingLayerIfNeeded(); + void flushPendingImageBackingChanges(); + void clearPendingStateChanges(); + + void purgeBackingStores(); + + void scheduleReleaseInactiveAtlases(); + void releaseInactiveAtlasesTimerFired(); + void releaseAtlases(ReleaseAtlasPolicy); + + double timestamp() const; + + WebCore::Page* m_page; + CompositingCoordinator::Client& m_client; + + std::unique_ptr<WebCore::GraphicsLayer> m_rootLayer; + WebCore::GraphicsLayer* m_rootCompositingLayer { nullptr }; + WebCore::GraphicsLayer* m_overlayCompositingLayer { nullptr }; + + WebCore::CoordinatedGraphicsState m_state; + + typedef HashMap<WebCore::CoordinatedLayerID, WebCore::CoordinatedGraphicsLayer*> LayerMap; + LayerMap m_registeredLayers; + typedef HashMap<WebCore::CoordinatedImageBackingID, RefPtr<WebCore::CoordinatedImageBacking> > ImageBackingMap; + ImageBackingMap m_imageBackings; + Vector<std::unique_ptr<UpdateAtlas>> m_updateAtlases; + + // We don't send the messages related to releasing resources to renderer during purging, because renderer already had removed all resources. + bool m_isDestructing { false }; + bool m_isPurging { false }; + bool m_isFlushingLayerChanges { false }; + bool m_shouldSyncFrame { false }; + bool m_didInitializeRootCompositingLayer { false }; + + WebCore::FloatRect m_visibleContentsRect; + WebCore::Timer m_releaseInactiveAtlasesTimer; + + double m_lastAnimationServiceTime { 0 }; +}; + +} + +#endif // namespace WebKit + +#endif // CompositingCoordinator_h diff --git a/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/CoordinatedLayerTreeHost.cpp b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/CoordinatedLayerTreeHost.cpp new file mode 100644 index 000000000..b74070519 --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/CoordinatedLayerTreeHost.cpp @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2012 Company 100, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if USE(COORDINATED_GRAPHICS) +#include "CoordinatedLayerTreeHost.h" + +#include "DrawingArea.h" +#include "WebCoordinatedSurface.h" +#include "WebPage.h" +#include "WebPageProxyMessages.h" +#include <WebCore/FrameView.h> +#include <WebCore/MainFrame.h> +#include <WebCore/PageOverlayController.h> + +#if USE(COORDINATED_GRAPHICS_THREADED) +#include "ThreadSafeCoordinatedSurface.h" +#endif + +using namespace WebCore; + +namespace WebKit { + +Ref<CoordinatedLayerTreeHost> CoordinatedLayerTreeHost::create(WebPage& webPage) +{ + return adoptRef(*new CoordinatedLayerTreeHost(webPage)); +} + +CoordinatedLayerTreeHost::~CoordinatedLayerTreeHost() +{ +} + +CoordinatedLayerTreeHost::CoordinatedLayerTreeHost(WebPage& webPage) + : LayerTreeHost(webPage) + , m_coordinator(webPage.corePage(), *this) + , m_layerFlushTimer(RunLoop::main(), this, &CoordinatedLayerTreeHost::layerFlushTimerFired) +{ + m_coordinator.createRootLayer(m_webPage.size()); + + CoordinatedSurface::setFactory(createCoordinatedSurface); + scheduleLayerFlush(); +} + +void CoordinatedLayerTreeHost::scheduleLayerFlush() +{ + if (!m_layerFlushSchedulingEnabled) + return; + + if (m_isWaitingForRenderer) { + m_scheduledWhileWaitingForRenderer = true; + return; + } + + if (!m_layerFlushTimer.isActive()) + m_layerFlushTimer.startOneShot(0); +} + +void CoordinatedLayerTreeHost::cancelPendingLayerFlush() +{ + m_layerFlushTimer.stop(); +} + +void CoordinatedLayerTreeHost::setViewOverlayRootLayer(GraphicsLayer* viewOverlayRootLayer) +{ + LayerTreeHost::setViewOverlayRootLayer(viewOverlayRootLayer); + m_coordinator.setViewOverlayRootLayer(viewOverlayRootLayer); +} + +void CoordinatedLayerTreeHost::setRootCompositingLayer(GraphicsLayer* graphicsLayer) +{ + m_coordinator.setRootCompositingLayer(graphicsLayer); +} + +void CoordinatedLayerTreeHost::invalidate() +{ + cancelPendingLayerFlush(); + + m_coordinator.invalidate(); + LayerTreeHost::invalidate(); +} + +void CoordinatedLayerTreeHost::forceRepaint() +{ + // This is necessary for running layout tests. Since in this case we are not waiting for a UIProcess to reply nicely. + // Instead we are just triggering forceRepaint. But we still want to have the scripted animation callbacks being executed. + m_coordinator.syncDisplayState(); + + // We need to schedule another flush, otherwise the forced paint might cancel a later expected flush. + // This is aligned with LayerTreeHostCA. + scheduleLayerFlush(); + + if (m_isWaitingForRenderer) + return; + + m_coordinator.flushPendingLayerChanges(); +} + +bool CoordinatedLayerTreeHost::forceRepaintAsync(uint64_t callbackID) +{ + // We expect the UI process to not require a new repaint until the previous one has finished. + ASSERT(!m_forceRepaintAsyncCallbackID); + m_forceRepaintAsyncCallbackID = callbackID; + scheduleLayerFlush(); + return true; +} + +void CoordinatedLayerTreeHost::sizeDidChange(const IntSize& newSize) +{ + m_coordinator.sizeDidChange(newSize); + scheduleLayerFlush(); +} + +void CoordinatedLayerTreeHost::setVisibleContentsRect(const FloatRect& rect, const FloatPoint& trajectoryVector) +{ + m_coordinator.setVisibleContentsRect(rect, trajectoryVector); + scheduleLayerFlush(); +} + +void CoordinatedLayerTreeHost::renderNextFrame() +{ + m_isWaitingForRenderer = false; + bool scheduledWhileWaitingForRenderer = std::exchange(m_scheduledWhileWaitingForRenderer, false); + m_coordinator.renderNextFrame(); + + if (scheduledWhileWaitingForRenderer || m_layerFlushTimer.isActive()) { + m_layerFlushTimer.stop(); + layerFlushTimerFired(); + } +} + +void CoordinatedLayerTreeHost::didFlushRootLayer(const FloatRect& visibleContentRect) +{ + // Because our view-relative overlay root layer is not attached to the FrameView's GraphicsLayer tree, we need to flush it manually. + if (m_viewOverlayRootLayer) + m_viewOverlayRootLayer->flushCompositingState(visibleContentRect); +} + +void CoordinatedLayerTreeHost::layerFlushTimerFired() +{ + if (m_isSuspended || m_isWaitingForRenderer) + return; + + m_coordinator.syncDisplayState(); + + if (!m_isValid || !m_coordinator.rootCompositingLayer()) + return; + + bool didSync = m_coordinator.flushPendingLayerChanges(); + + if (m_forceRepaintAsyncCallbackID) { + m_webPage.send(Messages::WebPageProxy::VoidCallback(m_forceRepaintAsyncCallbackID)); + m_forceRepaintAsyncCallbackID = 0; + } + + if (m_notifyAfterScheduledLayerFlush && didSync) { + m_webPage.drawingArea()->layerHostDidFlushLayers(); + m_notifyAfterScheduledLayerFlush = false; + } +} + +void CoordinatedLayerTreeHost::paintLayerContents(const GraphicsLayer*, GraphicsContext&, const IntRect&) +{ +} + +void CoordinatedLayerTreeHost::commitSceneState(const CoordinatedGraphicsState& state) +{ + m_isWaitingForRenderer = true; +} + +RefPtr<CoordinatedSurface> CoordinatedLayerTreeHost::createCoordinatedSurface(const IntSize& size, CoordinatedSurface::Flags flags) +{ +#if USE(COORDINATED_GRAPHICS_THREADED) + return ThreadSafeCoordinatedSurface::create(size, flags); +#else + UNUSED_PARAM(size); + UNUSED_PARAM(flags); + return nullptr; +#endif +} + +void CoordinatedLayerTreeHost::deviceOrPageScaleFactorChanged() +{ + m_coordinator.deviceOrPageScaleFactorChanged(); + m_webPage.mainFrame()->pageOverlayController().didChangeDeviceScaleFactor(); +} + +void CoordinatedLayerTreeHost::pageBackgroundTransparencyChanged() +{ +} + +GraphicsLayerFactory* CoordinatedLayerTreeHost::graphicsLayerFactory() +{ + return &m_coordinator; +} + +void CoordinatedLayerTreeHost::scheduleAnimation() +{ + if (m_isWaitingForRenderer) + return; + + if (m_layerFlushTimer.isActive()) + return; + + scheduleLayerFlush(); + m_layerFlushTimer.startOneShot(m_coordinator.nextAnimationServiceTime()); +} + +void CoordinatedLayerTreeHost::commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset) +{ + m_coordinator.commitScrollOffset(layerID, offset); +} + +} // namespace WebKit +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/CoordinatedLayerTreeHost.h b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/CoordinatedLayerTreeHost.h new file mode 100644 index 000000000..7b3aa5d35 --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/CoordinatedLayerTreeHost.h @@ -0,0 +1,92 @@ +/* + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2013 Company 100, Inc. + + 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. +*/ + +#ifndef CoordinatedLayerTreeHost_h +#define CoordinatedLayerTreeHost_h + +#if USE(COORDINATED_GRAPHICS) + +#include "CompositingCoordinator.h" +#include "LayerTreeHost.h" +#include <wtf/RunLoop.h> + +namespace WebCore { +class CoordinatedSurface; +class GraphicsLayerFactory; +} + +namespace WebKit { + +class WebPage; + +class CoordinatedLayerTreeHost : public LayerTreeHost, public CompositingCoordinator::Client +{ +public: + static Ref<CoordinatedLayerTreeHost> create(WebPage&); + virtual ~CoordinatedLayerTreeHost(); + +protected: + explicit CoordinatedLayerTreeHost(WebPage&); + + void scheduleLayerFlush() override; + void cancelPendingLayerFlush() override; + void setRootCompositingLayer(WebCore::GraphicsLayer*) override; + void invalidate() override; + + void forceRepaint() override; + bool forceRepaintAsync(uint64_t callbackID) override; + void sizeDidChange(const WebCore::IntSize& newSize) override; + + void deviceOrPageScaleFactorChanged() override; + void pageBackgroundTransparencyChanged() override; + + void setVisibleContentsRect(const WebCore::FloatRect&, const WebCore::FloatPoint&); + void renderNextFrame(); + void commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset); + + WebCore::GraphicsLayerFactory* graphicsLayerFactory() override; + + void scheduleAnimation() override; + + void setViewOverlayRootLayer(WebCore::GraphicsLayer*) override; + + // CompositingCoordinator::Client + void didFlushRootLayer(const WebCore::FloatRect& visibleContentRect) override; + void notifyFlushRequired() override { scheduleLayerFlush(); }; + void commitSceneState(const WebCore::CoordinatedGraphicsState&) override; + void paintLayerContents(const WebCore::GraphicsLayer*, WebCore::GraphicsContext&, const WebCore::IntRect& clipRect) override; + +private: + void layerFlushTimerFired(); + + static RefPtr<WebCore::CoordinatedSurface> createCoordinatedSurface(const WebCore::IntSize&, WebCore::CoordinatedSurface::Flags); + + CompositingCoordinator m_coordinator; + bool m_isWaitingForRenderer { true }; + bool m_scheduledWhileWaitingForRenderer { false }; + uint64_t m_forceRepaintAsyncCallbackID { 0 }; + RunLoop::Timer<CoordinatedLayerTreeHost> m_layerFlushTimer; +}; + +} // namespace WebKit + +#endif // USE(COORDINATED_GRAPHICS) + +#endif // CoordinatedLayerTreeHost_h diff --git a/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/CoordinatedLayerTreeHost.messages.in b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/CoordinatedLayerTreeHost.messages.in new file mode 100644 index 000000000..73f953d0b --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/CoordinatedLayerTreeHost.messages.in @@ -0,0 +1,28 @@ +# +# Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) +# Copyright (C) 2012 Intel Corporation. All rights reserved. +# +# 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. +# + + +#if USE(COORDINATED_GRAPHICS) +messages -> CoordinatedLayerTreeHost LegacyReceiver { + SetVisibleContentsRect(WebCore::FloatRect visibleContentsRect, WebCore::FloatPoint trajectoryVectory) + RenderNextFrame() + CommitScrollOffset(uint32_t layerID, WebCore::IntSize offset) +} +#endif diff --git a/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/ThreadedCoordinatedLayerTreeHost.cpp b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/ThreadedCoordinatedLayerTreeHost.cpp new file mode 100644 index 000000000..281353b8a --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/ThreadedCoordinatedLayerTreeHost.cpp @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (C) 2012 Company 100, Inc. + * Copyright (C) 2014 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ThreadedCoordinatedLayerTreeHost.h" + +#if USE(COORDINATED_GRAPHICS_THREADED) + +#include "AcceleratedSurface.h" +#include "WebPage.h" +#include <WebCore/FrameView.h> +#include <WebCore/MainFrame.h> + +using namespace WebCore; + +namespace WebKit { + +Ref<ThreadedCoordinatedLayerTreeHost> ThreadedCoordinatedLayerTreeHost::create(WebPage& webPage) +{ + return adoptRef(*new ThreadedCoordinatedLayerTreeHost(webPage)); +} + +ThreadedCoordinatedLayerTreeHost::~ThreadedCoordinatedLayerTreeHost() +{ +} + +ThreadedCoordinatedLayerTreeHost::ThreadedCoordinatedLayerTreeHost(WebPage& webPage) + : CoordinatedLayerTreeHost(webPage) + , m_compositorClient(*this) + , m_surface(AcceleratedSurface::create(webPage)) + , m_viewportController(webPage.size()) +{ + if (FrameView* frameView = m_webPage.mainFrameView()) { + auto contentsSize = frameView->contentsSize(); + if (!contentsSize.isEmpty()) + m_viewportController.didChangeContentsSize(contentsSize); + } + + IntSize scaledSize(m_webPage.size()); + scaledSize.scale(m_webPage.deviceScaleFactor()); + float scaleFactor = m_webPage.deviceScaleFactor() * m_viewportController.pageScaleFactor(); + + if (m_surface) { + TextureMapper::PaintFlags paintFlags = 0; + + if (m_surface->shouldPaintMirrored()) + paintFlags |= TextureMapper::PaintingMirrored; + + // Do not do frame sync when rendering offscreen in the web process to ensure that SwapBuffers never blocks. + // Rendering to the actual screen will happen later anyway since the UI process schedules a redraw for every update, + // the compositor will take care of syncing to vblank. + m_compositor = ThreadedCompositor::create(m_compositorClient, scaledSize, scaleFactor, m_surface->window(), ThreadedCompositor::ShouldDoFrameSync::No, paintFlags); + m_layerTreeContext.contextID = m_surface->surfaceID(); + } else + m_compositor = ThreadedCompositor::create(m_compositorClient, scaledSize, scaleFactor); + + didChangeViewport(); +} + +void ThreadedCoordinatedLayerTreeHost::invalidate() +{ + m_compositor->invalidate(); + CoordinatedLayerTreeHost::invalidate(); + m_surface = nullptr; +} + +void ThreadedCoordinatedLayerTreeHost::forceRepaint() +{ + CoordinatedLayerTreeHost::forceRepaint(); + m_compositor->forceRepaint(); +} + +void ThreadedCoordinatedLayerTreeHost::scrollNonCompositedContents(const IntRect& rect) +{ + FrameView* frameView = m_webPage.mainFrameView(); + if (!frameView || !frameView->delegatesScrolling()) + return; + + m_viewportController.didScroll(rect.location()); + if (m_isDiscardable) + m_discardableSyncActions |= DiscardableSyncActions::UpdateViewport; + else + didChangeViewport(); +} + +void ThreadedCoordinatedLayerTreeHost::contentsSizeChanged(const IntSize& newSize) +{ + m_viewportController.didChangeContentsSize(newSize); + if (m_isDiscardable) + m_discardableSyncActions |= DiscardableSyncActions::UpdateViewport; + else + didChangeViewport(); +} + +void ThreadedCoordinatedLayerTreeHost::deviceOrPageScaleFactorChanged() +{ + if (m_isDiscardable) { + m_discardableSyncActions |= DiscardableSyncActions::UpdateScale; + return; + } + + if (m_surface && m_surface->resize(m_webPage.size())) + m_layerTreeContext.contextID = m_surface->surfaceID(); + + CoordinatedLayerTreeHost::deviceOrPageScaleFactorChanged(); + m_compositor->setScaleFactor(m_webPage.deviceScaleFactor() * m_viewportController.pageScaleFactor()); +} + +void ThreadedCoordinatedLayerTreeHost::pageBackgroundTransparencyChanged() +{ + if (m_isDiscardable) { + m_discardableSyncActions |= DiscardableSyncActions::UpdateBackground; + return; + } + + CoordinatedLayerTreeHost::pageBackgroundTransparencyChanged(); + m_compositor->setDrawsBackground(m_webPage.drawsBackground()); +} + +void ThreadedCoordinatedLayerTreeHost::sizeDidChange(const IntSize& size) +{ + if (m_isDiscardable) { + m_discardableSyncActions |= DiscardableSyncActions::UpdateSize; + m_viewportController.didChangeViewportSize(size); + return; + } + + if (m_surface && m_surface->resize(size)) + m_layerTreeContext.contextID = m_surface->surfaceID(); + + CoordinatedLayerTreeHost::sizeDidChange(size); + m_viewportController.didChangeViewportSize(size); + IntSize scaledSize(size); + scaledSize.scale(m_webPage.deviceScaleFactor()); + m_compositor->setViewportSize(scaledSize, m_webPage.deviceScaleFactor() * m_viewportController.pageScaleFactor()); + didChangeViewport(); +} + +void ThreadedCoordinatedLayerTreeHost::didChangeViewportAttributes(ViewportAttributes&& attr) +{ + m_viewportController.didChangeViewportAttributes(WTFMove(attr)); + if (m_isDiscardable) + m_discardableSyncActions |= DiscardableSyncActions::UpdateViewport; + else + didChangeViewport(); +} + +#if PLATFORM(GTK) && PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW) +void ThreadedCoordinatedLayerTreeHost::setNativeSurfaceHandleForCompositing(uint64_t handle) +{ + m_layerTreeContext.contextID = handle; + m_compositor->setNativeSurfaceHandleForCompositing(handle); + scheduleLayerFlush(); +} +#endif + +void ThreadedCoordinatedLayerTreeHost::didChangeViewport() +{ + FloatRect visibleRect(m_viewportController.visibleContentsRect()); + if (visibleRect.isEmpty()) + return; + + // When using non overlay scrollbars, the contents size doesn't include the scrollbars, but we need to include them + // in the visible area used by the compositor to ensure that the scrollbar layers are also updated. + // See https://bugs.webkit.org/show_bug.cgi?id=160450. + FrameView* view = m_webPage.corePage()->mainFrame().view(); + Scrollbar* scrollbar = view->verticalScrollbar(); + if (scrollbar && !scrollbar->isOverlayScrollbar()) + visibleRect.expand(scrollbar->width(), 0); + scrollbar = view->horizontalScrollbar(); + if (scrollbar && !scrollbar->isOverlayScrollbar()) + visibleRect.expand(0, scrollbar->height()); + + CoordinatedLayerTreeHost::setVisibleContentsRect(visibleRect, FloatPoint::zero()); + + float pageScale = m_viewportController.pageScaleFactor(); + IntPoint scrollPosition = roundedIntPoint(visibleRect.location()); + if (m_lastScrollPosition != scrollPosition) { + m_lastScrollPosition = scrollPosition; + m_compositor->setScrollPosition(m_lastScrollPosition, m_webPage.deviceScaleFactor() * pageScale); + + if (!view->useFixedLayout()) + view->notifyScrollPositionChanged(m_lastScrollPosition); + } + + if (m_lastPageScaleFactor != pageScale) { + m_lastPageScaleFactor = pageScale; + m_webPage.scalePage(pageScale, m_lastScrollPosition); + } +} + +void ThreadedCoordinatedLayerTreeHost::commitSceneState(const CoordinatedGraphicsState& state) +{ + CoordinatedLayerTreeHost::commitSceneState(state); + m_compositor->updateSceneState(state); +} + +void ThreadedCoordinatedLayerTreeHost::setIsDiscardable(bool discardable) +{ + m_isDiscardable = discardable; + if (m_isDiscardable) { + m_discardableSyncActions = OptionSet<DiscardableSyncActions>(); + return; + } + + if (m_discardableSyncActions.isEmpty()) + return; + + if (m_discardableSyncActions.contains(DiscardableSyncActions::UpdateBackground)) + pageBackgroundTransparencyChanged(); + + if (m_discardableSyncActions.contains(DiscardableSyncActions::UpdateSize)) { + // Size changes already sets the scale factor and updates the viewport. + sizeDidChange(m_webPage.size()); + return; + } + + if (m_discardableSyncActions.contains(DiscardableSyncActions::UpdateScale)) + deviceOrPageScaleFactorChanged(); + + if (m_discardableSyncActions.contains(DiscardableSyncActions::UpdateViewport)) + didChangeViewport(); +} + +} // namespace WebKit + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/ThreadedCoordinatedLayerTreeHost.h b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/ThreadedCoordinatedLayerTreeHost.h new file mode 100644 index 000000000..ca8aeac63 --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/ThreadedCoordinatedLayerTreeHost.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2013 Company 100, Inc. + * Copyright (C) 2014 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ThreadedCoordinatedLayerTreeHost_h +#define ThreadedCoordinatedLayerTreeHost_h + +#if USE(COORDINATED_GRAPHICS_THREADED) + +#include "CoordinatedLayerTreeHost.h" +#include "SimpleViewportController.h" +#include "ThreadedCompositor.h" +#include <wtf/OptionSet.h> + +namespace WebCore { +class GraphicsContext; +class GraphicsLayer; +struct CoordinatedGraphicsState; +} + +namespace WebKit { + +class AcceleratedSurface; +class WebPage; + +class ThreadedCoordinatedLayerTreeHost final : public CoordinatedLayerTreeHost { +public: + static Ref<ThreadedCoordinatedLayerTreeHost> create(WebPage&); + virtual ~ThreadedCoordinatedLayerTreeHost(); + +private: + explicit ThreadedCoordinatedLayerTreeHost(WebPage&); + + void scrollNonCompositedContents(const WebCore::IntRect& scrollRect) override; + void sizeDidChange(const WebCore::IntSize&) override; + void deviceOrPageScaleFactorChanged() override; + void pageBackgroundTransparencyChanged() override; + + void contentsSizeChanged(const WebCore::IntSize&) override; + void didChangeViewportAttributes(WebCore::ViewportAttributes&&) override; + + void invalidate() override; + + void forceRepaint() override; + bool forceRepaintAsync(uint64_t callbackID) override { return false; } + + void setIsDiscardable(bool) override; + +#if PLATFORM(GTK) && PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW) + void setNativeSurfaceHandleForCompositing(uint64_t) override; +#endif + + class CompositorClient final : public ThreadedCompositor::Client { + WTF_MAKE_NONCOPYABLE(CompositorClient); + public: + CompositorClient(ThreadedCoordinatedLayerTreeHost& layerTreeHost) + : m_layerTreeHost(layerTreeHost) + { + } + + private: + void renderNextFrame() override + { + m_layerTreeHost.renderNextFrame(); + } + + void commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset) override + { + m_layerTreeHost.commitScrollOffset(layerID, offset); + } + + ThreadedCoordinatedLayerTreeHost& m_layerTreeHost; + }; + + void didChangeViewport(); + + // CompositingCoordinator::Client + void didFlushRootLayer(const WebCore::FloatRect&) override { } + void commitSceneState(const WebCore::CoordinatedGraphicsState&) override; + + enum class DiscardableSyncActions { + UpdateSize = 1 << 1, + UpdateViewport = 1 << 2, + UpdateScale = 1 << 3, + UpdateBackground = 1 << 4 + }; + + CompositorClient m_compositorClient; + std::unique_ptr<AcceleratedSurface> m_surface; + RefPtr<ThreadedCompositor> m_compositor; + SimpleViewportController m_viewportController; + float m_lastPageScaleFactor { 1 }; + WebCore::IntPoint m_lastScrollPosition; + bool m_isDiscardable { false }; + OptionSet<DiscardableSyncActions> m_discardableSyncActions; +}; + +} // namespace WebKit + +#endif // USE(COORDINATED_GRAPHICS_THREADED) + +#endif // ThreadedCoordinatedLayerTreeHost_h diff --git a/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/UpdateAtlas.cpp b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/UpdateAtlas.cpp new file mode 100644 index 000000000..e2c4ffeee --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/UpdateAtlas.cpp @@ -0,0 +1,116 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2012 Company 100, Inc. + + 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" +#include "UpdateAtlas.h" + +#if USE(COORDINATED_GRAPHICS) + +#include <WebCore/CoordinatedGraphicsState.h> +#include <WebCore/GraphicsContext.h> +#include <WebCore/IntRect.h> +#include <wtf/MathExtras.h> + +using namespace WebCore; + +namespace WebKit { + +class UpdateAtlasSurfaceClient final : public CoordinatedSurface::Client { +public: + UpdateAtlasSurfaceClient(CoordinatedSurface::Client& client, const IntSize& size, bool supportsAlpha) + : m_client(client) + , m_size(size) + , m_supportsAlpha(supportsAlpha) + { + } + + void paintToSurfaceContext(GraphicsContext& context) override + { + if (m_supportsAlpha) { + context.setCompositeOperation(CompositeCopy); + context.fillRect(IntRect(IntPoint::zero(), m_size), Color::transparent); + context.setCompositeOperation(CompositeSourceOver); + } + + m_client.paintToSurfaceContext(context); + } + +private: + CoordinatedSurface::Client& m_client; + IntSize m_size; + bool m_supportsAlpha; +}; + +UpdateAtlas::UpdateAtlas(Client& client, int dimension, CoordinatedSurface::Flags flags) + : m_client(client) +{ + static uint32_t nextID = 0; + m_ID = ++nextID; + IntSize size = nextPowerOfTwo(IntSize(dimension, dimension)); + m_surface = CoordinatedSurface::create(size, flags); + + m_client.createUpdateAtlas(m_ID, m_surface.copyRef()); +} + +UpdateAtlas::~UpdateAtlas() +{ + if (m_surface) + m_client.removeUpdateAtlas(m_ID); +} + +void UpdateAtlas::buildLayoutIfNeeded() +{ + if (m_areaAllocator) + return; + m_areaAllocator = std::make_unique<GeneralAreaAllocator>(size()); + m_areaAllocator->setMinimumAllocation(IntSize(32, 32)); +} + +void UpdateAtlas::didSwapBuffers() +{ + m_areaAllocator = nullptr; +} + +bool UpdateAtlas::paintOnAvailableBuffer(const IntSize& size, uint32_t& atlasID, IntPoint& offset, CoordinatedSurface::Client& client) +{ + m_inactivityInSeconds = 0; + buildLayoutIfNeeded(); + IntRect rect = m_areaAllocator->allocate(size); + + // No available buffer was found. + if (rect.isEmpty()) + return false; + + if (!m_surface) + return false; + + atlasID = m_ID; + + // FIXME: Use tri-state buffers, to allow faster updates. + offset = rect.location(); + + UpdateAtlasSurfaceClient surfaceClient(client, size, supportsAlpha()); + m_surface->paintToSurface(rect, surfaceClient); + + return true; +} + +} // namespace WebCore +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/UpdateAtlas.h b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/UpdateAtlas.h new file mode 100644 index 000000000..63f76be95 --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/UpdateAtlas.h @@ -0,0 +1,83 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2012 Company 100, Inc. + + 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. + */ + +#ifndef UpdateAtlas_h +#define UpdateAtlas_h + +#include "AreaAllocator.h" +#include <WebCore/CoordinatedSurface.h> +#include <WebCore/IntSize.h> +#include <wtf/RefPtr.h> + +#if USE(COORDINATED_GRAPHICS) + +namespace WebCore { +class GraphicsContext; +class IntPoint; +} + +namespace WebKit { + +class UpdateAtlas { + WTF_MAKE_NONCOPYABLE(UpdateAtlas); +public: + class Client { + public: + virtual void createUpdateAtlas(uint32_t /* id */, RefPtr<WebCore::CoordinatedSurface>&&) = 0; + virtual void removeUpdateAtlas(uint32_t /* id */) = 0; + }; + + UpdateAtlas(Client&, int dimension, WebCore::CoordinatedSurface::Flags); + ~UpdateAtlas(); + + inline WebCore::IntSize size() const { return m_surface->size(); } + + // Returns false if there is no available buffer. + bool paintOnAvailableBuffer(const WebCore::IntSize&, uint32_t& atlasID, WebCore::IntPoint& offset, WebCore::CoordinatedSurface::Client&); + void didSwapBuffers(); + bool supportsAlpha() const { return m_surface->supportsAlpha(); } + + void addTimeInactive(double seconds) + { + ASSERT(!isInUse()); + m_inactivityInSeconds += seconds; + } + bool isInactive() const + { + const double inactiveSecondsTolerance = 3; + return m_inactivityInSeconds > inactiveSecondsTolerance; + } + bool isInUse() const { return !!m_areaAllocator; } + +private: + void buildLayoutIfNeeded(); + +private: + Client& m_client; + std::unique_ptr<GeneralAreaAllocator> m_areaAllocator; + RefPtr<WebCore::CoordinatedSurface> m_surface; + double m_inactivityInSeconds { 0 }; + uint32_t m_ID { 0 }; +}; + +} // namespace WebKit + +#endif // USE(COORDINATED_GRAPHICS) +#endif // UpdateAtlas_h |