Make WebCore::IOSurface have single ownership instead of refcounting
[WebKit-https.git] / Source / WebKit2 / UIProcess / mac / ViewSnapshotStore.mm
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 #import "config.h"
27 #import "ViewSnapshotStore.h"
28
29 #import "WebBackForwardList.h"
30 #import "WebPageProxy.h"
31 #import <CoreGraphics/CoreGraphics.h>
32 #import <WebCore/IOSurface.h>
33
34 #if PLATFORM(IOS)
35 #import <WebCore/QuartzCoreSPI.h>
36 #endif
37
38 using namespace WebCore;
39
40 #if USE_IOSURFACE_VIEW_SNAPSHOTS
41 static const size_t maximumSnapshotCacheSize = 400 * (1024 * 1024);
42 #elif USE_RENDER_SERVER_VIEW_SNAPSHOTS
43 // Because render server snapshots are not purgeable, we should keep fewer around.
44 static const size_t maximumSnapshotCacheSize = 50 * (1024 * 1024);
45 #endif
46
47 namespace WebKit {
48
49 ViewSnapshotStore::ViewSnapshotStore()
50     : m_snapshotCacheSize(0)
51 {
52 }
53
54 ViewSnapshotStore::~ViewSnapshotStore()
55 {
56     discardSnapshotImages();
57 }
58
59 ViewSnapshotStore& ViewSnapshotStore::singleton()
60 {
61     static ViewSnapshotStore& store = *new ViewSnapshotStore;
62     return store;
63 }
64
65 #if USE_RENDER_SERVER_VIEW_SNAPSHOTS
66 CAContext *ViewSnapshotStore::snapshottingContext()
67 {
68     static CAContext *context;
69     static dispatch_once_t onceToken;
70     dispatch_once(&onceToken, ^{
71         NSDictionary *options = @{
72             kCAContextDisplayName: @"WebKitSnapshotting",
73             kCAContextIgnoresHitTest: @YES,
74             kCAContextDisplayId : @20000
75         };
76         context = [[CAContext remoteContextWithOptions:options] retain];
77     });
78
79     return context;
80 }
81 #endif
82
83 void ViewSnapshotStore::didAddImageToSnapshot(ViewSnapshot& snapshot)
84 {
85     bool isNewEntry = m_snapshotsWithImages.add(&snapshot).isNewEntry;
86     ASSERT_UNUSED(isNewEntry, isNewEntry);
87     m_snapshotCacheSize += snapshot.imageSizeInBytes();
88 }
89
90 void ViewSnapshotStore::willRemoveImageFromSnapshot(ViewSnapshot& snapshot)
91 {
92     bool removed = m_snapshotsWithImages.remove(&snapshot);
93     ASSERT_UNUSED(removed, removed);
94     m_snapshotCacheSize -= snapshot.imageSizeInBytes();
95 }
96
97 void ViewSnapshotStore::pruneSnapshots(WebPageProxy& webPageProxy)
98 {
99     if (m_snapshotCacheSize <= maximumSnapshotCacheSize)
100         return;
101
102     ASSERT(!m_snapshotsWithImages.isEmpty());
103
104     // FIXME: We have enough information to do smarter-than-LRU eviction (making use of the back-forward lists, etc.)
105
106     m_snapshotsWithImages.first()->clearImage();
107 }
108
109 void ViewSnapshotStore::recordSnapshot(WebPageProxy& webPageProxy, WebBackForwardListItem& item)
110 {
111     if (webPageProxy.isShowingNavigationGestureSnapshot())
112         return;
113
114     pruneSnapshots(webPageProxy);
115
116     webPageProxy.willRecordNavigationSnapshot(item);
117
118     RefPtr<ViewSnapshot> snapshot = webPageProxy.takeViewSnapshot();
119     if (!snapshot || !snapshot->hasImage())
120         return;
121
122     snapshot->setRenderTreeSize(webPageProxy.renderTreeSize());
123     snapshot->setDeviceScaleFactor(webPageProxy.deviceScaleFactor());
124     snapshot->setBackgroundColor(webPageProxy.pageExtendedBackgroundColor());
125
126     item.setSnapshot(snapshot.release());
127 }
128
129 void ViewSnapshotStore::discardSnapshotImages()
130 {
131     while (!m_snapshotsWithImages.isEmpty())
132         m_snapshotsWithImages.first()->clearImage();
133 }
134
135
136 #if USE_IOSURFACE_VIEW_SNAPSHOTS
137 PassRefPtr<ViewSnapshot> ViewSnapshot::create(std::unique_ptr<IOSurface> surface)
138 {
139     return adoptRef(new ViewSnapshot(WTF::move(surface)));
140 }
141 #elif USE_RENDER_SERVER_VIEW_SNAPSHOTS
142 PassRefPtr<ViewSnapshot> ViewSnapshot::create(uint32_t slotID, IntSize size, size_t imageSizeInBytes)
143 {
144     return adoptRef(new ViewSnapshot(slotID, size, imageSizeInBytes));
145 }
146 #endif
147
148 #if USE_IOSURFACE_VIEW_SNAPSHOTS
149 ViewSnapshot::ViewSnapshot(std::unique_ptr<IOSurface> surface)
150     : m_surface(WTF::move(surface))
151     , m_imageSizeInBytes(m_surface->totalBytes())
152     , m_size(m_surface->size())
153 #elif USE_RENDER_SERVER_VIEW_SNAPSHOTS
154 ViewSnapshot::ViewSnapshot(uint32_t slotID, IntSize size, size_t imageSizeInBytes)
155     : m_slotID(slotID)
156     , m_imageSizeInBytes(imageSizeInBytes)
157     , m_size(size)
158 #endif
159 {
160     if (hasImage())
161         ViewSnapshotStore::singleton().didAddImageToSnapshot(*this);
162 }
163
164 ViewSnapshot::~ViewSnapshot()
165 {
166     clearImage();
167 }
168
169 bool ViewSnapshot::hasImage() const
170 {
171 #if USE_IOSURFACE_VIEW_SNAPSHOTS
172     return !!m_surface;
173 #elif USE_RENDER_SERVER_VIEW_SNAPSHOTS
174     return m_slotID;
175 #endif
176 }
177
178 void ViewSnapshot::clearImage()
179 {
180     if (!hasImage())
181         return;
182
183     ViewSnapshotStore::singleton().willRemoveImageFromSnapshot(*this);
184
185 #if USE_IOSURFACE_VIEW_SNAPSHOTS
186     m_surface = nullptr;
187 #elif USE_RENDER_SERVER_VIEW_SNAPSHOTS
188     [ViewSnapshotStore::snapshottingContext() deleteSlot:m_slotID];
189     m_slotID = 0;
190 #endif
191     m_imageSizeInBytes = 0;
192 }
193
194 id ViewSnapshot::asLayerContents()
195 {
196 #if USE_IOSURFACE_VIEW_SNAPSHOTS
197     if (!m_surface)
198         return nullptr;
199
200     if (m_surface->setIsVolatile(false) != IOSurface::SurfaceState::Valid) {
201         clearImage();
202         return nullptr;
203     }
204
205     return (id)m_surface->surface();
206 #elif USE_RENDER_SERVER_VIEW_SNAPSHOTS
207     return [CAContext objectForSlot:m_slotID];
208 #endif
209 }
210
211 } // namespace WebKit