[Nicosia] Add threaded PaintingEngine implementation
authorzandobersek@gmail.com <zandobersek@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 9 Mar 2018 14:03:25 +0000 (14:03 +0000)
committerzandobersek@gmail.com <zandobersek@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 9 Mar 2018 14:03:25 +0000 (14:03 +0000)
https://bugs.webkit.org/show_bug.cgi?id=183511

Reviewed by Carlos Garcia Campos.

Add Nicosia::PaintingEngineThreaded, class that internally uses a thread
pool in which painting tasks are executed.

Implementation for now defaults to using GLib's GThreadPool, defaulting
to 4 threads that are exclusive to this pool. These parameters should be
fine-tuned in the future, or even made configurable, but are a solid
basis for testing.

In PaintingEngineThreaded::paint(), PaintingContext implementation is
used to record all the operations, and the gathered Vector is combined
with the Buffer object and dispatched into the thread pool. In the
thread function, the provided buffer and painting operations are run
through the PaintingContext implementation, replaying all the operations
on a painting context that draws into the given buffer.

The recorded operation objects implement the PaintingOperation interface
contain all the data necessary to replay a given operation. They can be
executed against a PaintingOperationReplay object, as is the case during
PaintingContext::replay(), or they can be dumped into a TextStream
object for debugging purposes.

PaintingContext now also provides the record() and replay() static
functions. PaintingContext objects now differ per purpose, which can be
either for painting or for recording. paint() and replay() use a
for-painting PaintingContext, and record() uses a for-recording one.
The for-painting PaintingContext receives a Buffer object, i.e. a memory
area on which it can draw, while the for-recording PaintingContext uses
the passed-in PaintingOperations Vector that should store all the
recorded operations.

The current Cairo implementation of PaintingContext is moved into
PaintingContextCairo::ForPainting. PaintingContextCairo::ForRecording is
added but is currently no-op until a Cairo-specific GraphicsContextImpl
with recording capabilities is added, allowing any call on the
GraphicsContext object used in PaintingContext::record() to be recorded
for later replay. PaintingOperationReplayCairo, inheriting from
PaintingOperationReplay, will be used for replay purposes, providing
only reference to the PlatformContextCairo object that is constructed in
PaintingContextCairo::ForPainting.

The Cairo-specific GraphicsContextImpl implementation will be added in
a separate patch. After that, PaintingEngine::create() will be modified
so that the Nicosia::PaintingEngineThreaded implementation can be used
for testing purposes, probably by setting an environment variable.

* platform/TextureMapper.cmake:
* platform/graphics/nicosia/NicosiaPaintingContext.cpp:
(Nicosia::PaintingContext::createForPainting):
(Nicosia::PaintingContext::createForRecording):
(Nicosia::PaintingContext::create): Deleted.
* platform/graphics/nicosia/NicosiaPaintingContext.h:
(Nicosia::PaintingContext::paint):
(Nicosia::PaintingContext::record):
(Nicosia::PaintingContext::replay):
* platform/graphics/nicosia/NicosiaPaintingEngineThreaded.cpp: Added.
(Nicosia::s_threadFunc):
(Nicosia::paintLayer):
(Nicosia::PaintingEngineThreaded::PaintingEngineThreaded):
(Nicosia::PaintingEngineThreaded::~PaintingEngineThreaded):
(Nicosia::PaintingEngineThreaded::paint):
* platform/graphics/nicosia/NicosiaPaintingEngineThreaded.h: Copied from Source/WebCore/platform/graphics/nicosia/NicosiaPaintingContext.cpp.
* platform/graphics/nicosia/NicosiaPaintingOperation.h: Copied from Source/WebCore/platform/graphics/nicosia/NicosiaPaintingContext.cpp.
* platform/graphics/nicosia/cairo/NicosiaPaintingContextCairo.cpp:
(Nicosia::PaintingContextCairo::ForPainting::ForPainting):
(Nicosia::PaintingContextCairo::ForPainting::~ForPainting):
(Nicosia::PaintingContextCairo::ForPainting::graphicsContext):
(Nicosia::PaintingContextCairo::ForPainting::replay):
(Nicosia::PaintingContextCairo::ForRecording::ForRecording):
(Nicosia::PaintingContextCairo::ForRecording::graphicsContext):
(Nicosia::PaintingContextCairo::ForRecording::replay):
(Nicosia::PaintingContextCairo::PaintingContextCairo): Deleted.
(Nicosia::PaintingContextCairo::~PaintingContextCairo): Deleted.
(Nicosia::PaintingContextCairo::graphicsContext): Deleted.
* platform/graphics/nicosia/cairo/NicosiaPaintingContextCairo.h:
* platform/graphics/nicosia/cairo/NicosiaPaintingOperationReplayCairo.h: Copied from Source/WebCore/platform/graphics/nicosia/NicosiaPaintingContext.cpp.
(Nicosia::PaintingOperationReplayCairo::PaintingOperationReplayCairo):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229460 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/platform/TextureMapper.cmake
Source/WebCore/platform/graphics/nicosia/NicosiaPaintingContext.cpp
Source/WebCore/platform/graphics/nicosia/NicosiaPaintingContext.h
Source/WebCore/platform/graphics/nicosia/NicosiaPaintingEngineThreaded.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/nicosia/NicosiaPaintingEngineThreaded.h [new file with mode: 0644]
Source/WebCore/platform/graphics/nicosia/NicosiaPaintingOperation.h [new file with mode: 0644]
Source/WebCore/platform/graphics/nicosia/cairo/NicosiaPaintingContextCairo.cpp
Source/WebCore/platform/graphics/nicosia/cairo/NicosiaPaintingContextCairo.h
Source/WebCore/platform/graphics/nicosia/cairo/NicosiaPaintingOperationReplayCairo.h [new file with mode: 0644]

