1/*
2 * Copyright (C) 2018 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#include "config.h"
27#include "CustomPaintCanvas.h"
28
29#if ENABLE(CSS_PAINTING_API)
30
31#include "ImageBitmap.h"
32#include "PaintRenderingContext2D.h"
33
34namespace WebCore {
35
36Ref<CustomPaintCanvas> CustomPaintCanvas::create(ScriptExecutionContext& context, unsigned width, unsigned height)
37{
38 return adoptRef(*new CustomPaintCanvas(context, width, height));
39}
40
41CustomPaintCanvas::CustomPaintCanvas(ScriptExecutionContext& context, unsigned width, unsigned height)
42 : ContextDestructionObserver(&context)
43 , m_size(width, height)
44{
45}
46
47CustomPaintCanvas::~CustomPaintCanvas()
48{
49 notifyObserversCanvasDestroyed();
50
51 m_context = nullptr; // Ensure this goes away before the ImageBuffer.
52}
53
54unsigned CustomPaintCanvas::width() const
55{
56 return m_size.width();
57}
58
59void CustomPaintCanvas::setWidth(unsigned newWidth)
60{
61 return m_size.setWidth(newWidth);
62}
63
64unsigned CustomPaintCanvas::height() const
65{
66 return m_size.height();
67}
68
69void CustomPaintCanvas::setHeight(unsigned newHeight)
70{
71 return m_size.setHeight(newHeight);
72}
73
74const IntSize& CustomPaintCanvas::size() const
75{
76 return m_size;
77}
78
79void CustomPaintCanvas::setSize(const IntSize& newSize)
80{
81 m_size = newSize;
82}
83
84ExceptionOr<RefPtr<PaintRenderingContext2D>> CustomPaintCanvas::getContext()
85{
86 if (m_context)
87 return { RefPtr<PaintRenderingContext2D> { &downcast<PaintRenderingContext2D>(*m_context) } };
88
89 m_context = PaintRenderingContext2D::create(*this);
90 downcast<PaintRenderingContext2D>(*m_context).setUsesDisplayListDrawing(true);
91 downcast<PaintRenderingContext2D>(*m_context).setTracksDisplayListReplay(false);
92
93 return { RefPtr<PaintRenderingContext2D> { &downcast<PaintRenderingContext2D>(*m_context) } };
94}
95
96void CustomPaintCanvas::replayDisplayList(GraphicsContext* ctx) const
97{
98 ASSERT(!m_destinationGraphicsContext);
99 if (!width() || !height())
100 return;
101
102 // FIXME: Using an intermediate buffer is not needed if there are no composite operations.
103 auto clipBounds = ctx->clipBounds();
104
105 auto image = ImageBuffer::createCompatibleBuffer(clipBounds.size(), *ctx);
106 if (!image)
107 return;
108
109 m_destinationGraphicsContext = &image->context();
110 m_destinationGraphicsContext->translate(-clipBounds.location());
111 if (m_context)
112 m_context->paintRenderingResultsToCanvas();
113 m_destinationGraphicsContext = nullptr;
114
115 ctx->drawImageBuffer(*image, clipBounds);
116}
117
118Image* CustomPaintCanvas::copiedImage() const
119{
120 ASSERT(!m_destinationGraphicsContext);
121 if (!width() || !height())
122 return nullptr;
123
124 m_copiedBuffer = ImageBuffer::create(size(), Unaccelerated, 1, ColorSpaceSRGB, nullptr);
125 if (!m_copiedBuffer)
126 return nullptr;
127
128 m_destinationGraphicsContext = &m_copiedBuffer->context();
129 if (m_context)
130 m_context->paintRenderingResultsToCanvas();
131 m_destinationGraphicsContext = nullptr;
132
133 m_copiedImage = m_copiedBuffer->copyImage(m_copiedBuffer->fastCopyImageMode(), PreserveResolution::Yes);
134 return m_copiedImage.get();
135}
136
137GraphicsContext* CustomPaintCanvas::drawingContext() const
138{
139 return m_destinationGraphicsContext;
140}
141
142GraphicsContext* CustomPaintCanvas::existingDrawingContext() const
143{
144 return drawingContext();
145}
146
147void CustomPaintCanvas::makeRenderingResultsAvailable()
148{
149 if (m_context)
150 m_context->paintRenderingResultsToCanvas();
151}
152
153}
154#endif
155