[Win][Direct2D] Implement basic SVG support
[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 #if PLATFORM(COCOA)
48 #include "WebCoreSystemInterface.h"
49 #endif
50
51
52 namespace WebCore {
53
54 static FloatSize scaleSizeToUserSpace(const FloatSize& logicalSize, const IntSize& backingStoreSize, const IntSize& internalSize)
55 {
56     float xMagnification = static_cast<float>(backingStoreSize.width()) / internalSize.width();
57     float yMagnification = static_cast<float>(backingStoreSize.height()) / internalSize.height();
58     return FloatSize(logicalSize.width() * xMagnification, logicalSize.height() * yMagnification);
59 }
60
61 std::unique_ptr<ImageBuffer> ImageBuffer::createCompatibleBuffer(const FloatSize& size, const GraphicsContext& context)
62 {
63     if (size.isEmpty())
64         return nullptr;
65
66     RenderingMode renderingMode = context.renderingMode();
67     IntSize scaledSize = ImageBuffer::compatibleBufferSize(size, context);
68     bool success = false;
69     std::unique_ptr<ImageBuffer> buffer(new ImageBuffer(scaledSize, 1, ColorSpaceSRGB, renderingMode, &context, success));
70
71     if (!success)
72         return nullptr;
73
74     // Set up a corresponding scale factor on the graphics context.
75     buffer->context().scale(FloatSize(scaledSize.width() / size.width(), scaledSize.height() / size.height()));
76     return buffer;
77 }
78
79 ImageBuffer::ImageBuffer(const FloatSize& size, float resolutionScale, ColorSpace /*colorSpace*/, RenderingMode renderingMode, const GraphicsContext* targetContext, bool& success)
80     : m_logicalSize(size)
81     , m_resolutionScale(resolutionScale)
82 {
83     success = false; // Make early return mean failure.
84     float scaledWidth = std::ceil(resolutionScale * size.width());
85     float scaledHeight = std::ceil(resolutionScale * size.height());
86
87     // FIXME: Should we automatically use a lower resolution?
88     if (!FloatSize(scaledWidth, scaledHeight).isExpressibleAsIntSize())
89         return;
90
91     m_size = IntSize(scaledWidth, scaledHeight);
92     m_data.backingStoreSize = m_size;
93
94     bool accelerateRendering = renderingMode == Accelerated;
95     if (m_size.width() <= 0 || m_size.height() <= 0)
96         return;
97
98     // Prevent integer overflows
99     m_data.bytesPerRow = 4 * Checked<unsigned, RecordOverflow>(m_data.backingStoreSize.width());
100     Checked<size_t, RecordOverflow> numBytes = Checked<unsigned, RecordOverflow>(m_data.backingStoreSize.height()) * m_data.bytesPerRow;
101     if (numBytes.hasOverflowed())
102         return;
103
104     auto renderTarget = targetContext ? targetContext->platformContext() : nullptr;
105     if (!renderTarget)
106         renderTarget = GraphicsContext::defaultRenderTarget();
107     RELEASE_ASSERT(renderTarget);
108
109     COMPtr<ID2D1BitmapRenderTarget> bitmapContext;
110     HRESULT hr = renderTarget->CreateCompatibleRenderTarget(FloatSize(m_logicalSize), &bitmapContext);
111     if (!bitmapContext || !SUCCEEDED(hr))
112         return;
113
114     m_data.context = std::make_unique<GraphicsContext>(bitmapContext.get());
115     m_data.m_compatibleTarget = renderTarget;
116
117     success = true;
118 }
119
120 ImageBuffer::ImageBuffer(const FloatSize& size, float resolutionScale, ColorSpace imageColorSpace, RenderingMode renderingMode, bool& success)
121     : ImageBuffer(size, resolutionScale, imageColorSpace, renderingMode, nullptr, success)
122 {
123 }
124
125 ImageBuffer::~ImageBuffer()
126 {
127 }
128
129 FloatSize ImageBuffer::sizeForDestinationSize(FloatSize destinationSize) const
130 {
131     return scaleSizeToUserSpace(destinationSize, m_data.backingStoreSize, internalSize());
132 }
133
134 GraphicsContext& ImageBuffer::context() const
135 {
136     return *m_data.context;
137 }
138
139 void ImageBuffer::flushContext() const
140 {
141     if (!context().didBeginDraw())
142         return;
143
144     HRESULT hr = context().platformContext()->Flush();
145     ASSERT(SUCCEEDED(hr));
146 }
147
148 RefPtr<Image> ImageBuffer::copyImage(BackingStoreCopy copyBehavior, ScaleBehavior scaleBehavior) const
149 {
150     notImplemented();
151     return nullptr;
152 }
153
154 RefPtr<Image> ImageBuffer::sinkIntoImage(std::unique_ptr<ImageBuffer> imageBuffer, ScaleBehavior scaleBehavior)
155 {
156     IntSize internalSize = imageBuffer->internalSize();
157     IntSize logicalSize = imageBuffer->logicalSize();
158     IntSize backingStoreSize = imageBuffer->m_data.backingStoreSize;
159     float resolutionScale = imageBuffer->m_resolutionScale;
160
161     notImplemented();
162     return nullptr;
163 }
164
165 BackingStoreCopy ImageBuffer::fastCopyImageMode()
166 {
167     return DontCopyBackingStore;
168 }
169
170 void ImageBuffer::drawConsuming(std::unique_ptr<ImageBuffer> imageBuffer, GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode)
171 {
172     imageBuffer->draw(destContext, destRect, srcRect, op, blendMode);
173 }
174
175 void ImageBuffer::draw(GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode)
176 {
177     auto bitmapTarget = reinterpret_cast<ID2D1BitmapRenderTarget*>(context().platformContext());
178     auto outputTarget = destContext.platformContext();
179
180     COMPtr<ID2D1Bitmap> image;
181     HRESULT hr = bitmapTarget->GetBitmap(&image);
182     if (!SUCCEEDED(hr))
183         return;
184
185     // If the render targets for the source and destination contexts do not match, move the image over.
186     if (destContext.platformContext() != m_data.m_compatibleTarget) {
187         COMPtr<ID2D1Bitmap> sourceImage = image;
188         image = nullptr;
189
190         auto bitmapProperties = D2D1::BitmapProperties();
191         GraphicsContext::systemFactory()->GetDesktopDpi(&bitmapProperties.dpiX, &bitmapProperties.dpiY);
192         hr = outputTarget->CreateSharedBitmap(__uuidof(ID2D1Bitmap), sourceImage.get(), &bitmapProperties, &image);
193         if (!SUCCEEDED(hr))
194             return;
195     }
196
197     FloatRect adjustedSrcRect = srcRect;
198     adjustedSrcRect.scale(m_resolutionScale, m_resolutionScale);
199
200     destContext.drawNativeImage(image, image->GetSize(), destRect, adjustedSrcRect, op, blendMode);
201 }
202
203 void ImageBuffer::drawPattern(GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, BlendMode blendMode)
204 {
205     FloatRect adjustedSrcRect = srcRect;
206     adjustedSrcRect.scale(m_resolutionScale, m_resolutionScale);
207
208     if (!context().isAcceleratedContext()) {
209         if (&destContext == &context() || destContext.isAcceleratedContext()) {
210             if (RefPtr<Image> copy = copyImage(CopyBackingStore)) // Drawing into our own buffer, need to deep copy.
211                 copy->drawPattern(destContext, destRect, adjustedSrcRect, patternTransform, phase, spacing, op, blendMode);
212         } else {
213             if (RefPtr<Image> imageForRendering = copyImage(DontCopyBackingStore))
214                 imageForRendering->drawPattern(destContext, destRect, adjustedSrcRect, patternTransform, phase, spacing, op, blendMode);
215         }
216     } else {
217         if (RefPtr<Image> copy = copyImage(CopyBackingStore))
218             copy->drawPattern(destContext, destRect, adjustedSrcRect, patternTransform, phase, spacing, op, blendMode);
219     }
220 }
221
222 RefPtr<Uint8ClampedArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect, CoordinateSystem coordinateSystem) const
223 {
224     if (context().isAcceleratedContext())
225         flushContext();
226
227     IntRect srcRect = rect;
228     if (coordinateSystem == LogicalCoordinateSystem)
229         srcRect.scale(m_resolutionScale);
230
231     return m_data.getData(srcRect, internalSize(), context().isAcceleratedContext(), true, 1);
232 }
233
234 RefPtr<Uint8ClampedArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect, CoordinateSystem coordinateSystem) const
235 {
236     if (context().isAcceleratedContext())
237         flushContext();
238
239     IntRect srcRect = rect;
240     if (coordinateSystem == LogicalCoordinateSystem)
241         srcRect.scale(m_resolutionScale);
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& mimeType, const double* quality, CoordinateSystem) const
262 {
263     notImplemented();
264     return ASCIILiteral("data:,");
265 }
266
267 String ImageDataToDataURL(const ImageData& source, const String& mimeType, const double* quality)
268 {
269     notImplemented();
270     return ASCIILiteral("data:,");
271 }
272
273 void ImageBuffer::transformColorSpace(ColorSpace, ColorSpace)
274 {
275     notImplemented();
276 }
277
278 } // namespace WebCore
279
280 #endif