Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / platform / graphics / win / ImageBufferDirect2D.cpp
1 /*
2  * Copyright (C) 2016 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 #include "config.h"
27 #include "ImageBuffer.h"
28
29 #if USE(DIRECT2D)
30
31 #include "BitmapImage.h"
32 #include "COMPtr.h"
33 #include "GraphicsContext.h"
34 #include "ImageData.h"
35 #include "IntRect.h"
36 #include "MIMETypeRegistry.h"
37 #include "NotImplemented.h"
38 #include <d2d1.h>
39 #include <math.h>
40 #include <wtf/Assertions.h>
41 #include <wtf/CheckedArithmetic.h>
42 #include <wtf/MainThread.h>
43 #include <wtf/RetainPtr.h>
44 #include <wtf/text/Base64.h>
45 #include <wtf/text/WTFString.h>
46
47
48 namespace WebCore {
49
50 static FloatSize scaleSizeToUserSpace(const FloatSize& logicalSize, const IntSize& backingStoreSize, const IntSize& internalSize)
51 {
52     float xMagnification = static_cast<float>(backingStoreSize.width()) / internalSize.width();
53     float yMagnification = static_cast<float>(backingStoreSize.height()) / internalSize.height();
54     return FloatSize(logicalSize.width() * xMagnification, logicalSize.height() * yMagnification);
55 }
56
57 std::unique_ptr<ImageBuffer> ImageBuffer::createCompatibleBuffer(const FloatSize& size, const GraphicsContext& context)
58 {
59     if (size.isEmpty())
60         return nullptr;
61
62     RenderingMode renderingMode = context.renderingMode();
63     IntSize scaledSize = ImageBuffer::compatibleBufferSize(size, context);
64     bool success = false;
65     std::unique_ptr<ImageBuffer> buffer(new ImageBuffer(scaledSize, 1, ColorSpaceSRGB, renderingMode, &context, success));
66
67     if (!success)
68         return nullptr;
69
70     // Set up a corresponding scale factor on the graphics context.
71     buffer->context().scale(FloatSize(scaledSize.width() / size.width(), scaledSize.height() / size.height()));
72     return buffer;
73 }
74
75 ImageBuffer::ImageBuffer(const FloatSize& size, float resolutionScale, ColorSpace /*colorSpace*/, RenderingMode renderingMode, const GraphicsContext* targetContext, bool& success)
76     : m_logicalSize(size)
77     , m_resolutionScale(resolutionScale)
78 {
79     success = false; // Make early return mean failure.
80     float scaledWidth = std::ceil(resolutionScale * size.width());
81     float scaledHeight = std::ceil(resolutionScale * size.height());
82
83     // FIXME: Should we automatically use a lower resolution?
84     if (!FloatSize(scaledWidth, scaledHeight).isExpressibleAsIntSize())
85         return;
86
87     m_size = IntSize(scaledWidth, scaledHeight);
88     m_data.backingStoreSize = m_size;
89
90     bool accelerateRendering = renderingMode == Accelerated;
91     if (m_size.width() <= 0 || m_size.height() <= 0)
92         return;
93
94     // Prevent integer overflows
95     m_data.bytesPerRow = 4 * Checked<unsigned, RecordOverflow>(m_data.backingStoreSize.width());
96     Checked<size_t, RecordOverflow> numBytes = Checked<unsigned, RecordOverflow>(m_data.backingStoreSize.height()) * m_data.bytesPerRow;
97     if (numBytes.hasOverflowed())
98         return;
99
100     auto renderTarget = targetContext ? targetContext->platformContext() : nullptr;
101     if (!renderTarget)
102         renderTarget = GraphicsContext::defaultRenderTarget();
103     RELEASE_ASSERT(renderTarget);
104
105     COMPtr<ID2D1BitmapRenderTarget> bitmapContext;
106     D2D1_SIZE_F desiredSize = FloatSize(m_logicalSize);
107     D2D1_SIZE_U pixelSize = IntSize(m_logicalSize);
108     HRESULT hr = renderTarget->CreateCompatibleRenderTarget(&desiredSize, &pixelSize, nullptr, D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_GDI_COMPATIBLE, &bitmapContext);
109     if (!bitmapContext || !SUCCEEDED(hr))
110         return;
111
112     m_data.context = std::make_unique<GraphicsContext>(bitmapContext.get());
113     m_data.m_compatibleTarget = renderTarget;
114
115     success = true;
116 }
117
118 ImageBuffer::ImageBuffer(const FloatSize& size, float resolutionScale, ColorSpace imageColorSpace, RenderingMode renderingMode, bool& success)
119     : ImageBuffer(size, resolutionScale, imageColorSpace, renderingMode, nullptr, success)
120 {
121 }
122
123 ImageBuffer::~ImageBuffer() = default;
124
125 FloatSize ImageBuffer::sizeForDestinationSize(FloatSize destinationSize) const
126 {
127     return scaleSizeToUserSpace(destinationSize, m_data.backingStoreSize, internalSize());
128 }
129
130 GraphicsContext& ImageBuffer::context() const
131 {
132     return *m_data.context;
133 }
134
135 void ImageBuffer::flushContext() const
136 {
137     context().flush();
138 }
139
140 RefPtr<Image> ImageBuffer::copyImage(BackingStoreCopy copyBehavior, ScaleBehavior scaleBehavior) const
141 {
142     notImplemented();
143     return nullptr;
144 }
145
146 RefPtr<Image> ImageBuffer::sinkIntoImage(std::unique_ptr<ImageBuffer> imageBuffer, ScaleBehavior scaleBehavior)
147 {
148     IntSize internalSize = imageBuffer->internalSize();
149     IntSize logicalSize = imageBuffer->logicalSize();
150     IntSize backingStoreSize = imageBuffer->m_data.backingStoreSize;
151     float resolutionScale = imageBuffer->m_resolutionScale;
152
153     notImplemented();
154     return nullptr;
155 }
156
157 BackingStoreCopy ImageBuffer::fastCopyImageMode()
158 {
159     return DontCopyBackingStore;
160 }
161
162 void ImageBuffer::drawConsuming(std::unique_ptr<ImageBuffer> imageBuffer, GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode)
163 {
164     imageBuffer->draw(destContext, destRect, srcRect, op, blendMode);
165 }
166
167 void ImageBuffer::draw(GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode)
168 {
169     auto bitmapTarget = reinterpret_cast<ID2D1BitmapRenderTarget*>(context().platformContext());
170     auto outputTarget = destContext.platformContext();
171
172     COMPtr<ID2D1Bitmap> image;
173     HRESULT hr = bitmapTarget->GetBitmap(&image);
174     if (!SUCCEEDED(hr))
175         return;
176
177     // If the render targets for the source and destination contexts do not match, move the image over.
178     if (destContext.platformContext() != m_data.m_compatibleTarget) {
179         COMPtr<ID2D1Bitmap> sourceImage = image;
180         image = nullptr;
181
182         auto bitmapProperties = D2D1::BitmapProperties();
183         GraphicsContext::systemFactory()->GetDesktopDpi(&bitmapProperties.dpiX, &bitmapProperties.dpiY);
184         hr = outputTarget->CreateSharedBitmap(__uuidof(ID2D1Bitmap), sourceImage.get(), &bitmapProperties, &image);
185         if (!SUCCEEDED(hr))
186             return;
187     }
188
189     FloatRect adjustedSrcRect = srcRect;
190     adjustedSrcRect.scale(m_resolutionScale, m_resolutionScale);
191
192     destContext.drawNativeImage(image, image->GetSize(), destRect, adjustedSrcRect, op, blendMode);
193
194     destContext.flush();
195 }
196
197 void ImageBuffer::drawPattern(GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, BlendMode blendMode)
198 {
199     FloatRect adjustedSrcRect = srcRect;
200     adjustedSrcRect.scale(m_resolutionScale, m_resolutionScale);
201
202     if (!context().isAcceleratedContext()) {
203         if (&destContext == &context() || destContext.isAcceleratedContext()) {
204             if (RefPtr<Image> copy = copyImage(CopyBackingStore)) // Drawing into our own buffer, need to deep copy.
205                 copy->drawPattern(destContext, destRect, adjustedSrcRect, patternTransform, phase, spacing, op, blendMode);
206         } else {
207             if (RefPtr<Image> imageForRendering = copyImage(DontCopyBackingStore))
208                 imageForRendering->drawPattern(destContext, destRect, adjustedSrcRect, patternTransform, phase, spacing, op, blendMode);
209         }
210     } else {
211         if (RefPtr<Image> copy = copyImage(CopyBackingStore))
212             copy->drawPattern(destContext, destRect, adjustedSrcRect, patternTransform, phase, spacing, op, blendMode);
213     }
214 }
215
216 RefPtr<Uint8ClampedArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect, IntSize* pixelArrayDimensions, CoordinateSystem coordinateSystem) const
217 {
218     if (context().isAcceleratedContext())
219         flushContext();
220
221     IntRect srcRect = rect;
222     if (coordinateSystem == LogicalCoordinateSystem)
223         srcRect.scale(m_resolutionScale);
224
225     if (pixelArrayDimensions)
226         *pixelArrayDimensions = srcRect.size();
227
228     return m_data.getData(srcRect, internalSize(), context().isAcceleratedContext(), true, 1);
229 }
230
231 RefPtr<Uint8ClampedArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect, IntSize* pixelArrayDimensions, CoordinateSystem coordinateSystem) const
232 {
233     if (context().isAcceleratedContext())
234         flushContext();
235
236     IntRect srcRect = rect;
237     if (coordinateSystem == LogicalCoordinateSystem)
238         srcRect.scale(m_resolutionScale);
239
240     if (pixelArrayDimensions)
241         *pixelArrayDimensions = srcRect.size();
242
243     return m_data.getData(srcRect, internalSize(), context().isAcceleratedContext(), false, 1);
244 }
245
246 void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, CoordinateSystem coordinateSystem)
247 {
248     if (context().isAcceleratedContext())
249         flushContext();
250
251     IntRect scaledSourceRect = sourceRect;
252     IntSize scaledSourceSize = sourceSize;
253     if (coordinateSystem == LogicalCoordinateSystem) {
254         scaledSourceRect.scale(m_resolutionScale);
255         scaledSourceSize.scale(m_resolutionScale);
256     }
257
258     m_data.putData(source, scaledSourceSize, scaledSourceRect, destPoint, internalSize(), context().isAcceleratedContext(), multiplied == Unmultiplied, 1);
259 }
260
261 String ImageBuffer::toDataURL(const String&, std::optional<double>, CoordinateSystem) const
262 {
263     notImplemented();
264     return ASCIILiteral("data:,");
265 }
266
267 Vector<uint8_t> ImageBuffer::toData(const String& mimeType, std::optional<double> quality) const
268 {
269     notImplemented();
270     return { };
271 }
272
273 String ImageDataToDataURL(const ImageData& source, const String& mimeType, const double* quality)
274 {
275     notImplemented();
276     return ASCIILiteral("data:,");
277 }
278
279 void ImageBuffer::transformColorSpace(ColorSpace, ColorSpace)
280 {
281     notImplemented();
282 }
283
284 } // namespace WebCore
285
286 #endif