index cf9a8d0..695855e 100644 (file)
@@ -1,5 +1,89 @@
 2018-03-09  Zan Dobersek  <zdobersek@igalia.com>
 
+        [Nicosia] Add threaded PaintingEngine implementation
+        https://bugs.webkit.org/show_bug.cgi?id=183511
+
+        Reviewed by Carlos Garcia Campos.
+
+        Add Nicosia::PaintingEngineThreaded, class that internally uses a thread
+        pool in which painting tasks are executed.
+
+        Implementation for now defaults to using GLib's GThreadPool, defaulting
+        to 4 threads that are exclusive to this pool. These parameters should be
+        fine-tuned in the future, or even made configurable, but are a solid
+        basis for testing.
+
+        In PaintingEngineThreaded::paint(), PaintingContext implementation is
+        used to record all the operations, and the gathered Vector is combined
+        with the Buffer object and dispatched into the thread pool. In the
+        thread function, the provided buffer and painting operations are run
+        through the PaintingContext implementation, replaying all the operations
+        on a painting context that draws into the given buffer.
+
+        The recorded operation objects implement the PaintingOperation interface
+        contain all the data necessary to replay a given operation. They can be
+        executed against a PaintingOperationReplay object, as is the case during
+        PaintingContext::replay(), or they can be dumped into a TextStream
+        object for debugging purposes.
+
+        PaintingContext now also provides the record() and replay() static
+        functions. PaintingContext objects now differ per purpose, which can be
+        either for painting or for recording. paint() and replay() use a
+        for-painting PaintingContext, and record() uses a for-recording one.
+        The for-painting PaintingContext receives a Buffer object, i.e. a memory
+        area on which it can draw, while the for-recording PaintingContext uses
+        the passed-in PaintingOperations Vector that should store all the
+        recorded operations.
+
+        The current Cairo implementation of PaintingContext is moved into
+        PaintingContextCairo::ForPainting. PaintingContextCairo::ForRecording is
+        added but is currently no-op until a Cairo-specific GraphicsContextImpl
+        with recording capabilities is added, allowing any call on the
+        GraphicsContext object used in PaintingContext::record() to be recorded
+        for later replay. PaintingOperationReplayCairo, inheriting from
+        PaintingOperationReplay, will be used for replay purposes, providing
+        only reference to the PlatformContextCairo object that is constructed in
+        PaintingContextCairo::ForPainting.
+
+        The Cairo-specific GraphicsContextImpl implementation will be added in
+        a separate patch. After that, PaintingEngine::create() will be modified
+        so that the Nicosia::PaintingEngineThreaded implementation can be used
+        for testing purposes, probably by setting an environment variable.
+
+        * platform/TextureMapper.cmake:
+        * platform/graphics/nicosia/NicosiaPaintingContext.cpp:
+        (Nicosia::PaintingContext::createForPainting):
+        (Nicosia::PaintingContext::createForRecording):
+        (Nicosia::PaintingContext::create): Deleted.
+        * platform/graphics/nicosia/NicosiaPaintingContext.h:
+        (Nicosia::PaintingContext::paint):
+        (Nicosia::PaintingContext::record):
+        (Nicosia::PaintingContext::replay):
+        * platform/graphics/nicosia/NicosiaPaintingEngineThreaded.cpp: Added.
+        (Nicosia::s_threadFunc):
+        (Nicosia::paintLayer):
+        (Nicosia::PaintingEngineThreaded::PaintingEngineThreaded):
+        (Nicosia::PaintingEngineThreaded::~PaintingEngineThreaded):
+        (Nicosia::PaintingEngineThreaded::paint):
+        * platform/graphics/nicosia/NicosiaPaintingEngineThreaded.h: Copied from Source/WebCore/platform/graphics/nicosia/NicosiaPaintingContext.cpp.
+        * platform/graphics/nicosia/NicosiaPaintingOperation.h: Copied from Source/WebCore/platform/graphics/nicosia/NicosiaPaintingContext.cpp.
+        * platform/graphics/nicosia/cairo/NicosiaPaintingContextCairo.cpp:
+        (Nicosia::PaintingContextCairo::ForPainting::ForPainting):
+        (Nicosia::PaintingContextCairo::ForPainting::~ForPainting):
+        (Nicosia::PaintingContextCairo::ForPainting::graphicsContext):
+        (Nicosia::PaintingContextCairo::ForPainting::replay):
+        (Nicosia::PaintingContextCairo::ForRecording::ForRecording):
+        (Nicosia::PaintingContextCairo::ForRecording::graphicsContext):
+        (Nicosia::PaintingContextCairo::ForRecording::replay):
+        (Nicosia::PaintingContextCairo::PaintingContextCairo): Deleted.
+        (Nicosia::PaintingContextCairo::~PaintingContextCairo): Deleted.
+        (Nicosia::PaintingContextCairo::graphicsContext): Deleted.
+        * platform/graphics/nicosia/cairo/NicosiaPaintingContextCairo.h:
+        * platform/graphics/nicosia/cairo/NicosiaPaintingOperationReplayCairo.h: Copied from Source/WebCore/platform/graphics/nicosia/NicosiaPaintingContext.cpp.
+        (Nicosia::PaintingOperationReplayCairo::PaintingOperationReplayCairo):
+
+2018-03-09  Zan Dobersek  <zdobersek@igalia.com>
+
         Remove some unused cruft in TextureMapperLayer.
 
         The ScrollingClient class is not used anymore since r229318.
