1/*
2 * Copyright (C) 2017 Metrological Group B.V.
3 * Copyright (C) 2017 Igalia S.L.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "config.h"
30#include "NicosiaPaintingContextCairo.h"
31
32#if USE(CAIRO)
33
34#include "GraphicsContext.h"
35#include "GraphicsContextImplCairo.h"
36#include "NicosiaBuffer.h"
37#include "NicosiaCairoOperationRecorder.h"
38#include "NicosiaPaintingOperationReplayCairo.h"
39#include "PlatformContextCairo.h"
40#include "RefPtrCairo.h"
41#include <cairo.h>
42#include <utility>
43
44namespace Nicosia {
45
46PaintingContextCairo::ForPainting::ForPainting(Buffer& buffer)
47{
48 // Balanced by the deref in the s_bufferKey user data destroy callback.
49 buffer.ref();
50
51 m_cairo.surface = adoptRef(cairo_image_surface_create_for_data(buffer.data(),
52 CAIRO_FORMAT_ARGB32, buffer.size().width(), buffer.size().height(), buffer.stride()));
53
54 static cairo_user_data_key_t s_bufferKey;
55 cairo_surface_set_user_data(m_cairo.surface.get(), &s_bufferKey,
56 new std::pair<Buffer*, ForPainting*> { &buffer, this },
57 [](void* data)
58 {
59 auto* userData = static_cast<std::pair<Buffer*, ForPainting*>*>(data);
60
61 // Deref the Buffer object.
62 userData->first->deref();
63#if !ASSERT_DISABLED
64 // Mark the deletion of the cairo_surface_t object associated with this
65 // PaintingContextCairo as complete. This way we check that the cairo_surface_t
66 // object doesn't outlive the PaintingContextCairo through which it was used.
67 userData->second->m_deletionComplete = true;
68#endif
69 delete userData;
70 });
71
72 m_cairo.context = adoptRef(cairo_create(m_cairo.surface.get()));
73 m_platformContext = std::make_unique<WebCore::PlatformContextCairo>(m_cairo.context.get());
74 m_graphicsContext = std::make_unique<WebCore::GraphicsContext>(WebCore::GraphicsContextImplCairo::createFactory(*m_platformContext));
75}
76
77PaintingContextCairo::ForPainting::~ForPainting()
78{
79 cairo_surface_flush(m_cairo.surface.get());
80
81 m_graphicsContext = nullptr;
82 m_platformContext = nullptr;
83 m_cairo.context = nullptr;
84 m_cairo.surface = nullptr;
85
86 // With all the Cairo references purged, the cairo_surface_t object should be destroyed
87 // as well. This is checked by asserting that m_deletionComplete is true, which should
88 // be the case if the s_bufferKey user data destroy callback has been invoked upon the
89 // cairo_surface_t destruction.
90 ASSERT(m_deletionComplete);
91}
92
93WebCore::GraphicsContext& PaintingContextCairo::ForPainting::graphicsContext()
94{
95 return *m_graphicsContext;
96}
97
98void PaintingContextCairo::ForPainting::replay(const PaintingOperations& paintingOperations)
99{
100 PaintingOperationReplayCairo operationReplay { *m_platformContext };
101 for (auto& operation : paintingOperations)
102 operation->execute(operationReplay);
103}
104
105PaintingContextCairo::ForRecording::ForRecording(PaintingOperations& paintingOperations)
106{
107 m_graphicsContext = std::make_unique<WebCore::GraphicsContext>(
108 [&paintingOperations](WebCore::GraphicsContext& context)
109 {
110 return std::make_unique<CairoOperationRecorder>(context, paintingOperations);
111 });
112}
113
114PaintingContextCairo::ForRecording::~ForRecording() = default;
115
116WebCore::GraphicsContext& PaintingContextCairo::ForRecording::graphicsContext()
117{
118 return *m_graphicsContext;
119}
120
121void PaintingContextCairo::ForRecording::replay(const PaintingOperations&)
122{
123 ASSERT_NOT_REACHED();
124}
125
126} // namespace Nicosia
127
128#endif // USE(CAIRO)
129