1/*
2 * Copyright (C) 2014 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "RemoteScrollingCoordinatorTransaction.h"
28
29#include "ArgumentCoders.h"
30#include "MessageDecoder.h"
31#include "MessageEncoder.h"
32#include "WebCoreArgumentCoders.h"
33#include <WebCore/GraphicsLayer.h>
34#include <WebCore/ScrollingStateFixedNode.h>
35#include <WebCore/ScrollingStateFrameScrollingNode.h>
36#include <WebCore/ScrollingStateOverflowScrollingNode.h>
37#include <WebCore/ScrollingStateStickyNode.h>
38#include <WebCore/ScrollingStateTree.h>
39#include <WebCore/TextStream.h>
40#include <wtf/text/CString.h>
41#include <wtf/text/StringBuilder.h>
42
43#include <wtf/HashMap.h>
44
45using namespace WebCore;
46
47#if ENABLE(ASYNC_SCROLLING)
48
49namespace IPC {
50
51template<> struct ArgumentCoder<ScrollingStateNode> {
52    static void encode(ArgumentEncoder&, const ScrollingStateNode&);
53    static bool decode(ArgumentDecoder&, ScrollingStateNode&);
54};
55
56template<> struct ArgumentCoder<ScrollingStateScrollingNode> {
57    static void encode(ArgumentEncoder&, const ScrollingStateScrollingNode&);
58    static bool decode(ArgumentDecoder&, ScrollingStateScrollingNode&);
59};
60
61template<> struct ArgumentCoder<ScrollingStateFrameScrollingNode> {
62    static void encode(ArgumentEncoder&, const ScrollingStateFrameScrollingNode&);
63    static bool decode(ArgumentDecoder&, ScrollingStateFrameScrollingNode&);
64};
65
66template<> struct ArgumentCoder<ScrollingStateOverflowScrollingNode> {
67    static void encode(ArgumentEncoder&, const ScrollingStateOverflowScrollingNode&);
68    static bool decode(ArgumentDecoder&, ScrollingStateOverflowScrollingNode&);
69};
70
71template<> struct ArgumentCoder<ScrollingStateFixedNode> {
72    static void encode(ArgumentEncoder&, const ScrollingStateFixedNode&);
73    static bool decode(ArgumentDecoder&, ScrollingStateFixedNode&);
74};
75
76template<> struct ArgumentCoder<ScrollingStateStickyNode> {
77    static void encode(ArgumentEncoder&, const ScrollingStateStickyNode&);
78    static bool decode(ArgumentDecoder&, ScrollingStateStickyNode&);
79};
80
81} // namespace IPC
82
83using namespace IPC;
84
85void ArgumentCoder<ScrollingStateNode>::encode(ArgumentEncoder& encoder, const ScrollingStateNode& node)
86{
87    encoder.encodeEnum(node.nodeType());
88    encoder << node.scrollingNodeID();
89    encoder << node.parentNodeID();
90    encoder << node.changedProperties();
91
92    if (node.hasChangedProperty(ScrollingStateNode::ScrollLayer))
93        encoder << static_cast<GraphicsLayer::PlatformLayerID>(node.layer());
94}
95
96bool ArgumentCoder<ScrollingStateNode>::decode(ArgumentDecoder& decoder, ScrollingStateNode& node)
97{
98    // nodeType, scrollingNodeID and parentNodeID have already been decoded by the caller in order to create the node.
99    ScrollingStateNode::ChangedProperties changedProperties;
100    if (!decoder.decode(changedProperties))
101        return false;
102
103    node.setChangedProperties(changedProperties);
104    if (node.hasChangedProperty(ScrollingStateNode::ScrollLayer)) {
105        GraphicsLayer::PlatformLayerID layerID;
106        if (!decoder.decode(layerID))
107            return false;
108        node.setLayer(layerID);
109    }
110
111    return true;
112}
113
114#define SCROLLING_NODE_ENCODE(property, getter) \
115    if (node.hasChangedProperty(property)) \
116        encoder << node.getter();
117
118#define SCROLLING_NODE_ENCODE_ENUM(property, getter) \
119    if (node.hasChangedProperty(property)) \
120        encoder.encodeEnum(node.getter());
121
122void ArgumentCoder<ScrollingStateScrollingNode>::encode(ArgumentEncoder& encoder, const ScrollingStateScrollingNode& node)
123{
124    encoder << static_cast<const ScrollingStateNode&>(node);
125
126    SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ScrollableAreaSize, scrollableAreaSize)
127    SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::TotalContentsSize, totalContentsSize)
128    SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ReachableContentsSize, reachableContentsSize)
129    SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ScrollPosition, scrollPosition)
130    SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ScrollOrigin, scrollOrigin)
131    SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ScrollableAreaParams, scrollableAreaParameters)
132    SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::RequestedScrollPosition, requestedScrollPosition)
133    SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::RequestedScrollPosition, requestedScrollPositionRepresentsProgrammaticScroll)
134}
135
136void ArgumentCoder<ScrollingStateFrameScrollingNode>::encode(ArgumentEncoder& encoder, const ScrollingStateFrameScrollingNode& node)
137{
138    encoder << static_cast<const ScrollingStateScrollingNode&>(node);
139
140    SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::FrameScaleFactor, frameScaleFactor)
141    SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::NonFastScrollableRegion, nonFastScrollableRegion)
142    SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::WheelEventHandlerCount, wheelEventHandlerCount)
143    SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::ReasonsForSynchronousScrolling, synchronousScrollingReasons)
144    SCROLLING_NODE_ENCODE_ENUM(ScrollingStateFrameScrollingNode::BehaviorForFixedElements, scrollBehaviorForFixedElements)
145    SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::HeaderHeight, headerHeight)
146    SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::FooterHeight, footerHeight)
147    SCROLLING_NODE_ENCODE(ScrollingStateFrameScrollingNode::TopContentInset, topContentInset)
148
149    if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::ScrolledContentsLayer))
150        encoder << static_cast<GraphicsLayer::PlatformLayerID>(node.scrolledContentsLayer());
151
152    if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::CounterScrollingLayer))
153        encoder << static_cast<GraphicsLayer::PlatformLayerID>(node.counterScrollingLayer());
154
155    if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::InsetClipLayer))
156        encoder << static_cast<GraphicsLayer::PlatformLayerID>(node.insetClipLayer());
157
158    if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::ContentShadowLayer))
159        encoder << static_cast<GraphicsLayer::PlatformLayerID>(node.contentShadowLayer());
160}
161
162void ArgumentCoder<ScrollingStateOverflowScrollingNode>::encode(ArgumentEncoder& encoder, const ScrollingStateOverflowScrollingNode& node)
163{
164    encoder << static_cast<const ScrollingStateScrollingNode&>(node);
165
166    if (node.hasChangedProperty(ScrollingStateOverflowScrollingNode::ScrolledContentsLayer))
167        encoder << static_cast<GraphicsLayer::PlatformLayerID>(node.scrolledContentsLayer());
168}
169
170#define SCROLLING_NODE_DECODE(property, type, setter) \
171    if (node.hasChangedProperty(property)) { \
172        type decodedValue; \
173        if (!decoder.decode(decodedValue)) \
174            return false; \
175        node.setter(decodedValue); \
176    }
177
178#define SCROLLING_NODE_DECODE_ENUM(property, type, setter) \
179    if (node.hasChangedProperty(property)) { \
180        type decodedValue; \
181        if (!decoder.decodeEnum(decodedValue)) \
182            return false; \
183        node.setter(decodedValue); \
184    }
185
186bool ArgumentCoder<ScrollingStateScrollingNode>::decode(ArgumentDecoder& decoder, ScrollingStateScrollingNode& node)
187{
188    if (!decoder.decode(static_cast<ScrollingStateNode&>(node)))
189        return false;
190
191    SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ScrollableAreaSize, FloatSize, setScrollableAreaSize);
192    SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::TotalContentsSize, FloatSize, setTotalContentsSize);
193    SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ReachableContentsSize, FloatSize, setReachableContentsSize);
194    SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ScrollPosition, FloatPoint, setScrollPosition);
195    SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ScrollOrigin, IntPoint, setScrollOrigin);
196    SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ScrollableAreaParams, ScrollableAreaParameters, setScrollableAreaParameters);
197
198    if (node.hasChangedProperty(ScrollingStateScrollingNode::RequestedScrollPosition)) {
199        FloatPoint scrollPosition;
200        if (!decoder.decode(scrollPosition))
201            return false;
202
203        bool representsProgrammaticScroll;
204        if (!decoder.decode(representsProgrammaticScroll))
205            return false;
206
207        node.setRequestedScrollPosition(scrollPosition, representsProgrammaticScroll);
208    }
209
210    return true;
211}
212
213bool ArgumentCoder<ScrollingStateFrameScrollingNode>::decode(ArgumentDecoder& decoder, ScrollingStateFrameScrollingNode& node)
214{
215    if (!decoder.decode(static_cast<ScrollingStateScrollingNode&>(node)))
216        return false;
217
218    SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::FrameScaleFactor, float, setFrameScaleFactor);
219    SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::NonFastScrollableRegion, Region, setNonFastScrollableRegion);
220    SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::WheelEventHandlerCount, int, setWheelEventHandlerCount);
221    SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::ReasonsForSynchronousScrolling, SynchronousScrollingReasons, setSynchronousScrollingReasons);
222    SCROLLING_NODE_DECODE_ENUM(ScrollingStateFrameScrollingNode::BehaviorForFixedElements, ScrollBehaviorForFixedElements, setScrollBehaviorForFixedElements);
223
224    SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::HeaderHeight, int, setHeaderHeight);
225    SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::FooterHeight, int, setFooterHeight);
226    SCROLLING_NODE_DECODE(ScrollingStateFrameScrollingNode::TopContentInset, float, setTopContentInset);
227
228    if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::ScrolledContentsLayer)) {
229        GraphicsLayer::PlatformLayerID layerID;
230        if (!decoder.decode(layerID))
231            return false;
232        node.setScrolledContentsLayer(layerID);
233    }
234
235    if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::CounterScrollingLayer)) {
236        GraphicsLayer::PlatformLayerID layerID;
237        if (!decoder.decode(layerID))
238            return false;
239        node.setCounterScrollingLayer(layerID);
240    }
241
242    if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::InsetClipLayer)) {
243        GraphicsLayer::PlatformLayerID layerID;
244        if (!decoder.decode(layerID))
245            return false;
246        node.setInsetClipLayer(layerID);
247    }
248
249    if (node.hasChangedProperty(ScrollingStateFrameScrollingNode::ContentShadowLayer)) {
250        GraphicsLayer::PlatformLayerID layerID;
251        if (!decoder.decode(layerID))
252            return false;
253        node.setContentShadowLayer(layerID);
254    }
255
256    return true;
257}
258
259bool ArgumentCoder<ScrollingStateOverflowScrollingNode>::decode(ArgumentDecoder& decoder, ScrollingStateOverflowScrollingNode& node)
260{
261    if (!decoder.decode(static_cast<ScrollingStateScrollingNode&>(node)))
262        return false;
263
264    if (node.hasChangedProperty(ScrollingStateOverflowScrollingNode::ScrolledContentsLayer)) {
265        GraphicsLayer::PlatformLayerID layerID;
266        if (!decoder.decode(layerID))
267            return false;
268        node.setScrolledContentsLayer(layerID);
269    }
270
271    return true;
272}
273
274void ArgumentCoder<ScrollingStateFixedNode>::encode(ArgumentEncoder& encoder, const ScrollingStateFixedNode& node)
275{
276    encoder << static_cast<const ScrollingStateNode&>(node);
277
278    if (node.hasChangedProperty(ScrollingStateFixedNode::ViewportConstraints))
279        encoder << node.viewportConstraints();
280}
281
282bool ArgumentCoder<ScrollingStateFixedNode>::decode(ArgumentDecoder& decoder, ScrollingStateFixedNode& node)
283{
284    if (!decoder.decode(static_cast<ScrollingStateNode&>(node)))
285        return false;
286
287    if (node.hasChangedProperty(ScrollingStateFixedNode::ViewportConstraints)) {
288        FixedPositionViewportConstraints decodedValue;
289        if (!decoder.decode(decodedValue))
290            return false;
291        node.updateConstraints(decodedValue);
292    }
293
294    return true;
295}
296
297void ArgumentCoder<ScrollingStateStickyNode>::encode(ArgumentEncoder& encoder, const ScrollingStateStickyNode& node)
298{
299    encoder << static_cast<const ScrollingStateNode&>(node);
300
301    if (node.hasChangedProperty(ScrollingStateStickyNode::ViewportConstraints))
302        encoder << node.viewportConstraints();
303}
304
305bool ArgumentCoder<ScrollingStateStickyNode>::decode(ArgumentDecoder& decoder, ScrollingStateStickyNode& node)
306{
307    if (!decoder.decode(static_cast<ScrollingStateNode&>(node)))
308        return false;
309
310    if (node.hasChangedProperty(ScrollingStateStickyNode::ViewportConstraints)) {
311        StickyPositionViewportConstraints decodedValue;
312        if (!decoder.decode(decodedValue))
313            return false;
314        node.updateConstraints(decodedValue);
315    }
316
317    return true;
318}
319
320namespace WebKit {
321
322static void encodeNodeAndDescendants(IPC::ArgumentEncoder& encoder, const ScrollingStateNode& stateNode, int& encodedNodeCount)
323{
324    ++encodedNodeCount;
325
326    switch (stateNode.nodeType()) {
327    case FrameScrollingNode:
328        encoder << toScrollingStateFrameScrollingNode(stateNode);
329        break;
330    case OverflowScrollingNode:
331        encoder << toScrollingStateOverflowScrollingNode(stateNode);
332        break;
333    case FixedNode:
334        encoder << toScrollingStateFixedNode(stateNode);
335        break;
336    case StickyNode:
337        encoder << toScrollingStateStickyNode(stateNode);
338        break;
339    }
340
341    if (!stateNode.children())
342        return;
343
344    for (const auto& child : *stateNode.children())
345        encodeNodeAndDescendants(encoder, *child.get(), encodedNodeCount);
346}
347
348void RemoteScrollingCoordinatorTransaction::encode(IPC::ArgumentEncoder& encoder) const
349{
350    int numNodes = m_scrollingStateTree ? m_scrollingStateTree->nodeCount() : 0;
351    encoder << numNodes;
352
353    bool hasNewRootNode = m_scrollingStateTree ? m_scrollingStateTree->hasNewRootStateNode() : false;
354    encoder << hasNewRootNode;
355
356    if (m_scrollingStateTree) {
357        encoder << m_scrollingStateTree->hasChangedProperties();
358
359        int numNodesEncoded = 0;
360        if (const ScrollingStateNode* rootNode = m_scrollingStateTree->rootStateNode())
361            encodeNodeAndDescendants(encoder, *rootNode, numNodesEncoded);
362
363        ASSERT_UNUSED(numNodesEncoded, numNodesEncoded == numNodes);
364        encoder << m_scrollingStateTree->removedNodes();
365    } else
366        encoder << Vector<ScrollingNodeID>();
367}
368
369bool RemoteScrollingCoordinatorTransaction::decode(IPC::ArgumentDecoder& decoder, RemoteScrollingCoordinatorTransaction& transaction)
370{
371    return transaction.decode(decoder);
372}
373
374bool RemoteScrollingCoordinatorTransaction::decode(IPC::ArgumentDecoder& decoder)
375{
376    int numNodes;
377    if (!decoder.decode(numNodes))
378        return false;
379
380    bool hasNewRootNode;
381    if (!decoder.decode(hasNewRootNode))
382        return false;
383
384    m_scrollingStateTree = ScrollingStateTree::create();
385
386    bool hasChangedProperties;
387    if (!decoder.decode(hasChangedProperties))
388        return false;
389
390    m_scrollingStateTree->setHasChangedProperties(hasChangedProperties);
391
392    for (int i = 0; i < numNodes; ++i) {
393        ScrollingNodeType nodeType;
394        if (!decoder.decodeEnum(nodeType))
395            return false;
396
397        ScrollingNodeID nodeID;
398        if (!decoder.decode(nodeID))
399            return false;
400
401        ScrollingNodeID parentNodeID;
402        if (!decoder.decode(parentNodeID))
403            return false;
404
405        m_scrollingStateTree->attachNode(nodeType, nodeID, parentNodeID);
406        ScrollingStateNode* newNode = m_scrollingStateTree->stateNodeForID(nodeID);
407        ASSERT(newNode);
408        ASSERT(!parentNodeID || newNode->parent());
409
410        switch (nodeType) {
411        case FrameScrollingNode:
412            if (!decoder.decode(*toScrollingStateFrameScrollingNode(newNode)))
413                return false;
414            break;
415        case OverflowScrollingNode:
416            if (!decoder.decode(*toScrollingStateOverflowScrollingNode(newNode)))
417                return false;
418            break;
419        case FixedNode:
420            if (!decoder.decode(*toScrollingStateFixedNode(newNode)))
421                return false;
422            break;
423        case StickyNode:
424            if (!decoder.decode(*toScrollingStateStickyNode(newNode)))
425                return false;
426            break;
427        }
428    }
429
430    m_scrollingStateTree->setHasNewRootStateNode(hasNewRootNode);
431
432    // Removed nodes
433    HashSet<ScrollingNodeID> removedNodes;
434    if (!decoder.decode(removedNodes))
435        return false;
436
437    if (removedNodes.size())
438        m_scrollingStateTree->setRemovedNodes(removedNodes);
439
440    return true;
441}
442
443#if !defined(NDEBUG) || !LOG_DISABLED
444
445class RemoteScrollingTreeTextStream : public TextStream {
446public:
447    using TextStream::operator<<;
448
449    RemoteScrollingTreeTextStream()
450        : m_indent(0)
451    {
452    }
453
454    RemoteScrollingTreeTextStream& operator<<(FloatRect);
455    RemoteScrollingTreeTextStream& operator<<(ScrollingNodeType);
456
457    RemoteScrollingTreeTextStream& operator<<(const FixedPositionViewportConstraints&);
458    RemoteScrollingTreeTextStream& operator<<(const StickyPositionViewportConstraints&);
459
460    void dump(const ScrollingStateTree&, bool changedPropertiesOnly = true);
461
462    void dump(const ScrollingStateNode&, bool changedPropertiesOnly = true);
463    void dump(const ScrollingStateScrollingNode&, bool changedPropertiesOnly = true);
464    void dump(const ScrollingStateFrameScrollingNode&, bool changedPropertiesOnly = true);
465    void dump(const ScrollingStateOverflowScrollingNode&, bool changedPropertiesOnly = true);
466    void dump(const ScrollingStateFixedNode&, bool changedPropertiesOnly = true);
467    void dump(const ScrollingStateStickyNode&, bool changedPropertiesOnly = true);
468
469    void increaseIndent() { ++m_indent; }
470    void decreaseIndent() { --m_indent; ASSERT(m_indent >= 0); }
471
472    void writeIndent();
473
474private:
475    void recursiveDumpNodes(const ScrollingStateNode&, bool changedPropertiesOnly);
476
477    int m_indent;
478};
479
480void RemoteScrollingTreeTextStream::writeIndent()
481{
482    for (int i = 0; i < m_indent; ++i)
483        *this << "  ";
484}
485
486template <class T>
487static void dumpProperty(RemoteScrollingTreeTextStream& ts, String name, T value)
488{
489    ts << "\n";
490    ts.increaseIndent();
491    ts.writeIndent();
492    ts << "(" << name << " ";
493    ts << value << ")";
494    ts.decreaseIndent();
495}
496
497RemoteScrollingTreeTextStream& RemoteScrollingTreeTextStream::operator<<(FloatRect rect)
498{
499    RemoteScrollingTreeTextStream& ts = *this;
500    ts << rect.x() << " " << rect.y() << " " << rect.width() << " " << rect.height();
501    return ts;
502}
503
504RemoteScrollingTreeTextStream& RemoteScrollingTreeTextStream::operator<<(ScrollingNodeType nodeType)
505{
506    RemoteScrollingTreeTextStream& ts = *this;
507
508    switch (nodeType) {
509    case FrameScrollingNode: ts << "frame-scrolling"; break;
510    case OverflowScrollingNode: ts << "overflow-scrolling"; break;
511    case FixedNode: ts << "fixed"; break;
512    case StickyNode: ts << "sticky"; break;
513    }
514
515    return ts;
516}
517
518RemoteScrollingTreeTextStream& RemoteScrollingTreeTextStream::operator<<(const FixedPositionViewportConstraints& constraints)
519{
520    RemoteScrollingTreeTextStream& ts = *this;
521
522    dumpProperty(ts, "viewport-rect-at-last-layout", constraints.viewportRectAtLastLayout());
523    dumpProperty(ts, "layer-position-at-last-layout", constraints.layerPositionAtLastLayout());
524
525    return ts;
526}
527
528RemoteScrollingTreeTextStream& RemoteScrollingTreeTextStream::operator<<(const StickyPositionViewportConstraints& constraints)
529{
530    RemoteScrollingTreeTextStream& ts = *this;
531
532    dumpProperty(ts, "sticky-position-at-last-layout", constraints.stickyOffsetAtLastLayout());
533    dumpProperty(ts, "layer-position-at-last-layout", constraints.layerPositionAtLastLayout());
534
535    return ts;
536}
537
538void RemoteScrollingTreeTextStream::dump(const ScrollingStateNode& node, bool changedPropertiesOnly)
539{
540    RemoteScrollingTreeTextStream& ts = *this;
541
542    ts << "(node " << node.scrollingNodeID();
543
544    dumpProperty(ts, "type", node.nodeType());
545
546    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateNode::ScrollLayer))
547        dumpProperty(ts, "layer", static_cast<GraphicsLayer::PlatformLayerID>(node.layer()));
548
549    switch (node.nodeType()) {
550    case FrameScrollingNode:
551        dump(toScrollingStateFrameScrollingNode(node), changedPropertiesOnly);
552        break;
553    case OverflowScrollingNode:
554        dump(toScrollingStateOverflowScrollingNode(node), changedPropertiesOnly);
555        break;
556    case FixedNode:
557        dump(toScrollingStateFixedNode(node), changedPropertiesOnly);
558        break;
559    case StickyNode:
560        dump(toScrollingStateStickyNode(node), changedPropertiesOnly);
561        break;
562    }
563}
564
565void RemoteScrollingTreeTextStream::dump(const ScrollingStateScrollingNode& node, bool changedPropertiesOnly)
566{
567    RemoteScrollingTreeTextStream& ts = *this;
568
569    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::ScrollableAreaSize))
570        dumpProperty(ts, "scrollable-area-size", node.scrollableAreaSize());
571
572    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::TotalContentsSize))
573        dumpProperty(ts, "total-contents-size", node.totalContentsSize());
574
575    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::ReachableContentsSize))
576        dumpProperty(ts, "reachable-contents-size", node.reachableContentsSize());
577
578    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::ScrollPosition))
579        dumpProperty(ts, "scroll-position", node.scrollPosition());
580
581    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::ScrollOrigin))
582        dumpProperty(ts, "scroll-origin", node.scrollOrigin());
583
584    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::RequestedScrollPosition)) {
585        dumpProperty(ts, "requested-scroll-position", node.requestedScrollPosition());
586        dumpProperty(ts, "requested-scroll-position-is-programatic", node.requestedScrollPositionRepresentsProgrammaticScroll());
587    }
588}
589
590void RemoteScrollingTreeTextStream::dump(const ScrollingStateFrameScrollingNode& node, bool changedPropertiesOnly)
591{
592    RemoteScrollingTreeTextStream& ts = *this;
593
594    dump(static_cast<const ScrollingStateScrollingNode&>(node), changedPropertiesOnly);
595
596    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::FrameScaleFactor))
597        dumpProperty(ts, "frame-scale-factor", node.frameScaleFactor());
598
599    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::NonFastScrollableRegion)) {
600        ts << "\n";
601        ts.increaseIndent();
602        ts.writeIndent();
603        ts << "(non-fast-scrollable-region";
604        ts.increaseIndent();
605        for (auto rect : node.nonFastScrollableRegion().rects()) {
606            ts << "\n";
607            ts.writeIndent();
608            ts << rect;
609        }
610        ts << ")\n";
611        ts.decreaseIndent();
612        ts.decreaseIndent();
613    }
614
615    // FIXME: dump wheelEventHandlerCount
616    // FIXME: dump synchronousScrollingReasons
617    // FIXME: dump scrollableAreaParameters
618    // FIXME: dump scrollBehaviorForFixedElements
619
620    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::HeaderHeight))
621        dumpProperty(ts, "header-height", node.headerHeight());
622
623    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::FooterHeight))
624        dumpProperty(ts, "footer-height", node.footerHeight());
625
626    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::TopContentInset))
627        dumpProperty(ts, "top-content-inset", node.topContentInset());
628
629    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::FrameScaleFactor))
630        dumpProperty(ts, "frame-scale-factor", node.frameScaleFactor());
631
632    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::ScrolledContentsLayer))
633        dumpProperty(ts, "scrolled-contents-layer", static_cast<GraphicsLayer::PlatformLayerID>(node.scrolledContentsLayer()));
634
635    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::InsetClipLayer))
636        dumpProperty(ts, "clip-inset-layer", static_cast<GraphicsLayer::PlatformLayerID>(node.insetClipLayer()));
637
638    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::ContentShadowLayer))
639        dumpProperty(ts, "content-shadow-layer", static_cast<GraphicsLayer::PlatformLayerID>(node.contentShadowLayer()));
640
641    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::HeaderLayer))
642        dumpProperty(ts, "header-layer", static_cast<GraphicsLayer::PlatformLayerID>(node.headerLayer()));
643
644    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFrameScrollingNode::FooterLayer))
645        dumpProperty(ts, "footer-layer", static_cast<GraphicsLayer::PlatformLayerID>(node.footerLayer()));
646}
647
648void RemoteScrollingTreeTextStream::dump(const ScrollingStateOverflowScrollingNode& node, bool changedPropertiesOnly)
649{
650    RemoteScrollingTreeTextStream& ts = *this;
651
652    dump(static_cast<const ScrollingStateScrollingNode&>(node), changedPropertiesOnly);
653
654    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateOverflowScrollingNode::ScrolledContentsLayer))
655        dumpProperty(ts, "scrolled-contents-layer", static_cast<GraphicsLayer::PlatformLayerID>(node.scrolledContentsLayer()));
656}
657
658void RemoteScrollingTreeTextStream::dump(const ScrollingStateFixedNode& node, bool changedPropertiesOnly)
659{
660    RemoteScrollingTreeTextStream& ts = *this;
661
662    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFixedNode::ViewportConstraints))
663        ts << node.viewportConstraints();
664}
665
666void RemoteScrollingTreeTextStream::dump(const ScrollingStateStickyNode& node, bool changedPropertiesOnly)
667{
668    RemoteScrollingTreeTextStream& ts = *this;
669
670    if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateFixedNode::ViewportConstraints))
671        ts << node.viewportConstraints();
672}
673
674void RemoteScrollingTreeTextStream::recursiveDumpNodes(const ScrollingStateNode& node, bool changedPropertiesOnly)
675{
676    RemoteScrollingTreeTextStream& ts = *this;
677
678    ts << "\n";
679    ts.increaseIndent();
680    ts.writeIndent();
681    dump(node, changedPropertiesOnly);
682
683    if (node.children()) {
684        ts << "\n";
685        ts.increaseIndent();
686        ts.writeIndent();
687        ts << "(children";
688        ts.increaseIndent();
689
690        for (auto& childNode : *node.children())
691            recursiveDumpNodes(*childNode, changedPropertiesOnly);
692
693        ts << ")";
694        ts.decreaseIndent();
695        ts.decreaseIndent();
696    }
697
698    ts << ")";
699    ts.decreaseIndent();
700}
701
702void RemoteScrollingTreeTextStream::dump(const ScrollingStateTree& stateTree, bool changedPropertiesOnly)
703{
704    RemoteScrollingTreeTextStream& ts = *this;
705
706    dumpProperty(ts, "has changed properties", stateTree.hasChangedProperties());
707    dumpProperty(ts, "has new root node", stateTree.hasNewRootStateNode());
708
709    if (stateTree.rootStateNode())
710        recursiveDumpNodes(*stateTree.rootStateNode(), changedPropertiesOnly);
711
712    if (!stateTree.removedNodes().isEmpty()) {
713        Vector<ScrollingNodeID> removedNodes;
714        copyToVector(stateTree.removedNodes(), removedNodes);
715        dumpProperty<Vector<ScrollingNodeID>>(ts, "removed-nodes", removedNodes);
716    }
717}
718
719WTF::CString RemoteScrollingCoordinatorTransaction::description() const
720{
721    RemoteScrollingTreeTextStream ts;
722
723    ts << "(\n";
724    ts.increaseIndent();
725    ts.writeIndent();
726    ts << "(scrolling state tree";
727
728    if (m_scrollingStateTree) {
729        if (!m_scrollingStateTree->hasChangedProperties())
730            ts << " - no changes";
731        else
732            ts.dump(*m_scrollingStateTree.get());
733    } else
734        ts << " - none";
735
736    ts << ")\n";
737    ts.decreaseIndent();
738
739    return ts.release().utf8();
740}
741
742void RemoteScrollingCoordinatorTransaction::dump() const
743{
744    fprintf(stderr, "%s", description().data());
745}
746#endif
747
748} // namespace WebKit
749
750#else // !ENABLE(ASYNC_SCROLLING)
751
752namespace WebKit {
753
754void RemoteScrollingCoordinatorTransaction::encode(IPC::ArgumentEncoder&) const
755{
756}
757
758bool RemoteScrollingCoordinatorTransaction::decode(IPC::ArgumentDecoder& decoder, RemoteScrollingCoordinatorTransaction& transaction)
759{
760    return true;
761}
762
763} // namespace WebKit
764
765#endif // ENABLE(ASYNC_SCROLLING)
766