index 63f965a..4d13d30 100644 (file)
@@ -54,6 +54,7 @@ if (USE_COORDINATED_GRAPHICS)
         platform/graphics/nicosia/NicosiaPaintingContext.cpp
         platform/graphics/nicosia/NicosiaPaintingEngine.cpp
         platform/graphics/nicosia/NicosiaPaintingEngineBasic.cpp
+        platform/graphics/nicosia/NicosiaPaintingEngineThreaded.cpp
 
         platform/graphics/nicosia/cairo/NicosiaPaintingContextCairo.cpp
     )
index 3fa140e..5be756a 100644 (file)
 
 namespace Nicosia {
 
-std::unique_ptr<PaintingContext> PaintingContext::create(Buffer& buffer)
-{
 #if USE(CAIRO)
-    return std::unique_ptr<PaintingContext>(new PaintingContextCairo(buffer));
+using ForPaintingClass = PaintingContextCairo::ForPainting;
+using ForRecordingClass = PaintingContextCairo::ForRecording;
 #else
 #error A Nicosia::PaintingContext implementation is required.
 #endif
+
+
+std::unique_ptr<PaintingContext> PaintingContext::createForPainting(Buffer& buffer)
+{
+    return std::unique_ptr<PaintingContext>(new ForPaintingClass(buffer));
+}
+
+std::unique_ptr<PaintingContext> PaintingContext::createForRecording(PaintingOperations& paintingOperations)
+{
+    return std::unique_ptr<PaintingContext>(new ForRecordingClass(paintingOperations));
 }
 
 } // namespace Nicosia
index afe69d7..5c4400e 100644 (file)
@@ -28,6 +28,7 @@
 
 #pragma once
 
+#include "NicosiaPaintingOperation.h"
 #include <memory>
 
 namespace WebCore {
@@ -44,17 +45,32 @@ public:
     template<typename T>
     static void paint(Buffer& buffer, const T& paintFunctor)
     {
-        auto paintingContext = PaintingContext::create(buffer);
+        auto paintingContext = PaintingContext::createForPainting(buffer);
         paintFunctor(paintingContext->graphicsContext());
     }
 
+    template<typename T>
+    static void record(PaintingOperations& paintingOperations, const T& recordFunctor)
+    {
+        auto recordingContext = PaintingContext::createForRecording(paintingOperations);
+        recordFunctor(recordingContext->graphicsContext());
+    }
+
+    static void replay(Buffer& buffer, const PaintingOperations& paintingOperations)
+    {
+        auto paintingContext = PaintingContext::createForPainting(buffer);
+        paintingContext->replay(paintingOperations);
+    }
+
     virtual ~PaintingContext() = default;
 
 protected:
     virtual WebCore::GraphicsContext& graphicsContext() = 0;
+    virtual void replay(const PaintingOperations&) = 0;
 
 private:
-    static std::unique_ptr<PaintingContext> create(Buffer&);
+    static std::unique_ptr<PaintingContext> createForPainting(Buffer&);
+    static std::unique_ptr<PaintingContext> createForRecording(PaintingOperations&);
 };
 
 } // namespace Nicosia
