Assertions or crashes under _takeViewSnapshot when restoring windows
[WebKit-https.git] / Source / WebCore / platform / graphics / cocoa / IOSurface.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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "IOSurface.h"
28
29 #if USE(IOSURFACE)
30
31 #import "GraphicsContextCG.h"
32 #import "IOSurfacePool.h"
33 #import <IOSurface/IOSurface.h>
34 #import <wtf/Assertions.h>
35
36 #if __has_include(<IOSurface/IOSurfacePrivate.h>)
37 #import <IOSurface/IOSurfacePrivate.h>
38 #else
39 enum {
40     kIOSurfacePurgeableNonVolatile = 0,
41     kIOSurfacePurgeableVolatile = 1,
42     kIOSurfacePurgeableEmpty = 2,
43     kIOSurfacePurgeableKeepCurrent = 3,
44 };
45 #endif
46
47 extern "C" {
48 CGContextRef CGIOSurfaceContextCreate(IOSurfaceRef, size_t, size_t, size_t, size_t, CGColorSpaceRef, CGBitmapInfo);
49 CGImageRef CGIOSurfaceContextCreateImage(CGContextRef);
50 IOReturn IOSurfaceSetPurgeable(IOSurfaceRef, uint32_t, uint32_t *);
51 }
52
53 using namespace WebCore;
54
55 PassRefPtr<IOSurface> IOSurface::create(IntSize size, ColorSpace colorSpace)
56 {
57     if (RefPtr<IOSurface> cachedSurface = IOSurfacePool::sharedPool().takeSurface(size, colorSpace))
58         return cachedSurface.release();
59     return adoptRef(new IOSurface(size, colorSpace));
60 }
61
62 PassRefPtr<IOSurface> IOSurface::createFromMachPort(mach_port_t machPort, ColorSpace colorSpace)
63 {
64     RetainPtr<IOSurfaceRef> surface = adoptCF(IOSurfaceLookupFromMachPort(machPort));
65     return IOSurface::createFromSurface(surface.get(), colorSpace);
66 }
67
68 PassRefPtr<IOSurface> IOSurface::createFromSurface(IOSurfaceRef surface, ColorSpace colorSpace)
69 {
70     return adoptRef(new IOSurface(surface, colorSpace));
71 }
72
73 PassRefPtr<IOSurface> IOSurface::createFromImage(CGImageRef image)
74 {
75     if (!image)
76         return nullptr;
77
78     size_t width = CGImageGetWidth(image);
79     size_t height = CGImageGetHeight(image);
80
81     RefPtr<IOSurface> surface = IOSurface::create(IntSize(width, height), ColorSpaceDeviceRGB);
82     auto surfaceContext = surface->ensurePlatformContext();
83     CGContextDrawImage(surfaceContext, CGRectMake(0, 0, width, height), image);
84     CGContextFlush(surfaceContext);
85
86     return surface.release();
87 }
88
89 IOSurface::IOSurface(IntSize size, ColorSpace colorSpace)
90     : m_colorSpace(colorSpace)
91     , m_size(size)
92 {
93     unsigned pixelFormat = 'BGRA';
94     unsigned bytesPerElement = 4;
95     int width = size.width();
96     int height = size.height();
97
98     size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, width * bytesPerElement);
99     ASSERT(bytesPerRow);
100
101     m_totalBytes = IOSurfaceAlignProperty(kIOSurfaceAllocSize, height * bytesPerRow);
102     ASSERT(m_totalBytes);
103
104     NSDictionary *options = @{
105         (id)kIOSurfaceWidth: @(width),
106         (id)kIOSurfaceHeight: @(height),
107         (id)kIOSurfacePixelFormat: @(pixelFormat),
108         (id)kIOSurfaceBytesPerElement: @(bytesPerElement),
109         (id)kIOSurfaceBytesPerRow: @(bytesPerRow),
110         (id)kIOSurfaceAllocSize: @(m_totalBytes),
111 #if PLATFORM(IOS)
112         (id)kIOSurfaceCacheMode: @(kIOMapWriteCombineCache)
113 #endif
114     };
115
116     m_surface = adoptCF(IOSurfaceCreate((CFDictionaryRef)options));
117 }
118
119 IOSurface::IOSurface(IOSurfaceRef surface, ColorSpace colorSpace)
120     : m_colorSpace(colorSpace)
121     , m_surface(surface)
122 {
123     m_size = IntSize(IOSurfaceGetWidth(surface), IOSurfaceGetHeight(surface));
124     m_totalBytes = IOSurfaceGetAllocSize(surface);
125 }
126
127 IntSize IOSurface::maximumSize()
128 {
129     return IntSize(IOSurfaceGetPropertyMaximum(kIOSurfaceWidth), IOSurfaceGetPropertyMaximum(kIOSurfaceHeight));
130 }
131
132 mach_port_t IOSurface::createMachPort() const
133 {
134     return IOSurfaceCreateMachPort(m_surface.get());
135 }
136
137 RetainPtr<CGImageRef> IOSurface::createImage()
138 {
139     return adoptCF(CGIOSurfaceContextCreateImage(ensurePlatformContext()));
140 }
141
142 CGContextRef IOSurface::ensurePlatformContext()
143 {
144     if (m_cgContext)
145         return m_cgContext.get();
146
147     CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
148     size_t bitsPerComponent = 8;
149     size_t bitsPerPixel = 32;
150     m_cgContext = adoptCF(CGIOSurfaceContextCreate(m_surface.get(), m_size.width(), m_size.height(), bitsPerComponent, bitsPerPixel, cachedCGColorSpace(m_colorSpace), bitmapInfo));
151
152     return m_cgContext.get();
153 }
154
155 GraphicsContext& IOSurface::ensureGraphicsContext()
156 {
157     if (m_graphicsContext)
158         return *m_graphicsContext;
159
160     m_graphicsContext = adoptPtr(new GraphicsContext(ensurePlatformContext()));
161
162     return *m_graphicsContext;
163 }
164
165 IOSurface::SurfaceState IOSurface::state() const
166 {
167 #if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
168     uint32_t previousState = 0;
169     IOReturn ret = IOSurfaceSetPurgeable(m_surface.get(), kIOSurfacePurgeableKeepCurrent, &previousState);
170     ASSERT_UNUSED(ret, ret == kIOReturnSuccess);
171     return previousState == kIOSurfacePurgeableEmpty ? IOSurface::SurfaceState::Empty : IOSurface::SurfaceState::Valid;
172 #else
173     return SurfaceState::Valid;
174 #endif
175 }
176
177 bool IOSurface::isVolatile() const
178 {
179 #if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
180     uint32_t previousState = 0;
181     IOReturn ret = IOSurfaceSetPurgeable(m_surface.get(), kIOSurfacePurgeableKeepCurrent, &previousState);
182     ASSERT_UNUSED(ret, ret == kIOReturnSuccess);
183     return previousState != kIOSurfacePurgeableNonVolatile;
184 #else
185     return false;
186 #endif
187 }
188
189 IOSurface::SurfaceState IOSurface::setIsVolatile(bool isVolatile)
190 {
191 #if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
192     uint32_t previousState = 0;
193     IOReturn ret = IOSurfaceSetPurgeable(m_surface.get(), isVolatile ? kIOSurfacePurgeableVolatile : kIOSurfacePurgeableNonVolatile, &previousState);
194     ASSERT_UNUSED(ret, ret == kIOReturnSuccess);
195
196     if (previousState == kIOSurfacePurgeableEmpty)
197         return IOSurface::SurfaceState::Empty;
198 #else
199     UNUSED_PARAM(isVolatile);
200 #endif
201
202     return IOSurface::SurfaceState::Valid;
203 }
204
205 bool IOSurface::isInUse() const
206 {
207     return IOSurfaceIsInUse(m_surface.get());
208 }
209
210 void IOSurface::releaseGraphicsContext()
211 {
212     m_graphicsContext = nullptr;
213     m_cgContext = nullptr;
214 }
215
216 #endif // USE(IOSURFACE)