blob: b38faaad6fc3ad1f18e146c67a0b12e3ae8f30a5 [file] [log] [blame]
/*
* Copyright (C) 2012 Apple 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.
*/
#import "config.h"
#import "RemoteLayerTreeHost.h"
#import "RemoteLayerTreeDrawingAreaProxy.h"
#import "RemoteLayerTreePropertyApplier.h"
#import "RemoteLayerTreeTransaction.h"
#import "ShareableBitmap.h"
#import "WebPageProxy.h"
#import "WebProcessProxy.h"
#import <QuartzCore/QuartzCore.h>
#import <WebCore/PlatformLayer.h>
#import <WebCore/WebActionDisablingCALayerDelegate.h>
#import <WebKitSystemInterface.h>
#if PLATFORM(IOS)
#import <UIKit/UIView.h>
#endif
using namespace WebCore;
namespace WebKit {
RemoteLayerTreeHost::RemoteLayerTreeHost(RemoteLayerTreeDrawingAreaProxy& drawingArea)
: m_drawingArea(drawingArea)
, m_rootLayer(nullptr)
, m_isDebugLayerTreeHost(false)
{
}
RemoteLayerTreeHost::~RemoteLayerTreeHost()
{
for (auto& delegate : m_animationDelegates.values())
[delegate.get() invalidate];
clearLayers();
}
bool RemoteLayerTreeHost::updateLayerTree(const RemoteLayerTreeTransaction& transaction, float indicatorScaleFactor)
{
for (const auto& createdLayer : transaction.createdLayers()) {
const RemoteLayerTreeTransaction::LayerProperties* properties = transaction.changedLayerProperties().get(createdLayer.layerID);
createLayer(createdLayer, properties);
}
bool rootLayerChanged = false;
LayerOrView *rootLayer = getLayer(transaction.rootLayerID());
if (m_rootLayer != rootLayer) {
m_rootLayer = rootLayer;
rootLayerChanged = true;
}
typedef std::pair<GraphicsLayer::PlatformLayerID, GraphicsLayer::PlatformLayerID> LayerIDPair;
Vector<LayerIDPair> clonesToUpdate;
for (auto& changedLayer : transaction.changedLayerProperties()) {
auto layerID = changedLayer.key;
const RemoteLayerTreeTransaction::LayerProperties& properties = *changedLayer.value;
LayerOrView *layer = getLayer(layerID);
ASSERT(layer);
RemoteLayerTreePropertyApplier::RelatedLayerMap relatedLayers;
if (properties.changedProperties & RemoteLayerTreeTransaction::ChildrenChanged) {
for (auto& child : properties.children)
relatedLayers.set(child, getLayer(child));
}
if (properties.changedProperties & RemoteLayerTreeTransaction::MaskLayerChanged && properties.maskLayerID)
relatedLayers.set(properties.maskLayerID, getLayer(properties.maskLayerID));
if (properties.changedProperties & RemoteLayerTreeTransaction::ClonedContentsChanged && properties.clonedLayerID)
clonesToUpdate.append(LayerIDPair(layerID, properties.clonedLayerID));
if (m_isDebugLayerTreeHost) {
RemoteLayerTreePropertyApplier::applyProperties(layer, this, properties, relatedLayers);
if (properties.changedProperties & RemoteLayerTreeTransaction::BorderWidthChanged)
asLayer(layer).borderWidth = properties.borderWidth / indicatorScaleFactor;
asLayer(layer).masksToBounds = false;
} else
RemoteLayerTreePropertyApplier::applyProperties(layer, this, properties, relatedLayers);
}
for (const auto& layerPair : clonesToUpdate) {
LayerOrView *layer = getLayer(layerPair.first);
LayerOrView *clonedLayer = getLayer(layerPair.second);
asLayer(layer).contents = asLayer(clonedLayer).contents;
}
for (auto& destroyedLayer : transaction.destroyedLayers())
layerWillBeRemoved(destroyedLayer);
// Drop the contents of any layers which were unparented; the Web process will re-send
// the backing store in the commit that reparents them.
for (auto& newlyUnreachableLayerID : transaction.layerIDsWithNewlyUnreachableBackingStore())
asLayer(getLayer(newlyUnreachableLayerID)).contents = nullptr;
return rootLayerChanged;
}
LayerOrView *RemoteLayerTreeHost::getLayer(GraphicsLayer::PlatformLayerID layerID) const
{
if (!layerID)
return nil;
return m_layers.get(layerID).get();
}
void RemoteLayerTreeHost::layerWillBeRemoved(WebCore::GraphicsLayer::PlatformLayerID layerID)
{
auto iter = m_animationDelegates.find(layerID);
if (iter != m_animationDelegates.end()) {
[iter->value invalidate];
m_animationDelegates.remove(iter);
}
m_layers.remove(layerID);
}
void RemoteLayerTreeHost::animationDidStart(WebCore::GraphicsLayer::PlatformLayerID layerID, CAAnimation *animation, double startTime)
{
CALayer *layer = asLayer(getLayer(layerID));
if (!layer)
return;
String animationKey;
for (NSString *key in [layer animationKeys]) {
if ([layer animationForKey:key] == animation) {
animationKey = key;
break;
}
}
if (!animationKey.isEmpty())
m_drawingArea.acceleratedAnimationDidStart(layerID, animationKey, startTime);
}
void RemoteLayerTreeHost::animationDidEnd(WebCore::GraphicsLayer::PlatformLayerID layerID, CAAnimation *animation)
{
CALayer *layer = asLayer(getLayer(layerID));
if (!layer)
return;
String animationKey;
for (NSString *key in [layer animationKeys]) {
if ([layer animationForKey:key] == animation) {
animationKey = key;
break;
}
}
if (!animationKey.isEmpty())
m_drawingArea.acceleratedAnimationDidEnd(layerID, animationKey);
}
void RemoteLayerTreeHost::clearLayers()
{
for (auto& idLayer : m_layers) {
m_animationDelegates.remove(idLayer.key);
#if PLATFORM(IOS)
[idLayer.value.get() removeFromSuperview];
#else
[asLayer(idLayer.value.get()) removeFromSuperlayer];
#endif
}
m_layers.clear();
if (m_rootLayer)
m_rootLayer = nullptr;
}
static NSString* const WKLayerIDPropertyKey = @"WKLayerID";
void RemoteLayerTreeHost::setLayerID(CALayer *layer, WebCore::GraphicsLayer::PlatformLayerID layerID)
{
[layer setValue:[NSNumber numberWithUnsignedLongLong:layerID] forKey:WKLayerIDPropertyKey];
}
WebCore::GraphicsLayer::PlatformLayerID RemoteLayerTreeHost::layerID(CALayer* layer)
{
return [[layer valueForKey:WKLayerIDPropertyKey] unsignedLongLongValue];
}
#if !PLATFORM(IOS)
LayerOrView *RemoteLayerTreeHost::createLayer(const RemoteLayerTreeTransaction::LayerCreationProperties& properties, const RemoteLayerTreeTransaction::LayerProperties*)
{
RetainPtr<CALayer>& layer = m_layers.add(properties.layerID, nullptr).iterator->value;
ASSERT(!layer);
switch (properties.type) {
case PlatformCALayer::LayerTypeLayer:
case PlatformCALayer::LayerTypeWebLayer:
case PlatformCALayer::LayerTypeRootLayer:
case PlatformCALayer::LayerTypeSimpleLayer:
case PlatformCALayer::LayerTypeTiledBackingLayer:
case PlatformCALayer::LayerTypePageTiledBackingLayer:
case PlatformCALayer::LayerTypeTiledBackingTileLayer:
case PlatformCALayer::LayerTypeScrollingLayer:
layer = adoptNS([[CALayer alloc] init]);
break;
case PlatformCALayer::LayerTypeTransformLayer:
layer = adoptNS([[CATransformLayer alloc] init]);
break;
case PlatformCALayer::LayerTypeBackdropLayer:
case PlatformCALayer::LayerTypeLightSystemBackdropLayer:
case PlatformCALayer::LayerTypeDarkSystemBackdropLayer:
#if ENABLE(FILTERS_LEVEL_2)
layer = adoptNS([[CABackdropLayer alloc] init]);
#else
ASSERT_NOT_REACHED();
layer = adoptNS([[CALayer alloc] init]);
#endif
break;
case PlatformCALayer::LayerTypeCustom:
case PlatformCALayer::LayerTypeAVPlayerLayer:
case PlatformCALayer::LayerTypeWebGLLayer:
if (!m_isDebugLayerTreeHost)
layer = WKMakeRenderLayer(properties.hostingContextID);
else
layer = adoptNS([[CALayer alloc] init]);
break;
case PlatformCALayer::LayerTypeShapeLayer:
layer = adoptNS([[CAShapeLayer alloc] init]);
break;
default:
ASSERT_NOT_REACHED();
}
[layer setDelegate:[WebActionDisablingCALayerDelegate shared]];
setLayerID(layer.get(), properties.layerID);
return layer.get();
}
#endif
void RemoteLayerTreeHost::detachRootLayer()
{
#if PLATFORM(IOS)
[m_rootLayer removeFromSuperview];
#else
[asLayer(m_rootLayer) removeFromSuperlayer];
#endif
m_rootLayer = nullptr;
}
} // namespace WebKit