| /* |
| * 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. |
| */ |
| |
| #pragma once |
| |
| #if ENABLE(ASYNC_SCROLLING) |
| |
| #include "GraphicsLayer.h" |
| #include "ScrollingCoordinator.h" |
| #include <stdint.h> |
| #include <wtf/ThreadSafeRefCounted.h> |
| #include <wtf/TypeCasts.h> |
| #include <wtf/Vector.h> |
| |
| namespace WTF { |
| class TextStream; |
| } |
| |
| namespace WebCore { |
| |
| class GraphicsLayer; |
| class ScrollingStateTree; |
| |
| // Used to allow ScrollingStateNodes to refer to layers in various contexts: |
| // a) Async scrolling, main thread: ScrollingStateNode holds onto a GraphicsLayer, and uses m_layerID |
| // to detect whether that GraphicsLayer's underlying PlatformLayer changed. |
| // b) Threaded scrolling, commit to scrolling thread: ScrollingStateNode wraps a PlatformLayer, which |
| // can be passed to the Scrolling Thread |
| // c) Remote scrolling UI process, where LayerRepresentation wraps just a PlatformLayerID. |
| class LayerRepresentation { |
| public: |
| enum Type { |
| EmptyRepresentation, |
| GraphicsLayerRepresentation, |
| PlatformLayerRepresentation, |
| PlatformLayerIDRepresentation |
| }; |
| |
| LayerRepresentation() = default; |
| |
| LayerRepresentation(GraphicsLayer* graphicsLayer) |
| : m_graphicsLayer(graphicsLayer) |
| , m_layerID(graphicsLayer ? graphicsLayer->primaryLayerID() : 0) |
| , m_representation(GraphicsLayerRepresentation) |
| { } |
| |
| LayerRepresentation(PlatformLayer* platformLayer) |
| : m_typelessPlatformLayer(makePlatformLayerTypeless(platformLayer)) |
| , m_representation(PlatformLayerRepresentation) |
| { |
| retainPlatformLayer(m_typelessPlatformLayer); |
| } |
| |
| LayerRepresentation(GraphicsLayer::PlatformLayerID layerID) |
| : m_layerID(layerID) |
| , m_representation(PlatformLayerIDRepresentation) |
| { |
| } |
| |
| LayerRepresentation(const LayerRepresentation& other) |
| : m_typelessPlatformLayer(other.m_typelessPlatformLayer) |
| , m_layerID(other.m_layerID) |
| , m_representation(other.m_representation) |
| { |
| if (m_representation == PlatformLayerRepresentation) |
| retainPlatformLayer(m_typelessPlatformLayer); |
| } |
| |
| ~LayerRepresentation() |
| { |
| if (m_representation == PlatformLayerRepresentation) |
| releasePlatformLayer(m_typelessPlatformLayer); |
| } |
| |
| explicit operator GraphicsLayer*() const |
| { |
| ASSERT(m_representation == GraphicsLayerRepresentation); |
| return m_graphicsLayer.get(); |
| } |
| |
| explicit operator PlatformLayer*() const |
| { |
| ASSERT(m_representation == PlatformLayerRepresentation); |
| return makePlatformLayerTyped(m_typelessPlatformLayer); |
| } |
| |
| GraphicsLayer::PlatformLayerID layerID() const |
| { |
| return m_layerID; |
| } |
| |
| explicit operator GraphicsLayer::PlatformLayerID() const |
| { |
| ASSERT(m_representation != PlatformLayerRepresentation); |
| return m_layerID; |
| } |
| |
| LayerRepresentation& operator=(const LayerRepresentation& other) |
| { |
| m_graphicsLayer = other.m_graphicsLayer; |
| m_typelessPlatformLayer = other.m_typelessPlatformLayer; |
| m_layerID = other.m_layerID; |
| m_representation = other.m_representation; |
| |
| if (m_representation == PlatformLayerRepresentation) |
| retainPlatformLayer(m_typelessPlatformLayer); |
| |
| return *this; |
| } |
| |
| explicit operator bool() const |
| { |
| switch (m_representation) { |
| case EmptyRepresentation: |
| return false; |
| case GraphicsLayerRepresentation: |
| return !!m_graphicsLayer; |
| case PlatformLayerRepresentation: |
| return !!m_typelessPlatformLayer; |
| case PlatformLayerIDRepresentation: |
| return !!m_layerID; |
| } |
| ASSERT_NOT_REACHED(); |
| return false; |
| } |
| |
| bool operator==(const LayerRepresentation& other) const |
| { |
| if (m_representation != other.m_representation) |
| return false; |
| switch (m_representation) { |
| case EmptyRepresentation: |
| return true; |
| case GraphicsLayerRepresentation: |
| return m_graphicsLayer == other.m_graphicsLayer |
| && m_layerID == other.m_layerID; |
| case PlatformLayerRepresentation: |
| return m_typelessPlatformLayer == other.m_typelessPlatformLayer; |
| case PlatformLayerIDRepresentation: |
| return m_layerID == other.m_layerID; |
| } |
| ASSERT_NOT_REACHED(); |
| return true; |
| } |
| |
| LayerRepresentation toRepresentation(Type representation) const |
| { |
| switch (representation) { |
| case EmptyRepresentation: |
| return LayerRepresentation(); |
| case GraphicsLayerRepresentation: |
| ASSERT(m_representation == GraphicsLayerRepresentation); |
| return LayerRepresentation(m_graphicsLayer.get()); |
| case PlatformLayerRepresentation: |
| return m_graphicsLayer ? m_graphicsLayer->platformLayer() : nullptr; |
| case PlatformLayerIDRepresentation: |
| return LayerRepresentation(m_layerID); |
| } |
| ASSERT_NOT_REACHED(); |
| return LayerRepresentation(); |
| } |
| |
| bool representsGraphicsLayer() const { return m_representation == GraphicsLayerRepresentation; } |
| bool representsPlatformLayerID() const { return m_representation == PlatformLayerIDRepresentation; } |
| |
| private: |
| WEBCORE_EXPORT static void retainPlatformLayer(void* typelessPlatformLayer); |
| WEBCORE_EXPORT static void releasePlatformLayer(void* typelessPlatformLayer); |
| WEBCORE_EXPORT static PlatformLayer* makePlatformLayerTyped(void* typelessPlatformLayer); |
| WEBCORE_EXPORT static void* makePlatformLayerTypeless(PlatformLayer*); |
| |
| RefPtr<GraphicsLayer> m_graphicsLayer; |
| void* m_typelessPlatformLayer { nullptr }; |
| GraphicsLayer::PlatformLayerID m_layerID { 0 }; |
| Type m_representation { EmptyRepresentation }; |
| }; |
| |
| class ScrollingStateNode : public ThreadSafeRefCounted<ScrollingStateNode> { |
| WTF_MAKE_FAST_ALLOCATED; |
| public: |
| virtual ~ScrollingStateNode(); |
| |
| ScrollingNodeType nodeType() const { return m_nodeType; } |
| |
| bool isFixedNode() const { return m_nodeType == ScrollingNodeType::Fixed; } |
| bool isStickyNode() const { return m_nodeType == ScrollingNodeType::Sticky; } |
| bool isPositionedNode() const { return m_nodeType == ScrollingNodeType::Positioned; } |
| bool isScrollingNode() const { return isFrameScrollingNode() || isOverflowScrollingNode(); } |
| bool isFrameScrollingNode() const { return m_nodeType == ScrollingNodeType::MainFrame || m_nodeType == ScrollingNodeType::Subframe; } |
| bool isFrameHostingNode() const { return m_nodeType == ScrollingNodeType::FrameHosting; } |
| bool isOverflowScrollingNode() const { return m_nodeType == ScrollingNodeType::Overflow; } |
| bool isOverflowScrollProxyNode() const { return m_nodeType == ScrollingNodeType::OverflowProxy; } |
| |
| virtual Ref<ScrollingStateNode> clone(ScrollingStateTree& adoptiveTree) = 0; |
| Ref<ScrollingStateNode> cloneAndReset(ScrollingStateTree& adoptiveTree); |
| void cloneAndResetChildren(ScrollingStateNode&, ScrollingStateTree& adoptiveTree); |
| |
| enum class Property : uint64_t { |
| // ScrollingStateNode |
| Layer = 1LLU << 0, |
| ChildNodes = 1LLU << 1, |
| // ScrollingStateScrollingNode |
| ScrollableAreaSize = 1LLU << 2, |
| TotalContentsSize = 1LLU << 3, |
| ReachableContentsSize = 1LLU << 4, |
| ScrollPosition = 1LLU << 5, |
| ScrollOrigin = 1LLU << 6, |
| ScrollableAreaParams = 1LLU << 7, |
| ReasonsForSynchronousScrolling = 1LLU << 8, |
| RequestedScrollPosition = 1LLU << 9, |
| SnapOffsetsInfo = 1LLU << 10, |
| CurrentHorizontalSnapOffsetIndex = 1LLU << 11, |
| CurrentVerticalSnapOffsetIndex = 1LLU << 12, |
| IsMonitoringWheelEvents = 1LLU << 13, |
| ScrollContainerLayer = 1LLU << 14, |
| ScrolledContentsLayer = 1LLU << 15, |
| HorizontalScrollbarLayer = 1LLU << 16, |
| VerticalScrollbarLayer = 1LLU << 17, |
| PainterForScrollbar = 1LLU << 18, |
| // ScrollingStateFrameScrollingNode |
| FrameScaleFactor = 1LLU << 19, |
| EventTrackingRegion = 1LLU << 20, |
| RootContentsLayer = 1LLU << 21, |
| CounterScrollingLayer = 1LLU << 22, |
| InsetClipLayer = 1LLU << 23, |
| ContentShadowLayer = 1LLU << 24, |
| HeaderHeight = 1LLU << 25, |
| FooterHeight = 1LLU << 26, |
| HeaderLayer = 1LLU << 27, |
| FooterLayer = 1LLU << 28, |
| BehaviorForFixedElements = 1LLU << 29, |
| TopContentInset = 1LLU << 30, |
| FixedElementsLayoutRelativeToFrame = 1LLU << 31, |
| VisualViewportIsSmallerThanLayoutViewport = 1LLU << 32, |
| AsyncFrameOrOverflowScrollingEnabled = 1LLU << 33, |
| WheelEventGesturesBecomeNonBlocking = 1LLU << 34, |
| ScrollingPerformanceTestingEnabled = 1LLU << 35, |
| LayoutViewport = 1LLU << 36, |
| MinLayoutViewportOrigin = 1LLU << 37, |
| MaxLayoutViewportOrigin = 1LLU << 38, |
| OverrideVisualViewportSize = 1LLU << 39, |
| // ScrollingStatePositionedNode |
| RelatedOverflowScrollingNodes = 1LLU << 40, |
| LayoutConstraintData = 1LLU << 41, |
| // ScrollingStateFixedNode, ScrollingStateStickyNode |
| ViewportConstraints = 1LLU << 42, |
| // ScrollingStateOverflowScrollProxyNode |
| OverflowScrollingNode = 1LLU << 43, |
| }; |
| |
| bool hasChangedProperties() const { return !m_changedProperties.isEmpty(); } |
| bool hasChangedProperty(Property property) const { return m_changedProperties.contains(property); } |
| void resetChangedProperties() { m_changedProperties = { }; } |
| void setPropertyChanged(Property); |
| |
| virtual void setPropertyChangesAfterReattach(); |
| |
| OptionSet<Property> changedProperties() const { return m_changedProperties; } |
| void setChangedProperties(OptionSet<Property> changedProperties) { m_changedProperties = changedProperties; } |
| |
| virtual void reconcileLayerPositionForViewportRect(const LayoutRect& /*viewportRect*/, ScrollingLayerPositionAction) { } |
| |
| const LayerRepresentation& layer() const { return m_layer; } |
| WEBCORE_EXPORT void setLayer(const LayerRepresentation&); |
| |
| ScrollingStateTree& scrollingStateTree() const { return m_scrollingStateTree; } |
| |
| ScrollingNodeID scrollingNodeID() const { return m_nodeID; } |
| |
| ScrollingStateNode* parent() const { return m_parent; } |
| void setParent(ScrollingStateNode* parent) { m_parent = parent; } |
| ScrollingNodeID parentNodeID() const { return m_parent ? m_parent->scrollingNodeID() : 0; } |
| |
| Vector<RefPtr<ScrollingStateNode>>* children() const { return m_children.get(); } |
| std::unique_ptr<Vector<RefPtr<ScrollingStateNode>>> takeChildren() { return WTFMove(m_children); } |
| |
| void appendChild(Ref<ScrollingStateNode>&&); |
| void insertChild(Ref<ScrollingStateNode>&&, size_t index); |
| |
| // Note that node ownership is via the parent, so these functions can trigger node deletion. |
| void removeFromParent(); |
| void removeChildAtIndex(size_t index); |
| void removeChild(ScrollingStateNode&); |
| |
| size_t indexOfChild(ScrollingStateNode&) const; |
| |
| String scrollingStateTreeAsText(OptionSet<ScrollingStateTreeAsTextBehavior> = { }) const; |
| |
| protected: |
| ScrollingStateNode(const ScrollingStateNode&, ScrollingStateTree&); |
| ScrollingStateNode(ScrollingNodeType, ScrollingStateTree&, ScrollingNodeID); |
| |
| void setPropertyChangedInternal(Property property) { m_changedProperties.add(property); } |
| void setPropertiesChangedInternal(OptionSet<Property> properties) { m_changedProperties.add(properties); } |
| |
| virtual void dumpProperties(WTF::TextStream&, OptionSet<ScrollingStateTreeAsTextBehavior>) const; |
| virtual OptionSet<Property> applicableProperties() const; |
| |
| private: |
| void dump(WTF::TextStream&, OptionSet<ScrollingStateTreeAsTextBehavior>) const; |
| |
| const ScrollingNodeType m_nodeType; |
| const ScrollingNodeID m_nodeID; |
| OptionSet<Property> m_changedProperties; |
| |
| ScrollingStateTree& m_scrollingStateTree; |
| |
| ScrollingStateNode* m_parent { nullptr }; |
| std::unique_ptr<Vector<RefPtr<ScrollingStateNode>>> m_children; |
| |
| LayerRepresentation m_layer; |
| }; |
| |
| } // namespace WebCore |
| |
| #define SPECIALIZE_TYPE_TRAITS_SCROLLING_STATE_NODE(ToValueTypeName, predicate) \ |
| SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ToValueTypeName) \ |
| static bool isType(const WebCore::ScrollingStateNode& node) { return node.predicate; } \ |
| SPECIALIZE_TYPE_TRAITS_END() |
| |
| #endif // ENABLE(ASYNC_SCROLLING) |