diff --git a/Source/WebCore/platform/graphics/nicosia/NicosiaPaintingEngineThreaded.cpp b/Source/WebCore/platform/graphics/nicosia/NicosiaPaintingEngineThreaded.cpp
new file mode 100644 (file)
index 0000000..64617ff
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 Metrological Group B.V.
+ * Copyright (C) 2017 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "NicosiaPaintingEngineThreaded.h"
+
+#include "GraphicsContext.h"
+#include "GraphicsLayer.h"
+#include "NicosiaBuffer.h"
+#include "NicosiaPaintingContext.h"
+#include <glib.h>
+#include <wtf/FastMalloc.h>
+
+namespace Nicosia {
+using namespace WebCore;
+
+struct TaskData {
+    WTF_MAKE_STRUCT_FAST_ALLOCATED;
+
+    Ref<Buffer> buffer;
+    PaintingOperations paintingOperations;
+};
+
+void s_threadFunc(gpointer data, gpointer)
+{
+    std::unique_ptr<TaskData> taskData(static_cast<TaskData*>(data));
+
+    PaintingContext::replay(taskData->buffer, taskData->paintingOperations);
+    taskData->buffer->completePainting();
+}
+
+static void paintLayer(GraphicsContext& context, GraphicsLayer& layer, const IntRect& sourceRect, const IntRect& mappedSourceRect, const IntRect& targetRect, float contentsScale, bool supportsAlpha)
+{
+    context.save();
+    context.clip(targetRect);
+    context.translate(targetRect.x(), targetRect.y());
+
+    if (supportsAlpha) {
+        context.setCompositeOperation(CompositeCopy);
+        context.fillRect(IntRect(IntPoint::zero(), sourceRect.size()), Color::transparent);
+        context.setCompositeOperation(CompositeSourceOver);
+    }
+
+    context.translate(-sourceRect.x(), -sourceRect.y());
+    context.scale(FloatSize(contentsScale, contentsScale));
+
+    layer.paintGraphicsLayerContents(context, mappedSourceRect);
+
+    context.restore();
+}
+
+PaintingEngineThreaded::PaintingEngineThreaded()
+{
+    // FIXME: these parameters should be fine-tuned, or maybe made configurable.
+    m_threadPool = g_thread_pool_new(s_threadFunc, nullptr, 4, TRUE, nullptr);
+}
+
+PaintingEngineThreaded::~PaintingEngineThreaded()
+{
+    g_thread_pool_free(m_threadPool, TRUE, FALSE);
+}
+
+bool PaintingEngineThreaded::paint(GraphicsLayer& layer, Ref<Buffer>&& buffer, const IntRect& sourceRect, const IntRect& mappedSourceRect, const IntRect& targetRect, float contentsScale)
+{
+    buffer->beginPainting();
+
+    PaintingOperations paintingOperations;
+    PaintingContext::record(paintingOperations,
+        [&](GraphicsContext& context)
+        {
+            paintLayer(context, layer, sourceRect, mappedSourceRect, targetRect, contentsScale, buffer->supportsAlpha());
+        });
+
+    g_thread_pool_push(m_threadPool, new TaskData { WTFMove(buffer), WTFMove(paintingOperations) }, nullptr);
+
+    return true;
+}
+
+} // namespace Nicosia
diff --git a/Source/WebCore/platform/graphics/nicosia/NicosiaPaintingEngineThreaded.h b/Source/WebCore/platform/graphics/nicosia/NicosiaPaintingEngineThreaded.h
new file mode 100644 (file)
index 0000000..391c8cc
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 Metrological Group B.V.
+ * Copyright (C) 2017 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "NicosiaPaintingEngine.h"
+
+typedef struct _GThreadPool GThreadPool;
+
+namespace Nicosia {
+
+class PaintingEngineThreaded final : public PaintingEngine {
+public:
+    PaintingEngineThreaded();
+    virtual ~PaintingEngineThreaded();
+
+private:
+    bool paint(WebCore::GraphicsLayer&, Ref<Buffer>&&, const WebCore::IntRect&, const WebCore::IntRect&, const WebCore::IntRect&, float) override;
+
+    GThreadPool* m_threadPool;
+};
+
+} // namespace Nicosia
diff --git a/Source/WebCore/platform/graphics/nicosia/NicosiaPaintingOperation.h b/Source/WebCore/platform/graphics/nicosia/NicosiaPaintingOperation.h
new file mode 100644 (file)
index 0000000..83f7766
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 Metrological Group B.V.
+ * Copyright (C) 2018 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <memory>
+#include <wtf/Vector.h>
+
+namespace WTF {
+class TextStream;
+}
+
+namespace Nicosia {
+
+struct PaintingOperationReplay { };
+
+struct PaintingOperation {
+    virtual ~PaintingOperation() = default;
+    virtual void execute(PaintingOperationReplay&) = 0;
+    virtual void dump(WTF::TextStream&) = 0;
+};
+
+using PaintingOperations = Vector<std::unique_ptr<PaintingOperation>>;
+
+} // namespace Nicosia
index b05f533..71615bb 100644 (file)
@@ -34,6 +34,7 @@
 #include "GraphicsContext.h"
 #include "GraphicsContextImplCairo.h"
 #include "NicosiaBuffer.h"
