/* * Copyright (C) 2014-2015 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. */ #include "config.h" #include "RemoteScrollingCoordinatorTransaction.h" #include "ArgumentCoders.h" #include "MessageDecoder.h" #include "MessageEncoder.h" #include "WebCoreArgumentCoders.h" #include #include #include #include #include #include #include #include #include #include using namespace WebCore; #if ENABLE(ASYNC_SCROLLING) namespace IPC { template<> struct ArgumentCoder { static void encode(ArgumentEncoder&, const ScrollingStateNode&); static bool decode(ArgumentDecoder&, ScrollingStateNode&); }; template<> struct ArgumentCoder { static void encode(ArgumentEncoder&, const ScrollingStateScrollingNode&); static bool decode(ArgumentDecoder&, ScrollingStateScrollingNode&); }; template<> struct ArgumentCoder { static void encode(ArgumentEncoder&, const ScrollingStateFrameScrollingNode&); static bool decode(ArgumentDecoder&, ScrollingStateFrameScrollingNode&); }; template<> struct ArgumentCoder { static void encode(ArgumentEncoder&, const ScrollingStateOverflowScrollingNode&); static bool decode(ArgumentDecoder&, ScrollingStateOverflowScrollingNode&); }; template<> struct ArgumentCoder { static void encode(ArgumentEncoder&, const ScrollingStateFixedNode&); static bool decode(ArgumentDecoder&, ScrollingStateFixedNode&); }; template<> struct ArgumentCoder { static void encode(ArgumentEncoder&, const ScrollingStateStickyNode&); static bool decode(ArgumentDecoder&, ScrollingStateStickyNode&); }; } // namespace IPC using namespace IPC; void ArgumentCoder::encode(ArgumentEncoder& encoder, const ScrollingStateNode& node) { encoder.encodeEnum(node.nodeType()); encoder << node.scrollingNodeID(); encoder << node.parentNodeID(); encoder << node.changedProperties(); if (node.hasChangedProperty(ScrollingStateNode::ScrollLayer)) encoder << static_cast(node.layer()); } bool ArgumentCoder::decode(ArgumentDecoder& decoder, ScrollingStateNode& node) { // nodeType, scrollingNodeID and parentNodeID have already been decoded by the caller in order to create the node. ScrollingStateNode::ChangedProperties changedProperties; if (!decoder.decode(changedProperties)) return false; node.setChangedProperties(changedProperties); if (node.hasChangedProperty(ScrollingStateNode::ScrollLayer)) { GraphicsLayer::PlatformLayerID layerID; if (!decoder.decode(layerID)) return false; node.setLayer(layerID); } return true; } #define SCROLLING_NODE_ENCODE(property, getter) \ if (node.hasChangedProperty(property)) \ encoder << node.getter(); #define SCROLLING_NODE_ENCODE_ENUM(property, getter) \ if (node.hasChangedProperty(property)) \ encoder.encodeEnum(node.getter()); void ArgumentCoder::encode(ArgumentEncoder& encoder, const ScrollingStateScrollingNode& node) { encoder << static_cast(node); SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ScrollableAreaSize, scrollableAreaSize) SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::TotalContentsSize, totalContentsSize) SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ReachableContentsSize, reachableContentsSize) SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ScrollPosition, scrollPosition) SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ScrollOrigin, scrollOrigin) #if ENABLE(CSS_SCROLL_SNAP) SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::HorizontalSnapOffsets, horizontalSnapOffsets) SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::VerticalSnapOffsets, verticalSnapOffsets) SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::CurrentHorizontalSnapOffsetIndex, currentHorizontalSnapPointIndex) SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::CurrentVerticalSnapOffsetIndex, currentVerticalSnapPointIndex) #endif SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ScrollableAreaParams, scrollableAreaParameters) SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::RequestedScrollPosition, requestedScrollPosition) SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::RequestedScrollPosition, requestedScrollPositionRepresentsProgrammaticScroll) } void ArgumentCoder::encode(ArgumentEncoder& encoder, const ScrollingStateFrameScrollingNode& node) { encoder << static_cast(node); SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::FrameScaleFactor, frameScaleFactor) SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::NonFastScrollableRegion, nonFastScrollableRegion) SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::ReasonsForSynchronousScrolling, synchronousScrollingReasons) SCROLLING_NODE_ENCODE_ENUM(ScrollingStateFrameScrollingNode::BehaviorForFixedElements, scrollBehaviorForFixedElements) SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::HeaderHeight, headerHeight) SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::FooterHeight, footerHeight) SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::TopContentInset, topContentInset) SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::FixedElementsLayoutRelativeToFrame, fixedElementsLayoutRelativeToFrame) if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::ScrolledContentsLayer)) encoder << static_cast(node.scrolledContentsLayer()); if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::CounterScrollingLayer)) encoder << static_cast(node.counterScrollingLayer()); if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::InsetClipLayer)) encoder << static_cast(node.insetClipLayer()); if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::ContentShadowLayer)) encoder << static_cast(node.contentShadowLayer()); } void ArgumentCoder::encode(ArgumentEncoder& encoder, const ScrollingStateOverflowScrollingNode& node) { encoder << static_cast(node); if (node.hasChangedProperty(ScrollingStateOverflowScrollingNode::ScrolledContentsLayer)) encoder << static_cast(node.scrolledContentsLayer()); } #define SCROLLING_NODE_DECODE(property, type, setter) \ if (node.hasChangedProperty(property)) { \ type decodedValue; \ if (!decoder.decode(decodedValue)) \ return false; \ node.setter(decodedValue); \ } #define SCROLLING_NODE_DECODE_ENUM(property, type, setter) \ if (node.hasChangedProperty(property)) { \ type decodedValue; \ if (!decoder.decodeEnum(decodedValue)) \ return false; \ node.setter(decodedValue); \ } bool ArgumentCoder::decode(ArgumentDecoder& decoder, ScrollingStateScrollingNode& node) { if (!decoder.decode(static_cast(node))) return false; SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ScrollableAreaSize, FloatSize, setScrollableAreaSize); SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::TotalContentsSize, FloatSize, setTotalContentsSize); SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ReachableContentsSize, FloatSize, setReachableContentsSize); SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ScrollPosition, FloatPoint, setScrollPosition); SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ScrollOrigin, IntPoint, setScrollOrigin); #if ENABLE(CSS_SCROLL_SNAP) SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::HorizontalSnapOffsets, Vector, setHorizontalSnapOffsets); SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::VerticalSnapOffsets, Vector, setVerticalSnapOffsets); SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::CurrentHorizontalSnapOffsetIndex, unsigned, setCurrentHorizontalSnapPointIndex); SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::CurrentVerticalSnapOffsetIndex, unsigned, setCurrentVerticalSnapPointIndex); #endif SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ScrollableAreaParams, ScrollableAreaParameters, setScrollableAreaParameters); if (node.hasChangedProperty(ScrollingStateScrollingNode::RequestedScrollPosition)) { FloatPoint scrollPosition; if (!decoder.decode(scrollPosition)) return false; bool representsProgrammaticScroll; if (!decoder.decode(representsProgrammaticScroll)) return false; node.setRequestedScrollPosition(scrollPosition, representsProgrammaticScroll); } return true; } bool ArgumentCoder::decode(ArgumentDecoder& decoder, ScrollingStateFrameScrollingNode& node) { if (!decoder.decode(static_cast(node))) return false; SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::FrameScaleFactor, float, setFrameScaleFactor); SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::NonFastScrollableRegion, Region, setNonFastScrollableRegion); SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::ReasonsForSynchronousScrolling, SynchronousScrollingReasons, setSynchronousScrollingReasons); SCROLLING_NODE_DECODE_ENUM(ScrollingStateFrameScrollingNode::BehaviorForFixedElements, ScrollBehaviorForFixedElements, setScrollBehaviorForFixedElements); SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::HeaderHeight, int, setHeaderHeight); SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::FooterHeight, int, setFooterHeight); SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::TopContentInset, float, setTopContentInset); SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::FixedElementsLayoutRelativeToFrame, bool, setFixedElementsLayoutRelativeToFrame); if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::ScrolledContentsLayer)) { GraphicsLayer::PlatformLayerID layerID; if (!decoder.decode(layerID)) return false; node.setScrolledContentsLayer(layerID); } if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::CounterScrollingLayer)) { GraphicsLayer::PlatformLayerID layerID; if (!decoder.decode(layerID)) return false; node.setCounterScrollingLayer(layerID); } if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::InsetClipLayer)) { GraphicsLayer::PlatformLayerID layerID; if (!decoder.decode(layerID)) return false; node.setInsetClipLayer(layerID); } if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::ContentShadowLayer)) { GraphicsLayer::PlatformLayerID layerID; if (!decoder.decode(layerID)) return false; node.setContentShadowLayer(layerID); } return true; } bool ArgumentCoder::decode(ArgumentDecoder& decoder, ScrollingStateOverflowScrollingNode& node) { if (!decoder.decode(static_cast(node))) return false; if (node.hasChangedProperty(ScrollingStateOverflowScrollingNode::ScrolledContentsLayer)) { GraphicsLayer::PlatformLayerID layerID; if (!decoder.decode(layerID)) return false; node.setScrolledContentsLayer(layerID); } return true; } void ArgumentCoder::encode(ArgumentEncoder& encoder, const ScrollingStateFixedNode& node) { encoder << static_cast(node); if (node.hasChangedProperty(ScrollingStateFixedNode::ViewportConstraints)) encoder << node.viewportConstraints(); } bool ArgumentCoder::decode(ArgumentDecoder& decoder, ScrollingStateFixedNode& node) { if (!decoder.decode(static_cast(node))) return false; if (node.hasChangedProperty(ScrollingStateFixedNode::ViewportConstraints)) { FixedPositionViewportConstraints decodedValue; if (!decoder.decode(decodedValue)) return false; node.updateConstraints(decodedValue); } return true; } void ArgumentCoder::encode(ArgumentEncoder& encoder, const ScrollingStateStickyNode& node) { encoder << static_cast(node); if (node.hasChangedProperty(ScrollingStateStickyNode::ViewportConstraints)) encoder << node.viewportConstraints(); } bool ArgumentCoder::decode(ArgumentDecoder& decoder, ScrollingStateStickyNode& node) { if (!decoder.decode(static_cast(node))) return false; if (node.hasChangedProperty(ScrollingStateStickyNode::ViewportConstraints)) { StickyPositionViewportConstraints decodedValue; if (!decoder.decode(decodedValue)) return false; node.updateConstraints(decodedValue); } return true; } namespace WebKit { static void encodeNodeAndDescendants(IPC::ArgumentEncoder& encoder, const ScrollingStateNode& stateNode, int& encodedNodeCount) { ++encodedNodeCount; switch (stateNode.nodeType()) { case FrameScrollingNode: encoder << downcast(stateNode); break; case OverflowScrollingNode: encoder << downcast(stateNode); break; case FixedNode: encoder << downcast(stateNode); break; case StickyNode: encoder << downcast(stateNode); break; } if (!stateNode.children()) return; for (const auto& child : *stateNode.children()) encodeNodeAndDescendants(encoder, *child.get(), encodedNodeCount); } void RemoteScrollingCoordinatorTransaction::encode(IPC::ArgumentEncoder& encoder) const { int numNodes = m_scrollingStateTree ? m_scrollingStateTree->nodeCount() : 0; encoder << numNodes; bool hasNewRootNode = m_scrollingStateTree ? m_scrollingStateTree->hasNewRootStateNode() : false; encoder << hasNewRootNode; if (m_scrollingStateTree) { encoder << m_scrollingStateTree->hasChangedProperties(); int numNodesEncoded = 0; if (const ScrollingStateNode* rootNode = m_scrollingStateTree->rootStateNode()) encodeNodeAndDescendants(encoder, *rootNode, numNodesEncoded); ASSERT_UNUSED(numNodesEncoded, numNodesEncoded == numNodes); encoder << m_scrollingStateTree->removedNodes(); } else encoder << Vector(); } bool RemoteScrollingCoordinatorTransaction::decode(IPC::ArgumentDecoder& decoder, RemoteScrollingCoordinatorTransaction& transaction) { return transaction.decode(decoder); } bool RemoteScrollingCoordinatorTransaction::decode(IPC::ArgumentDecoder& decoder) { int numNodes; if (!decoder.decode(numNodes)) return false; bool hasNewRootNode; if (!decoder.decode(hasNewRootNode)) return false; m_scrollingStateTree = std::make_unique(); bool hasChangedProperties; if (!decoder.decode(hasChangedProperties)) return false; m_scrollingStateTree->setHasChangedProperties(hasChangedProperties); for (int i = 0; i < numNodes; ++i) { ScrollingNodeType nodeType; if (!decoder.decodeEnum(nodeType)) return false; ScrollingNodeID nodeID; if (!decoder.decode(nodeID)) return false; ScrollingNodeID parentNodeID; if (!decoder.decode(parentNodeID)) return false; m_scrollingStateTree->attachNode(nodeType, nodeID, parentNodeID); ScrollingStateNode* newNode = m_scrollingStateTree->stateNodeForID(nodeID); ASSERT(newNode); ASSERT(!parentNodeID || newNode->parent()); switch (nodeType) { case FrameScrollingNode: if (!decoder.decode(downcast(*newNode))) return false; break; case OverflowScrollingNode: if (!decoder.decode(downcast(*newNode))) return false; break; case FixedNode: if (!decoder.decode(downcast(*newNode))) return false; break; case StickyNode: if (!decoder.decode(downcast(*newNode))) return false; break; } } m_scrollingStateTree->setHasNewRootStateNode(hasNewRootNode); // Removed nodes HashSet removedNodes; if (!decoder.decode(removedNodes)) return false; if (removedNodes.size()) m_scrollingStateTree->setRemovedNodes(removedNodes); return true; } #if !defined(NDEBUG) || !LOG_DISABLED static void dump(TextStream& ts, const ScrollingStateScrollingNode& node, bool changedPropertiesOnly) { if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::ScrollableAreaSize)) ts.dumpProperty("scrollable-area-size", node.scrollableAreaSize()); if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::TotalContentsSize)) ts.dumpProperty("total-contents-size", node.totalContentsSize()); if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::ReachableContentsSize)) ts.dumpProperty("reachable-contents-size", node.reachableContentsSize()); if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::ScrollPosition)) ts.dumpProperty("scroll-position", node.scrollPosition()); if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::ScrollOrigin)) ts.dumpProperty("scroll-origin", node.scrollOrigin()); if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::RequestedScrollPosition)) { ts.dumpProperty("requested-scroll-position", node.requestedScrollPosition()); ts.dumpProperty("requested-scroll-position-is-programatic", node.requestedScrollPositionRepresentsProgrammaticScroll()); } } static void dump(TextStream& ts, const ScrollingStateFrameScrollingNode& node, bool changedPropertiesOnly) { dump(ts, static_cast(node), changedPropertiesOnly); if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::FrameScaleFactor)) ts.dumpProperty("frame-scale-factor", node.frameScaleFactor()); if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::NonFastScrollableRegion)) { TextStream::GroupScope group(ts); ts << "non-fast-scrollable-region"; for (auto rect : node.nonFastScrollableRegion().rects()) { ts << "\n"; ts.writeIndent(); ts << rect; } } // FIXME: dump synchronousScrollingReasons // FIXME: dump scrollableAreaParameters // FIXME: dump scrollBehaviorForFixedElements if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::HeaderHeight)) ts.dumpProperty("header-height", node.headerHeight()); if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::FooterHeight)) ts.dumpProperty("footer-height", node.footerHeight()); if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::TopContentInset)) ts.dumpProperty("top-content-inset", node.topContentInset()); if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::FrameScaleFactor)) ts.dumpProperty("frame-scale-factor", node.frameScaleFactor()); if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::ScrolledContentsLayer)) ts.dumpProperty("scrolled-contents-layer", static_cast(node.scrolledContentsLayer())); if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::InsetClipLayer)) ts.dumpProperty("clip-inset-layer", static_cast(node.insetClipLayer())); if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::ContentShadowLayer)) ts.dumpProperty("content-shadow-layer", static_cast(node.contentShadowLayer())); if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::HeaderLayer)) ts.dumpProperty("header-layer", static_cast(node.headerLayer())); if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::FooterLayer)) ts.dumpProperty("footer-layer", static_cast(node.footerLayer())); } static void dump(TextStream& ts, const ScrollingStateOverflowScrollingNode& node, bool changedPropertiesOnly) { dump(ts, static_cast(node), changedPropertiesOnly); if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateOverflowScrollingNode::ScrolledContentsLayer)) ts.dumpProperty("scrolled-contents-layer", static_cast(node.scrolledContentsLayer())); } static void dump(TextStream& ts, const ScrollingStateFixedNode& node, bool changedPropertiesOnly) { if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFixedNode::ViewportConstraints)) ts << node.viewportConstraints(); } static void dump(TextStream& ts, const ScrollingStateStickyNode& node, bool changedPropertiesOnly) { if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFixedNode::ViewportConstraints)) ts << node.viewportConstraints(); } static void dump(TextStream& ts, const ScrollingStateNode& node, bool changedPropertiesOnly) { ts.dumpProperty("type", node.nodeType()); if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateNode::ScrollLayer)) ts.dumpProperty("layer", static_cast(node.layer())); switch (node.nodeType()) { case FrameScrollingNode: dump(ts, downcast(node), changedPropertiesOnly); break; case OverflowScrollingNode: dump(ts, downcast(node), changedPropertiesOnly); break; case FixedNode: dump(ts, downcast(node), changedPropertiesOnly); break; case StickyNode: dump(ts, downcast(node), changedPropertiesOnly); break; } } static void recursiveDumpNodes(TextStream& ts, const ScrollingStateNode& node, bool changedPropertiesOnly) { TextStream::GroupScope group(ts); ts << "node " << node.scrollingNodeID(); dump(ts, node, changedPropertiesOnly); if (node.children()) { TextStream::GroupScope group(ts); ts << "children"; for (auto& childNode : *node.children()) recursiveDumpNodes(ts, *childNode, changedPropertiesOnly); } } static void dump(TextStream& ts, const ScrollingStateTree& stateTree, bool changedPropertiesOnly) { ts.dumpProperty("has changed properties", stateTree.hasChangedProperties()); ts.dumpProperty("has new root node", stateTree.hasNewRootStateNode()); if (stateTree.rootStateNode()) recursiveDumpNodes(ts, *stateTree.rootStateNode(), changedPropertiesOnly); if (!stateTree.removedNodes().isEmpty()) { Vector removedNodes; copyToVector(stateTree.removedNodes(), removedNodes); ts.dumpProperty>("removed-nodes", removedNodes); } } WTF::CString RemoteScrollingCoordinatorTransaction::description() const { TextStream ts; ts.startGroup(); ts << "scrolling state tree"; if (m_scrollingStateTree) { if (!m_scrollingStateTree->hasChangedProperties()) ts << " - no changes"; else WebKit::dump(ts, *m_scrollingStateTree.get(), true); } else ts << " - none"; ts.endGroup(); return ts.release().utf8(); } void RemoteScrollingCoordinatorTransaction::dump() const { fprintf(stderr, "%s", description().data()); } #endif } // namespace WebKit #else // !ENABLE(ASYNC_SCROLLING) namespace WebKit { void RemoteScrollingCoordinatorTransaction::encode(IPC::ArgumentEncoder&) const { } bool RemoteScrollingCoordinatorTransaction::decode(IPC::ArgumentDecoder& decoder, RemoteScrollingCoordinatorTransaction& transaction) { return true; } } // namespace WebKit #endif // ENABLE(ASYNC_SCROLLING)