Use StaticLock instead of NeverDestroyed<Lock>
[WebKit-https.git] / Source / WebKitLegacy / ios / WebCoreSupport / WebFixedPositionContent.mm
1 /*
2  * Copyright (C) 2011 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 #if PLATFORM(IOS)
27
28 #import "WebFixedPositionContent.h"
29 #import "WebFixedPositionContentInternal.h"
30
31 #import "WebViewInternal.h"
32 #import <WebCore/ChromeClient.h>
33 #import <WebCore/Frame.h>
34 #import <WebCore/IntSize.h>
35 #import <WebCore/ScrollingConstraints.h>
36 #import <WebCore/WebCoreThreadRun.h>
37 #import <pal/spi/cg/CoreGraphicsSPI.h>
38
39 #import <wtf/HashMap.h>
40 #import <wtf/NeverDestroyed.h>
41 #import <wtf/RetainPtr.h>
42 #import <wtf/StdLibExtras.h>
43 #import <wtf/Threading.h>
44
45 #import <Foundation/Foundation.h>
46 #import <QuartzCore/QuartzCore.h>
47 #import <algorithm>
48
49 using namespace WebCore;
50 using namespace std;
51
52 static StaticLock webFixedPositionContentDataLock;
53
54 struct ViewportConstrainedLayerData {
55     ViewportConstrainedLayerData()
56         : m_enclosingAcceleratedScrollLayer(nil)
57     { }
58     CALayer* m_enclosingAcceleratedScrollLayer; // May be nil.
59     std::unique_ptr<ViewportConstraints> m_viewportConstraints;
60 };
61
62 typedef HashMap<RetainPtr<CALayer>, std::unique_ptr<ViewportConstrainedLayerData>> LayerInfoMap;
63
64 struct WebFixedPositionContentData {
65 public:
66     WebFixedPositionContentData(WebView *);
67     ~WebFixedPositionContentData();
68     
69     WebView *m_webView;
70     LayerInfoMap m_viewportConstrainedLayers;
71 };
72
73
74 WebFixedPositionContentData::WebFixedPositionContentData(WebView *webView)
75     : m_webView(webView)
76 {
77 }
78
79 WebFixedPositionContentData::~WebFixedPositionContentData()
80 {
81 }
82
83 @implementation WebFixedPositionContent {
84     struct WebFixedPositionContentData* _private;
85 }
86
87 - (id)initWithWebView:(WebView *)webView
88 {
89     if ((self = [super init])) {
90         _private = new WebFixedPositionContentData(webView);
91     }
92     return self;
93 }
94
95 - (void)dealloc
96 {
97     delete _private;
98     [super dealloc];
99 }
100
101 - (void)scrollOrZoomChanged:(CGRect)positionedObjectsRect
102 {
103     auto locker = holdLock(webFixedPositionContentDataLock);
104
105     LayerInfoMap::const_iterator end = _private->m_viewportConstrainedLayers.end();
106     for (LayerInfoMap::const_iterator it = _private->m_viewportConstrainedLayers.begin(); it != end; ++it) {
107         CALayer *layer = it->key.get();
108         ViewportConstrainedLayerData* constraintData = it->value.get();
109         const ViewportConstraints& constraints = *(constraintData->m_viewportConstraints.get());
110
111         switch (constraints.constraintType()) {
112         case ViewportConstraints::FixedPositionConstraint: {
113                 const FixedPositionViewportConstraints& fixedConstraints = static_cast<const FixedPositionViewportConstraints&>(constraints);
114
115                 FloatPoint layerPosition = fixedConstraints.layerPositionForViewportRect(positionedObjectsRect);
116             
117                 CGRect layerBounds = [layer bounds];
118                 CGPoint anchorPoint = [layer anchorPoint];
119                 CGPoint newPosition = CGPointMake(layerPosition.x() - constraints.alignmentOffset().width() + anchorPoint.x * layerBounds.size.width,
120                                                   layerPosition.y() - constraints.alignmentOffset().height() + anchorPoint.y * layerBounds.size.height);
121                 [layer setPosition:newPosition];
122                 break;
123             }
124         case ViewportConstraints::StickyPositionConstraint: {
125                 const StickyPositionViewportConstraints& stickyConstraints = static_cast<const StickyPositionViewportConstraints&>(constraints);
126
127                 FloatPoint layerPosition = stickyConstraints.layerPositionForConstrainingRect(positionedObjectsRect);
128
129                 CGRect layerBounds = [layer bounds];
130                 CGPoint anchorPoint = [layer anchorPoint];
131                 CGPoint newPosition = CGPointMake(layerPosition.x() - constraints.alignmentOffset().width() + anchorPoint.x * layerBounds.size.width,
132                                                   layerPosition.y() - constraints.alignmentOffset().height() + anchorPoint.y * layerBounds.size.height);
133                 [layer setPosition:newPosition];
134                 break;
135             }
136         }
137     }
138 }
139
140 - (void)overflowScrollPositionForLayer:(CALayer *)scrollLayer changedTo:(CGPoint)scrollPosition
141 {
142     auto locker = holdLock(webFixedPositionContentDataLock);
143
144     LayerInfoMap::const_iterator end = _private->m_viewportConstrainedLayers.end();
145     for (LayerInfoMap::const_iterator it = _private->m_viewportConstrainedLayers.begin(); it != end; ++it) {
146         CALayer *layer = it->key.get();
147         ViewportConstrainedLayerData* constraintData = it->value.get();
148         
149         if (constraintData->m_enclosingAcceleratedScrollLayer == scrollLayer) {
150             const StickyPositionViewportConstraints& stickyConstraints = static_cast<const StickyPositionViewportConstraints&>(*(constraintData->m_viewportConstraints.get()));
151             FloatRect constrainingRectAtLastLayout = stickyConstraints.constrainingRectAtLastLayout();
152             FloatRect scrolledConstrainingRect = FloatRect(scrollPosition.x, scrollPosition.y, constrainingRectAtLastLayout.width(), constrainingRectAtLastLayout.height());
153             FloatPoint layerPosition = stickyConstraints.layerPositionForConstrainingRect(scrolledConstrainingRect);
154
155             CGRect layerBounds = [layer bounds];
156             CGPoint anchorPoint = [layer anchorPoint];
157             CGPoint newPosition = CGPointMake(layerPosition.x() - stickyConstraints.alignmentOffset().width() + anchorPoint.x * layerBounds.size.width,
158                                               layerPosition.y() - stickyConstraints.alignmentOffset().height() + anchorPoint.y * layerBounds.size.height);
159             [layer setPosition:newPosition];
160         }
161     }
162 }
163
164 // FIXME: share code with 'sendScrollEvent'?
165 - (void)didFinishScrollingOrZooming
166 {
167     WebThreadRun(^{
168         if (Frame* frame = [_private->m_webView _mainCoreFrame])
169             frame->viewportOffsetChanged(Frame::CompletedScrollOffset);
170     });
171 }
172
173 - (void)setViewportConstrainedLayers:(WTF::HashMap<CALayer *, std::unique_ptr<WebCore::ViewportConstraints>>&)layerMap stickyContainerMap:(WTF::HashMap<CALayer*, CALayer*>&)stickyContainers
174 {
175     auto locker = holdLock(webFixedPositionContentDataLock);
176
177     _private->m_viewportConstrainedLayers.clear();
178
179     for (auto& layerAndConstraints : layerMap) {
180         CALayer* layer = layerAndConstraints.key;
181         auto layerData = std::make_unique<ViewportConstrainedLayerData>();
182
183         layerData->m_enclosingAcceleratedScrollLayer = stickyContainers.get(layer);
184         layerData->m_viewportConstraints = WTFMove(layerAndConstraints.value);
185
186         _private->m_viewportConstrainedLayers.set(layer, WTFMove(layerData));
187     }
188 }
189
190 - (BOOL)hasFixedOrStickyPositionLayers
191 {
192     auto locker = holdLock(webFixedPositionContentDataLock);
193     return !_private->m_viewportConstrainedLayers.isEmpty();
194 }
195
196 @end
197
198 #endif // PLATFORM(IOS)