+#include "NicosiaPaintingOperationReplayCairo.h"
 #include "PlatformContextCairo.h"
 #include "RefPtrCairo.h"
 #include <cairo.h>
@@ -41,7 +42,7 @@
 
 namespace Nicosia {
 
-PaintingContextCairo::PaintingContextCairo(Buffer& buffer)
+PaintingContextCairo::ForPainting::ForPainting(Buffer& buffer)
 {
     // Balanced by the deref in the s_bufferKey user data destroy callback.
     buffer.ref();
@@ -51,10 +52,10 @@ PaintingContextCairo::PaintingContextCairo(Buffer& buffer)
 
     static cairo_user_data_key_t s_bufferKey;
     cairo_surface_set_user_data(m_cairo.surface.get(), &s_bufferKey,
-        new std::pair<Buffer*, PaintingContextCairo*> { &buffer, this },
+        new std::pair<Buffer*, ForPainting*> { &buffer, this },
         [](void* data)
         {
-            auto* userData = static_cast<std::pair<Buffer*, PaintingContextCairo*>*>(data);
+            auto* userData = static_cast<std::pair<Buffer*, ForPainting*>*>(data);
 
             // Deref the Buffer object.
             userData->first->deref();
@@ -72,7 +73,7 @@ PaintingContextCairo::PaintingContextCairo(Buffer& buffer)
     m_graphicsContext = std::make_unique<WebCore::GraphicsContext>(WebCore::GraphicsContextImplCairo::createFactory(*m_platformContext));
 }
 
-PaintingContextCairo::~PaintingContextCairo()
+PaintingContextCairo::ForPainting::~ForPainting()
 {
     cairo_surface_flush(m_cairo.surface.get());
 
@@ -88,11 +89,40 @@ PaintingContextCairo::~PaintingContextCairo()
     ASSERT(m_deletionComplete);
 }
 
-WebCore::GraphicsContext& PaintingContextCairo::graphicsContext()
+WebCore::GraphicsContext& PaintingContextCairo::ForPainting::graphicsContext()
 {
     return *m_graphicsContext;
 }
 
+void PaintingContextCairo::ForPainting::replay(const PaintingOperations& paintingOperations)
+{
+    PaintingOperationReplayCairo operationReplay { *m_platformContext };
+    for (auto& operation : paintingOperations)
+        operation->execute(operationReplay);
+}
+
+PaintingContextCairo::ForRecording::ForRecording(PaintingOperations& paintingOperations)
+{
+    m_graphicsContext = std::make_unique<WebCore::GraphicsContext>(
+        [&paintingOperations](WebCore::GraphicsContext&)
+        {
+            // FIXME: return a GraphicsContextImpl with recording capabilities.
+            return nullptr;
+        });
+}
+
+PaintingContextCairo::ForRecording::~ForRecording() = default;
+
+WebCore::GraphicsContext& PaintingContextCairo::ForRecording::graphicsContext()
+{
+    return *m_graphicsContext;
+}
+
+void PaintingContextCairo::ForRecording::replay(const PaintingOperations&)
+{
+    ASSERT_NOT_REACHED();
+}
+
 } // namespace Nicosia
 
 #endif // USE(CAIRO)
index ef381e2..18ee482 100644 (file)
@@ -44,24 +44,40 @@ class PlatformContextCairo;
 
 namespace Nicosia {
 
-class PaintingContextCairo final : public PaintingContext {
+class PaintingContextCairo final {
 public:
-    explicit PaintingContextCairo(Buffer&);
-    virtual ~PaintingContextCairo();
+    class ForPainting final : public PaintingContext {
+    public:
+        explicit ForPainting(Buffer&);
+        virtual ~ForPainting();
 
-private:
-    WebCore::GraphicsContext& graphicsContext() override;
+    private:
+        WebCore::GraphicsContext& graphicsContext() override;
+        void replay(const PaintingOperations&) override;
 
-    struct {
-        RefPtr<cairo_surface_t> surface;
-        RefPtr<cairo_t> context;
-    } m_cairo;
-    std::unique_ptr<WebCore::PlatformContextCairo> m_platformContext;
-    std::unique_ptr<WebCore::GraphicsContext> m_graphicsContext;
+        struct {
+            RefPtr<cairo_surface_t> surface;
+            RefPtr<cairo_t> context;
+        } m_cairo;
+        std::unique_ptr<WebCore::PlatformContextCairo> m_platformContext;
+        std::unique_ptr<WebCore::GraphicsContext> m_graphicsContext;
 
 #ifndef NDEBUG
-    bool m_deletionComplete { false };
+        bool m_deletionComplete { false };
 #endif
+    };
+
+    class ForRecording final : public PaintingContext {
+    public:
+        ForRecording(PaintingOperations&);
+        virtual ~ForRecording();
+
+    private:
+        WebCore::GraphicsContext& graphicsContext() override;
+        void replay(const PaintingOperations&) override;
+
+        std::unique_ptr<WebCore::GraphicsContext> m_graphicsContext;
+    };
 };
 
 } // namespace Nicosia
diff --git a/Source/WebCore/platform/graphics/nicosia/cairo/NicosiaPaintingOperationReplayCairo.h b/Source/WebCore/platform/graphics/nicosia/cairo/NicosiaPaintingOperationReplayCairo.h
new file mode 100644 (file)
index 0000000..7d81eeb
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 Metrological Group B.V.
+ * Copyright (C) 2018 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "NicosiaPaintingOperation.h"
+
+namespace WebCore {
+class PlatformContextCairo;
+}
+
+namespace Nicosia {
+
+struct PaintingOperationReplayCairo : PaintingOperationReplay {
+    PaintingOperationReplayCairo(WebCore::PlatformContextCairo& platformContext)
+        : platformContext(platformContext)
+    { }
+
+    WebCore::PlatformContextCairo& platformContext;
+};
+
+}