+2014-07-09 Tim Horton <timothy_horton@apple.com>
+
+ Use IOSurface ViewSnapshots everywhere on Mac, remove JPEG encoding path
+ https://bugs.webkit.org/show_bug.cgi?id=134773
+
+ Reviewed by Anders Carlsson.
+
+ * UIProcess/API/mac/WKView.mm:
+ (-[WKView _takeViewSnapshot]):
+ * UIProcess/mac/ViewSnapshotStore.h:
+ * UIProcess/mac/ViewSnapshotStore.mm:
+ (WebKit::ViewSnapshotStore::ViewSnapshotStore):
+ (WebKit::ViewSnapshotStore::~ViewSnapshotStore):
+ (WebKit::ViewSnapshotStore::recordSnapshot):
+ (WebKit::ViewSnapshot::clearImage):
+ (WebKit::ViewSnapshot::asLayerContents):
+ (WebKit::createIOSurfaceFromImage): Deleted.
+ (WebKit::compressImageAsJPEG): Deleted.
+ (WebKit::ViewSnapshotStore::reduceSnapshotMemoryCost): Deleted.
+ (WebKit::ViewSnapshotStore::didCompressSnapshot): Deleted.
+ Remove all ViewSnapshot(Store) code related to JPEG-encoded snapshots.
+ Remove the "image" member on ViewSnapshot; Mac will always start out with an IOSurface instead.
+ Adopt WebCore::IOSurface::createFromImage to make that happen.
+ Add a comment noting that if a snapshot comes back empty, we should throw it away completely.
+
2014-07-09 Anders Carlsson <andersca@apple.com>
RemoteLayerBackingStore::ensureBackingStore should ensure that the entire backing store gets redrawn
OBJC_CLASS CAContext;
-#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
-#define USE_JPEG_VIEW_SNAPSHOTS false
+#if PLATFORM(MAC)
#define USE_IOSURFACE_VIEW_SNAPSHOTS true
#define USE_RENDER_SERVER_VIEW_SNAPSHOTS false
-#elif PLATFORM(MAC)
-// Mountain Lion and before do not support IOSurface purgeability.
-#define USE_JPEG_VIEW_SNAPSHOTS true
-#define USE_IOSURFACE_VIEW_SNAPSHOTS false
-#define USE_RENDER_SERVER_VIEW_SNAPSHOTS false
#else
-#define USE_JPEG_VIEW_SNAPSHOTS false
#define USE_IOSURFACE_VIEW_SNAPSHOTS false
#define USE_RENDER_SERVER_VIEW_SNAPSHOTS true
#endif
class WebPageProxy;
struct ViewSnapshot {
-#if USE_JPEG_VIEW_SNAPSHOTS || USE_IOSURFACE_VIEW_SNAPSHOTS
+#if USE_IOSURFACE_VIEW_SNAPSHOTS
RefPtr<WebCore::IOSurface> surface;
- RetainPtr<CGImageRef> image;
#endif
#if USE_RENDER_SERVER_VIEW_SNAPSHOTS
uint32_t slotID = 0;
private:
void pruneSnapshots(WebPageProxy&);
void removeSnapshotImage(ViewSnapshot&);
- void reduceSnapshotMemoryCost(const String& uuid);
-
-#if USE_JPEG_VIEW_SNAPSHOTS
- void didCompressSnapshot(const String& uuid, RetainPtr<CGImageRef> newImage, size_t newImageSize);
- dispatch_queue_t m_compressionQueue;
-#endif
HashMap<String, ViewSnapshot> m_snapshotMap;
#if USE_IOSURFACE_VIEW_SNAPSHOTS
static const size_t maximumSnapshotCacheSize = 400 * (1024 * 1024);
-#elif USE_JPEG_VIEW_SNAPSHOTS || USE_RENDER_SERVER_VIEW_SNAPSHOTS
-// Because non-IOSurface snapshots are not purgeable, we should keep fewer around.
+#elif USE_RENDER_SERVER_VIEW_SNAPSHOTS
+// Because render server snapshots are not purgeable, we should keep fewer around.
static const size_t maximumSnapshotCacheSize = 50 * (1024 * 1024);
#endif
: m_enabled(true)
, m_snapshotCacheSize(0)
{
-#if USE_JPEG_VIEW_SNAPSHOTS
- m_compressionQueue = dispatch_queue_create("com.apple.WebKit.ViewSnapshotStore.CompressionQueue", nullptr);
-#endif
}
ViewSnapshotStore::~ViewSnapshotStore()
{
-#if USE_JPEG_VIEW_SNAPSHOTS
- dispatch_release(m_compressionQueue);
-#endif
discardSnapshots();
}
m_snapshotMap.add(item->snapshotUUID(), snapshot);
m_snapshotCacheSize += snapshot.imageSizeInBytes;
-
- reduceSnapshotMemoryCost(item->snapshotUUID());
}
bool ViewSnapshotStore::getSnapshot(WebBackForwardListItem* item, ViewSnapshot& snapshot)
removeSnapshotImage(snapshot);
}
-#if USE_IOSURFACE_VIEW_SNAPSHOTS
-static RefPtr<IOSurface> createIOSurfaceFromImage(CGImageRef image)
-{
- size_t width = CGImageGetWidth(image);
- size_t height = CGImageGetHeight(image);
-
- RefPtr<IOSurface> surface = IOSurface::create(IntSize(width, height), ColorSpaceDeviceRGB);
- RetainPtr<CGContextRef> surfaceContext = surface->ensurePlatformContext();
- CGContextDrawImage(surfaceContext.get(), CGRectMake(0, 0, width, height), image);
- CGContextFlush(surfaceContext.get());
-
- surface->setIsVolatile(true);
-
- return surface;
-}
-#endif
-
-#if USE_JPEG_VIEW_SNAPSHOTS
-static std::pair<RetainPtr<CGImageRef>, size_t> compressImageAsJPEG(CGImageRef image)
-{
- RetainPtr<NSData> compressedData = adoptNS([[NSMutableData alloc] init]);
- RetainPtr<CGImageDestinationRef> destination = adoptCF(CGImageDestinationCreateWithData((CFMutableDataRef)compressedData.get(), kUTTypeJPEG, 1, 0));
-
- RetainPtr<NSDictionary> options = @{
- (NSString*)kCGImageDestinationLossyCompressionQuality: @0.9
- };
-
- CGImageDestinationAddImage(destination.get(), image, (CFDictionaryRef)options.get());
- CGImageDestinationFinalize(destination.get());
-
- RetainPtr<CGImageSourceRef> imageSourceRef = adoptCF(CGImageSourceCreateWithData((CFDataRef)compressedData.get(), 0));
- RetainPtr<CGImageRef> compressedSnapshot = adoptCF(CGImageSourceCreateImageAtIndex(imageSourceRef.get(), 0, 0));
-
- return std::make_pair(compressedSnapshot, [compressedData length]);
-}
-#endif
-
-void ViewSnapshotStore::reduceSnapshotMemoryCost(const String& uuid)
-{
- const auto& snapshotIterator = m_snapshotMap.find(uuid);
- if (snapshotIterator == m_snapshotMap.end())
- return;
- ViewSnapshot& snapshot = snapshotIterator->value;
- if (!snapshot.hasImage())
- return;
-
-#if USE_IOSURFACE_VIEW_SNAPSHOTS
- snapshot.surface = createIOSurfaceFromImage(snapshot.image.get());
- snapshot.image = nullptr;
-#elif USE_JPEG_VIEW_SNAPSHOTS
- RetainPtr<CGImageRef> originalImage = snapshot.image.get();
- dispatch_async(m_compressionQueue, [uuid, originalImage] {
- auto imageAndBytes = compressImageAsJPEG(originalImage.get());
- dispatch_async(dispatch_get_main_queue(), [uuid, imageAndBytes] {
- ViewSnapshotStore::shared().didCompressSnapshot(uuid, imageAndBytes.first, imageAndBytes.second);
- });
- });
-#endif
-}
-
-#if USE_JPEG_VIEW_SNAPSHOTS
-void ViewSnapshotStore::didCompressSnapshot(const String& uuid, RetainPtr<CGImageRef> newImage, size_t newImageSize)
-{
- const auto& snapshotIterator = m_snapshotMap.find(uuid);
- if (snapshotIterator == m_snapshotMap.end())
- return;
- ViewSnapshot& snapshot = snapshotIterator->value;
-
- size_t originalImageSize = snapshot.imageSizeInBytes;
- if (!newImage || newImageSize > originalImageSize)
- return;
- snapshot.image = newImage;
- snapshot.imageSizeInBytes = newImageSize;
- m_snapshotCacheSize += newImageSize;
- m_snapshotCacheSize -= originalImageSize;
-}
-#endif
-
bool ViewSnapshot::hasImage() const
{
return imageSizeInBytes;
{
#if USE_IOSURFACE_VIEW_SNAPSHOTS
surface = nullptr;
-#endif
-#if USE_IOSURFACE_VIEW_SNAPSHOTS || USE_JPEG_VIEW_SNAPSHOTS
- image = nullptr;
-#endif
-#if USE_RENDER_SERVER_VIEW_SNAPSHOTS
+#elif USE_RENDER_SERVER_VIEW_SNAPSHOTS
if (slotID)
[ViewSnapshotStore::snapshottingContext() deleteSlot:slotID];
slotID = 0;
id ViewSnapshot::asLayerContents()
{
#if USE_IOSURFACE_VIEW_SNAPSHOTS
- if (surface) {
- if (surface->setIsVolatile(false) != IOSurface::SurfaceState::Valid)
- return nullptr;
+ if (!surface)
+ return nullptr;
- return (id)surface->surface();
- }
-#endif
-#if USE_IOSURFACE_VIEW_SNAPSHOTS || USE_JPEG_VIEW_SNAPSHOTS
- return (id)image.get();
-#endif
-#if USE_RENDER_SERVER_VIEW_SNAPSHOTS
+ // FIXME: This should destroy the surface and inform the ViewSnapshotStore to reduce m_snapshotCacheSize.
+ if (surface->setIsVolatile(false) != IOSurface::SurfaceState::Valid)
+ return nullptr;
+
+ return (id)surface->surface();
+#elif USE_RENDER_SERVER_VIEW_SNAPSHOTS
return [CAContext objectForSlot:slotID];
#endif
}