common composite: code refactoring
authorHermet Park <hermetpark@gmail.com>
Fri, 25 Dec 2020 10:47:01 +0000 (19:47 +0900)
committerJunsuChoi <jsuya.choi@samsung.com>
Mon, 28 Dec 2020 01:18:23 +0000 (10:18 +0900)
Splited out ClipPath routine from other pixel compositions'
since yet it's unlikely compatible...

Also revise internal engine interfaces to be simpler.

This is a step forward to enhance masking feature.

Change-Id: Ic86983f0701defd6ef4c9cc4b7bb795753b0266e

14 files changed:
inc/thorvg.h
src/examples/Masking.cpp
src/lib/gl_engine/tvgGlCommon.h
src/lib/gl_engine/tvgGlRenderer.cpp
src/lib/gl_engine/tvgGlRenderer.h
src/lib/sw_engine/tvgSwRenderer.cpp
src/lib/sw_engine/tvgSwRenderer.h
src/lib/tvgCanvasImpl.h
src/lib/tvgPaint.h
src/lib/tvgPicture.cpp
src/lib/tvgPictureImpl.h
src/lib/tvgRender.h
src/lib/tvgSceneImpl.h
src/lib/tvgShapeImpl.h

index 01f1904..e525dc7 100644 (file)
@@ -279,6 +279,7 @@ public:
 
     Result size(float w, float h) noexcept;
     Result size(float* w, float* h) const noexcept;
+    const uint32_t* data() const noexcept;
 
     static std::unique_ptr<Picture> gen() noexcept;
 
index 08eb1ee..4da3aa1 100644 (file)
@@ -12,11 +12,12 @@ void tvgDrawCmds(tvg::Canvas* canvas)
     if (!canvas) return;
 
     //Mask Target 2
+#if 0
     auto scene = tvg::Scene::gen();
     scene->opacity(127);
     scene->scale(1.2);
     scene->reserve(2);
-
+#endif
     //Star
     auto shape = tvg::Shape::gen();
 
@@ -33,17 +34,20 @@ void tvgDrawCmds(tvg::Canvas* canvas)
     shape->lineTo(146, 143);
     shape->close();
     shape->fill(0, 0, 255, 255);
-    shape->stroke(10);
-    shape->stroke(255, 255, 255, 255);
-    shape->opacity(127);
+//    shape->stroke(10);
+//    shape->stroke(255, 255, 255, 255);
+    //shape->opacity(127);
 
-    scene->push(move(shape));
+//    scene->push(move(shape));
 
     //Alpha Mask
-    auto mask2 = tvg::Shape::gen();
-    mask2->appendCircle(200, 200, 125, 125);
-    mask2->fill(255, 255, 255, 100);
+    auto mask = tvg::Shape::gen();
+    mask->appendCircle(200, 200, 125, 125);
+    mask->fill(255, 255, 255, 255);
+    shape->composite(move(mask), tvg::CompositeMethod::AlphaMask);
+    canvas->push(move(shape));
 
+#if 0
     scene->composite(move(mask2), tvg::CompositeMethod::AlphaMask);
     if (canvas->push(move(scene)) != tvg::Result::Success) return;
 
@@ -66,9 +70,7 @@ void tvgDrawCmds(tvg::Canvas* canvas)
 
     picture->composite(move(mask), tvg::CompositeMethod::AlphaMask);
     if (canvas->push(move(picture)) != tvg::Result::Success) return;
-
-
-
+#endif
 }
 
 
index 7c5ba2e..31dd102 100644 (file)
@@ -54,6 +54,7 @@ class GlGeometry;
 \r
 struct GlShape\r
 {\r
+  const Shape* shape = nullptr;\r
   float viewWd;\r
   float viewHt;\r
   RenderUpdateFlag updateFlag;\r
index 1a4cbed..bae6e4f 100644 (file)
@@ -73,7 +73,7 @@ bool GlRenderer::sync()
 }
 
 
-bool GlRenderer::renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
+bool GlRenderer::renderRegion(TVG_UNUSED RenderData data, TVG_UNUSED uint32_t* x, TVG_UNUSED uint32_t* y, TVG_UNUSED uint32_t* w, TVG_UNUSED uint32_t* h)
 {
     return true;
 }
@@ -102,31 +102,29 @@ bool GlRenderer::postRender()
 }
 
 
-void* GlRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+void* GlRenderer::addCompositor(TVG_UNUSED CompositeMethod method, TVG_UNUSED uint32_t x, TVG_UNUSED uint32_t y, TVG_UNUSED uint32_t w, TVG_UNUSED uint32_t h, TVG_UNUSED uint32_t opacity)
 {
     //TODO: Prepare frameBuffer & Setup render target for composition
     return nullptr;
 }
 
 
-bool GlRenderer::endComposite(void* ctx, uint32_t opacity)
+bool GlRenderer::delCompositor(TVG_UNUSED void* cmp)
 {
-    //TODO: Composite Framebuffer to main surface
+    //TODO: delete the given compositor and restore the context
     return false;
 }
 
 
-bool GlRenderer::render(const Picture& picture, void *data)
+bool GlRenderer::renderImage(TVG_UNUSED void* data, TVG_UNUSED void* cmp)
 {
-    //TODO Draw Bitmap Image
-
-    return true;
+    return false;
 }
 
 
-bool GlRenderer::render(const Shape& shape, void* data)
+bool GlRenderer::renderShape(RenderData data, TVG_UNUSED void* cmp)
 {
-    GlShape* sdata = static_cast<GlShape*>(data);
+    auto sdata = static_cast<GlShape*>(data);
     if (!sdata) return false;
 
     uint8_t r, g, b, a;
@@ -139,17 +137,17 @@ bool GlRenderer::render(const Shape& shape, void* data)
     {
         if (flags & RenderUpdateFlag::Gradient)
         {
-            const Fill* gradient = shape.fill();
+            const Fill* gradient = sdata->shape->fill();
             drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient);
         }
         else if (flags & RenderUpdateFlag::Color)
         {
-            shape.fillColor(&r, &g, &b, &a);
+            sdata->shape->fillColor(&r, &g, &b, &a);
             drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Color);
         }
         if (flags & RenderUpdateFlag::Stroke)
         {
-            shape.strokeColor(&r, &g, &b, &a);
+            sdata->shape->strokeColor(&r, &g, &b, &a);
             drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Stroke);
         }
     }
@@ -158,9 +156,9 @@ bool GlRenderer::render(const Shape& shape, void* data)
 }
 
 
-bool GlRenderer::dispose(void *data)
+bool GlRenderer::dispose(RenderData data)
 {
-    GlShape* sdata = static_cast<GlShape*>(data);
+    auto sdata = static_cast<GlShape*>(data);
     if (!sdata) return false;
 
     delete sdata;
@@ -168,20 +166,21 @@ bool GlRenderer::dispose(void *data)
 }
 
 
-void* GlRenderer::prepare(TVG_UNUSED const Picture& picture, TVG_UNUSED void* data, TVG_UNUSED uint32_t *buffer, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, TVG_UNUSED Array<Composite>& compList, TVG_UNUSED RenderUpdateFlag flags)
+RenderData GlRenderer::prepare(TVG_UNUSED const Picture& picture, TVG_UNUSED RenderData data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, TVG_UNUSED Array<RenderData>& clips, TVG_UNUSED RenderUpdateFlag flags)
 {
     //TODO:
     return nullptr;
 }
 
 
-void* GlRenderer::prepare(const Shape& shape, void* data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags)
+RenderData GlRenderer::prepare(const Shape& shape, RenderData data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
 {
     //prepare shape data
     GlShape* sdata = static_cast<GlShape*>(data);
     if (!sdata) {
         sdata = new GlShape;
         if (!sdata) return nullptr;
+        sdata->shape = &shape;
     }
 
     sdata->viewWd = static_cast<float>(surface.w);
index d7cb96c..d1da960 100644 (file)
@@ -30,16 +30,16 @@ class GlRenderer : public RenderMethod
 public:
     Surface surface = {nullptr, 0, 0, 0};
 
-    void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) override;
-    void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) override;
-    bool dispose(void *data) override;
-    void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
-    bool endComposite(void* ctx, uint32_t opacity) override;
+    RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
+    RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
+    bool dispose(RenderData data) override;
+    void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) override;
+    bool delCompositor(void* cmp) override;
     bool preRender() override;
-    bool render(const Shape& shape, void *data) override;
-    bool render(const Picture& picture, void *data) override;
+    bool renderShape(RenderData data, void* cmp) override;
+    bool renderImage(RenderData data, void* cmp) override;
     bool postRender() override;
-    bool renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
+    bool renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
     bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h);
     bool sync() override;
     bool clear() override;
index de76176..cbb51dc 100644 (file)
@@ -33,9 +33,11 @@ static uint32_t rendererCnt = 0;
 struct SwComposite
 {
     SwSurface surface;
-    SwSurface* recover;
+    SwComposite* recover;
     SwImage image;
     SwBBox bbox;
+    CompositeMethod method;
+    uint32_t opacity;
     bool valid;
 };
 
@@ -45,7 +47,7 @@ struct SwTask : Task
     Matrix* transform = nullptr;
     SwSurface* surface = nullptr;
     RenderUpdateFlag flags = RenderUpdateFlag::None;
-    Array<Composite> compList;
+    Array<RenderData> clips;
     uint32_t opacity;
     SwBBox bbox = {{0, 0}, {0, 0}};       //Whole Rendering Region
 
@@ -102,7 +104,7 @@ struct SwShapeTask : SwTask
                        shape outline below stroke could be full covered by stroke drawing.
                        Thus it turns off antialising in that condition. */
                     auto antiAlias = (strokeAlpha == 255 && strokeWidth > 2) ? false : true;
-                    if (!shapeGenRle(&shape, sdata, clip, antiAlias, compList.count > 0 ? true : false)) goto end;
+                    if (!shapeGenRle(&shape, sdata, clip, antiAlias, clips.count > 0 ? true : false)) goto end;
                     ++addStroking;
                 }
             }
@@ -131,22 +133,18 @@ struct SwShapeTask : SwTask
             }
         }
 
-        //Composition
-        for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) {
-            auto compShape = &static_cast<SwShapeTask*>((*comp).edata)->shape;
-            if ((*comp).method == CompositeMethod::ClipPath) {
-                //Clip shape rle
-                if (shape.rle) {
-                    if (compShape->rect) rleClipRect(shape.rle, &compShape->bbox);
-                    else if (compShape->rle) rleClipPath(shape.rle, compShape->rle);
-                }
-                //Clip stroke rle
-                if (shape.strokeRle) {
-                    if (compShape->rect) rleClipRect(shape.strokeRle, &compShape->bbox);
-                    else if (compShape->rle) rleClipPath(shape.strokeRle, compShape->rle);
-                }                
-            } else if ((*comp).method == CompositeMethod::AlphaMask) {
-                rleAlphaMask(shape.rle, compShape->rle);
+        //Clip Path
+        for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) {
+            auto compShape = &static_cast<SwShapeTask*>(*comp)->shape;
+            //Clip shape rle
+            if (shape.rle) {
+                if (compShape->rect) rleClipRect(shape.rle, &compShape->bbox);
+                else if (compShape->rle) rleClipPath(shape.rle, compShape->rle);
+            }
+            //Clip stroke rle
+            if (shape.strokeRle) {
+                if (compShape->rect) rleClipRect(shape.strokeRle, &compShape->bbox);
+                else if (compShape->rle) rleClipPath(shape.strokeRle, compShape->rle);
             }
         }
     end:
@@ -167,7 +165,6 @@ struct SwImageTask : SwTask
 {
     SwImage image;
     const Picture* pdata = nullptr;
-    uint32_t* pixels = nullptr;
 
     void run(unsigned tid) override
     {
@@ -181,23 +178,19 @@ struct SwImageTask : SwTask
             imageReset(&image);
             if (!imagePrepare(&image, pdata, tid, clip, transform, bbox)) goto end;
 
-            //Composition?
-            if (compList.count > 0) {
+            //Clip Path?
+            if (clips.count > 0) {
                 if (!imageGenRle(&image, pdata, clip, bbox, false, true)) goto end;
                 if (image.rle) {
-                    for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) {
-                        auto compShape = &static_cast<SwShapeTask*>((*comp).edata)->shape;
-                        if ((*comp).method == CompositeMethod::ClipPath) {
-                            if (compShape->rect) rleClipRect(image.rle, &compShape->bbox);
-                            else if (compShape->rle) rleClipPath(image.rle, compShape->rle);
-                        } else if ((*comp).method == CompositeMethod::AlphaMask) {
-                            rleAlphaMask(image.rle, compShape->rle);
-                        }
+                    for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) {
+                        auto compShape = &static_cast<SwShapeTask*>(*comp)->shape;
+                        if (compShape->rect) rleClipRect(image.rle, &compShape->bbox);
+                        else if (compShape->rle) rleClipPath(image.rle, compShape->rle);
                     }
                 }
             }
         }
-        if (pixels) image.data = pixels;
+        image.data = const_cast<uint32_t*>(pdata->data());
     end:
         imageDelOutline(&image, tid);
     }
@@ -255,6 +248,7 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
     if (!surface) {
         surface = new SwSurface;
         if (!surface) return false;
+        mainSurface = surface;
     }
 
     surface->buffer = buffer;
@@ -278,40 +272,85 @@ bool SwRenderer::postRender()
     tasks.clear();
 
     //Free Composite Caches
-    for (auto comp = composites.data; comp < (composites.data + composites.count); ++comp) {
+    for (auto comp = compositors.data; comp < (compositors.data + compositors.count); ++comp) {
         free((*comp)->image.data);
         delete(*comp);
     }
-    composites.reset();
+    compositors.reset();
 
     return true;
 }
 
 
-bool SwRenderer::renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
+bool SwRenderer::renderImage(RenderData data, TVG_UNUSED void* cmp)
 {
-    static_cast<SwTask*>(data)->bounds(x, y, w, h);
+    auto task = static_cast<SwImageTask*>(data);
+    task->done();
 
-    return true;
-}
+    if (task->opacity == 0) return true;
 
+    return rasterImage(surface, &task->image, task->transform, task->bbox, task->opacity);
+}
 
 
-bool SwRenderer::render(TVG_UNUSED const Picture& picture, void *data)
+bool SwRenderer::renderShape(RenderData data, TVG_UNUSED void* cmp)
 {
-    auto task = static_cast<SwImageTask*>(data);
+    auto task = static_cast<SwShapeTask*>(data);
     task->done();
 
-    return rasterImage(surface, &task->image, task->transform, task->bbox, task->opacity);
+    if (task->opacity == 0) return true;
+
+    uint32_t opacity;
+    void *cmp2 = nullptr;
+
+    //Do Composition
+    if (task->compStroking) {
+        uint32_t x, y, w, h;
+        task->bounds(&x, &y, &w, &h);
+        opacity = 255;
+        //CompositeMethod::None is used for a default alpha blending
+        cmp2 = addCompositor(CompositeMethod::None, x, y, w, h, opacity);
+    //No Composition
+    } else {
+        opacity = task->opacity;
+    }
+
+    //Main raster stage
+    uint8_t r, g, b, a;
+
+    if (auto fill = task->sdata->fill()) {
+        //FIXME: pass opacity to apply gradient fill?
+        rasterGradientShape(surface, &task->shape, fill->id());
+    } else{
+        task->sdata->fillColor(&r, &g, &b, &a);
+        a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
+        if (a > 0) rasterSolidShape(surface, &task->shape, r, g, b, a);
+    }
+
+    task->sdata->strokeColor(&r, &g, &b, &a);
+    a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
+    if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a);
+
+    //Composition (Shape + Stroke) stage
+    if (task->compStroking) delCompositor(cmp2);
+
+    return true;
+}
+
+bool SwRenderer::renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
+{
+    static_cast<SwTask*>(data)->bounds(x, y, w, h);
+
+    return true;
 }
 
 
-void* SwRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+void* SwRenderer::addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity)
 {
     SwComposite* comp = nullptr;
 
     //Use cached data
-    for (auto p = composites.data; p < (composites.data + composites.count); ++p) {
+    for (auto p = compositors.data; p < (compositors.data + compositors.count); ++p) {
         if ((*p)->valid) {
             comp = *p;
             break;
@@ -328,17 +367,19 @@ void* SwRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
             delete(comp);
             return nullptr;
         }
-        composites.push(comp);
+        compositors.push(comp);
     }
 
     comp->valid = false;
+    comp->method = method;
+    comp->opacity = opacity;
 
     //Boundary Check
     if (x + w > surface->w) w = (surface->w - x);
     if (y + h > surface->h) h = (surface->h - y);
 
 #ifdef THORVG_LOG_ENABLED
-    printf("SW_ENGINE: Using intermediate opacity composition [Region: %d %d %d %d]\n", x, y, w, h);
+    printf("SW_ENGINE: Using intermediate composition [Method: %d][Region: %d %d %d %d]\n", (int)method, x, y, w, h);
 #endif
 
     comp->bbox.min.x = x;
@@ -365,75 +406,38 @@ void* SwRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
     comp->surface.w = comp->image.w;
     comp->surface.h = comp->image.h;
 
+    //Switch active compositor
+    comp->recover = compositor;   //Backup current compositor
+    compositor = comp;
+
     //Switch render target
-    comp->recover = surface;
     surface = &comp->surface;
 
     return comp;
 }
 
 
-bool SwRenderer::endComposite(void* p, uint32_t opacity)
+bool SwRenderer::delCompositor(void* ctx)
 {
-    if (!p) return false;
-    auto comp = static_cast<SwComposite*>(p);
-
-    //Recover render target
-    surface = comp->recover;
-
-    auto ret = rasterImage(surface, &comp->image, nullptr, comp->bbox, opacity);
+    if (!ctx) return false;
 
+    auto comp = static_cast<SwComposite*>(ctx);
     comp->valid = true;
 
-    return ret;
-}
-
+    //Recover Context
+    compositor = comp->recover;
+    surface = compositor ? &compositor->surface : mainSurface;
 
-bool SwRenderer::render(TVG_UNUSED const Shape& shape, void *data)
-{
-    auto task = static_cast<SwShapeTask*>(data);
-    task->done();
-    
-    if (task->opacity == 0) return true;
-
-    uint32_t opacity;
-    void *ctx = nullptr;
-
-    //Do Composition
-    if (task->compStroking) {
-        uint32_t x, y, w, h;
-        task->bounds(&x, &y, &w, &h);
-        ctx = beginComposite(x, y, w, h);
-        opacity = 255;
-    //No Composition
-    } else {
-        opacity = task->opacity;
+    //Default is alpha blending
+    if (comp->method == CompositeMethod::None) {
+        return rasterImage(surface, &comp->image, nullptr, comp->bbox, comp->opacity);
     }
 
-    //Main raster stage
-    uint8_t r, g, b, a;
-
-    if (auto fill = task->sdata->fill()) {
-        //FIXME: pass opacity to apply gradient fill?
-        rasterGradientShape(surface, &task->shape, fill->id());
-    } else{
-        task->sdata->fillColor(&r, &g, &b, &a);
-        a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
-        if (a > 0) rasterSolidShape(surface, &task->shape, r, g, b, a);
-    }
-
-    task->sdata->strokeColor(&r, &g, &b, &a);
-    a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
-    if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a);
-
-    //Composition (Shape + Stroke) stage
-    if (task->compStroking) endComposite(ctx, task->opacity);
-
     return true;
 }
 
 
-bool SwRenderer::dispose(void *data)
+bool SwRenderer::dispose(RenderData data)
 {
     auto task = static_cast<SwTask*>(data);
     if (!task) return true;
@@ -447,14 +451,19 @@ bool SwRenderer::dispose(void *data)
 }
 
 
-void SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags)
+void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
 {
-    if (compList.count > 0) {
+    if (flags == RenderUpdateFlag::None) return task;
+
+    //Finish previous task if it has duplicated request.
+    task->done();
+
+    if (clips.count > 0) {
         //Guarantee composition targets get ready.
-        for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) {
-            static_cast<SwShapeTask*>((*comp).edata)->done();
+        for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) {
+            static_cast<SwShapeTask*>(*comp)->done();
         }
-        task->compList = compList;
+        task->clips = clips;
     }
 
     if (transform) {
@@ -471,50 +480,34 @@ void SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, u
 
     tasks.push(task);
     TaskScheduler::request(task);
+
+    return task;
 }
 
 
-void* SwRenderer::prepare(const Picture& pdata, void* data, uint32_t *pixels, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags)
+RenderData SwRenderer::prepare(const Picture& pdata, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
 {
     //prepare task
     auto task = static_cast<SwImageTask*>(data);
     if (!task) {
         task = new SwImageTask;
         if (!task) return nullptr;
+        task->pdata = &pdata;
     }
-
-    if (flags == RenderUpdateFlag::None) return task;
-
-    //Finish previous task if it has duplicated request.
-    task->done();
-
-    task->pdata = &pdata;
-    task->pixels = pixels;
-
-    prepareCommon(task, transform, opacity, compList, flags);
-
-    return task;
+    return prepareCommon(task, transform, opacity, clips, flags);
 }
 
 
-void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags)
+RenderData SwRenderer::prepare(const Shape& sdata, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
 {
     //prepare task
     auto task = static_cast<SwShapeTask*>(data);
     if (!task) {
         task = new SwShapeTask;
         if (!task) return nullptr;
+        task->sdata = &sdata;
     }
-
-    if (flags == RenderUpdateFlag::None) return task;
-
-    //Finish previous task if it has duplicated request.
-    task->done();
-    task->sdata = &sdata;
-
-    prepareCommon(task, transform, opacity, compList, flags);
-
-    return task;
+    return prepareCommon(task, transform, opacity, clips, flags);
 }
 
 
index e3e600d..5c252ee 100644 (file)
@@ -26,8 +26,6 @@
 
 struct SwSurface;
 struct SwTask;
-struct SwShapeTask;
-struct SwImage;
 struct SwComposite;
 
 namespace tvg
@@ -36,17 +34,17 @@ namespace tvg
 class SwRenderer : public RenderMethod
 {
 public:
-    void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) override;
-    void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) override;
-    void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override;
-    bool endComposite(void* ctx, uint32_t opacity) override;
-    bool dispose(void *data) override;
+    RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
+    RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
+    void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) override;
+    bool delCompositor(void* cmp) override;
+    bool dispose(RenderData data) override;
     bool preRender() override;
     bool postRender() override;
-    bool renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
+    bool renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
     bool clear() override;
-    bool render(const Shape& shape, void *data) override;
-    bool render(const Picture& picture, void *data) override;
+    bool renderShape(RenderData data, void* cmp) override;
+    bool renderImage(RenderData data, void* cmp) override;
     bool sync() override;
     bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs);
 
@@ -55,14 +53,16 @@ public:
     static bool term();
 
 private:
-    SwSurface*          surface = nullptr;
-    Array<SwTask*>      tasks;
-    Array<SwComposite*> composites;
+    SwSurface*          surface = nullptr;           //active surface
+    SwComposite*        compositor = nullptr;        //active compositor
+    SwSurface*          mainSurface = nullptr;       //main (default) surface
+    Array<SwTask*>      tasks;                       //async task list
+    Array<SwComposite*> compositors;                 //compositor cache list
 
     SwRenderer(){};
     ~SwRenderer();
 
-    void prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags);
+    RenderData prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags);
 };
 
 }
index 03527c8..ef63238 100644 (file)
@@ -76,15 +76,15 @@ struct Canvas::Impl
     {
         if (!renderer) return Result::InsufficientCondition;
 
-        Array<Composite> compList;
+        Array<RenderData> clips;
 
         //Update single paint node
         if (paint) {
-            paint->pImpl->update(*renderer, nullptr, 255, compList, RenderUpdateFlag::None);
+            paint->pImpl->update(*renderer, nullptr, 255, clips, RenderUpdateFlag::None);
         //Update all retained paint nodes
         } else {
             for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
-                (*paint)->pImpl->update(*renderer, nullptr, 255, compList, RenderUpdateFlag::None);
+                (*paint)->pImpl->update(*renderer, nullptr, 255, clips, RenderUpdateFlag::None);
             }
         }
         return Result::Success;
index 4d2a721..91adb68 100644 (file)
@@ -34,7 +34,7 @@ namespace tvg
         virtual ~StrategyMethod() {}
 
         virtual bool dispose(RenderMethod& renderer) = 0;
-        virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag pFlag) = 0;   //Return engine data if it has.
+        virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag) = 0;   //Return engine data if it has.
         virtual bool render(RenderMethod& renderer) = 0;
         virtual bool bounds(float* x, float* y, float* w, float* h) const = 0;
         virtual bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) const = 0;
@@ -137,7 +137,7 @@ namespace tvg
             return smethod->dispose(renderer);
         }
 
-        void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array<Composite>& compList, uint32_t pFlag)
+        void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array<RenderData>& clips, uint32_t pFlag)
         {
             if (flag & RenderUpdateFlag::Transform) {
                 if (!rTransform) return nullptr;
@@ -149,9 +149,9 @@ namespace tvg
 
             void *compdata = nullptr;
 
-            if (compTarget && (compMethod != CompositeMethod::None)) {
-                compdata = compTarget->pImpl->update(renderer, pTransform, opacity, compList, pFlag);
-                if (compdata) compList.push({compdata, compMethod});
+            if (compTarget) {
+                compdata = compTarget->pImpl->update(renderer, pTransform, opacity, clips, pFlag);
+                if (compMethod == CompositeMethod::ClipPath) clips.push(compdata);
             }
 
             void *edata = nullptr;
@@ -161,20 +161,34 @@ namespace tvg
 
             if (rTransform && pTransform) {
                 RenderTransform outTransform(pTransform, rTransform);
-                edata = smethod->update(renderer, &outTransform, opacity, compList, newFlag);
+                edata = smethod->update(renderer, &outTransform, opacity, clips, newFlag);
             } else {
                 auto outTransform = pTransform ? pTransform : rTransform;
-                edata = smethod->update(renderer, outTransform, opacity, compList, newFlag);
+                edata = smethod->update(renderer, outTransform, opacity, clips, newFlag);
             }
 
-            if (compdata) compList.pop();
+            if (compdata) clips.pop();
 
             return edata;
         }
 
         bool render(RenderMethod& renderer)
         {
-            return smethod->render(renderer);
+            void* cmp = nullptr;
+
+            /* Note: only ClipPath is processed in update() step */
+            if (compTarget && compMethod != CompositeMethod::ClipPath) {
+                uint32_t x, y, w, h;
+                if (!compTarget->pImpl->bounds(renderer, &x, &y, &w, &h)) return false;
+                cmp = renderer.addCompositor(compMethod, x, y, w, h, 255);
+                compTarget->pImpl->render(renderer);
+            }
+
+            auto ret = smethod->render(renderer);
+
+            renderer.delCompositor(cmp);
+
+            return ret;
         }
 
         Paint* duplicate()
@@ -198,6 +212,7 @@ namespace tvg
         bool composite(Paint* target, CompositeMethod method)
         {
             if (!target && method != CompositeMethod::None) return false;
+            if (target && method == CompositeMethod::None) return false;
             compTarget = target;
             compMethod = method;
             return true;
@@ -228,9 +243,9 @@ namespace tvg
             return inst->dispose(renderer);
         }
 
-        void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flag) override
+        void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flag) override
         {
-            return inst->update(renderer, transform, opacity, compList, flag);
+            return inst->update(renderer, transform, opacity, clips, flag);
         }
 
         bool render(RenderMethod& renderer) override
index eed0e0e..f66fb6e 100644 (file)
@@ -89,3 +89,11 @@ Result Picture::size(float* w, float* h) const noexcept
     return Result::Success;
 }
 
+
+const uint32_t* Picture::data() const noexcept
+{
+    //Try it, If not loaded yet.
+    if (pImpl->loader) return pImpl->loader->pixels();
+
+    return pImpl->pixels;
+}
\ No newline at end of file
index c84b04b..a9ff448 100644 (file)
@@ -36,7 +36,7 @@ struct Picture::Impl
     Paint* paint = nullptr;
     uint32_t *pixels = nullptr;
     Picture *picture = nullptr;
-    void *edata = nullptr;              //engine data
+    void *rdata = nullptr;              //engine data
     float w = 0, h = 0;
     bool resizing = false;
 
@@ -53,7 +53,7 @@ struct Picture::Impl
             return true;
         }
         else if (pixels) {
-            return renderer.dispose(edata);
+            return renderer.dispose(rdata);
         }
         return false;
     }
@@ -103,28 +103,28 @@ struct Picture::Impl
                 }
             }
             if (!pixels) {
-                pixels = (uint32_t*)loader->pixels();
+                pixels = const_cast<uint32_t*>(loader->pixels());
                 if (pixels) return RenderUpdateFlag::Image;
             }
         }
         return RenderUpdateFlag::None;
     }
 
-    void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag pFlag)
+    void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag)
     {
-        uint32_t flag = reload();
+        auto flag = reload();
 
-        if (pixels) edata = renderer.prepare(*picture, edata, pixels, transform, opacity, compList, static_cast<RenderUpdateFlag>(pFlag | flag));
+        if (pixels) rdata = renderer.prepare(*picture, rdata, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag));
         else if (paint) {
             if (resizing) resize();
-            edata = paint->pImpl->update(renderer, transform, opacity, compList, static_cast<RenderUpdateFlag>(pFlag | flag));
+            rdata = paint->pImpl->update(renderer, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag));
         }
-        return edata;
+        return rdata;
     }
 
     bool render(RenderMethod &renderer)
     {
-        if (pixels) return renderer.render(*picture, edata);
+        if (pixels) return renderer.renderImage(rdata, nullptr);
         else if (paint) return paint->pImpl->render(renderer);
         return false;
     }
@@ -155,8 +155,8 @@ struct Picture::Impl
 
     bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
     {
-        if (edata) return renderer.renderRegion(edata, x, y, w, h);
-        if (paint) paint->pImpl->bounds(renderer, x, y, w, h);
+        if (rdata) return renderer.renderRegion(rdata, x, y, w, h);
+        if (paint) return paint->pImpl->bounds(renderer, x, y, w, h);
         return false;
     }
 
index 6557ff0..681d450 100644 (file)
@@ -37,10 +37,7 @@ struct Surface
     uint32_t cs;
 };
 
-struct Composite {
-    void* edata;
-    CompositeMethod method;
-};
+using RenderData = void*;
 
 enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, All = 64};
 
@@ -60,21 +57,20 @@ struct RenderTransform
     RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs);
 };
 
-
 class RenderMethod
 {
 public:
     virtual ~RenderMethod() {}
-    virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) = 0;
-    virtual void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) = 0;
-    virtual void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) = 0;
-    virtual bool endComposite(void* ctx, uint32_t opacity) = 0;
-    virtual bool dispose(void *data) = 0;
+    virtual RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) = 0;
+    virtual RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) = 0;
+    virtual void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) = 0;
+    virtual bool delCompositor(void* cmp) = 0;
+    virtual bool dispose(RenderData data) = 0;
     virtual bool preRender() = 0;
-    virtual bool render(const Shape& shape, void *data) = 0;
-    virtual bool render(const Picture& picture, void *data) = 0;
+    virtual bool renderShape(RenderData data, void* cmp) = 0;
+    virtual bool renderImage(RenderData data, void* cmp) = 0;
     virtual bool postRender() = 0;
-    virtual bool renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) = 0;
+    virtual bool renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) = 0;
     virtual bool clear() = 0;
     virtual bool sync() = 0;
 };
index 71b17f2..fc29364 100644 (file)
@@ -44,41 +44,40 @@ struct Scene::Impl
         return true;
     }
 
-    void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flag)
+    void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flag)
     {
         this->opacity = opacity;
 
         /* Overriding opacity value. If this scene is half-translucent,
            It must do intermeidate composition with that opacity value. */
-        if (opacity < 255 && opacity > 0) opacity = 255;
-
-        /* FXIME: it requires to return list of children engine data
-           This is necessary for scene composition */
-        void* edata = nullptr;
+        if (opacity > 0) opacity = 255;
 
         for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
-            edata = (*paint)->pImpl->update(renderer, transform, opacity, compList, static_cast<uint32_t>(flag));
+            (*paint)->pImpl->update(renderer, transform, opacity, clips, static_cast<uint32_t>(flag));
         }
 
-        return edata;
+        /* FXIME: it requires to return list of children engine data
+           This is necessary for scene composition */
+        return nullptr;
     }
 
     bool render(RenderMethod& renderer)
     {
-        void* ctx = nullptr;
+        void* cmp = nullptr;
 
-        //Half translucent. This requires intermediate composition.
-        if (opacity < 255 && opacity > 0) {
+        //Half translucent. This condition requires intermediate composition.
+        if (opacity < 255 && opacity > 0 && (paints.count > 1)) {
             uint32_t x, y, w, h;
             if (!bounds(renderer, &x, &y, &w, &h)) return false;
-            ctx = renderer.beginComposite(x, y, w, h);
+            //CompositeMethod::None is used for a default alpha blending
+            cmp = renderer.addCompositor(CompositeMethod::None, x, y, w, h, opacity);
         }
 
         for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
             if (!(*paint)->pImpl->render(renderer)) return false;
         }
 
-        if (ctx) return renderer.endComposite(ctx, opacity);
+        if (cmp) renderer.delCompositor(cmp);
 
         return true;
     }
index 82b56ed..2e697ca 100644 (file)
@@ -199,7 +199,7 @@ struct Shape::Impl
     ShapeStroke *stroke = nullptr;
     uint8_t color[4] = {0, 0, 0, 0};    //r, g, b, a
     FillRule rule = FillRule::Winding;
-    void *edata = nullptr;              //engine data
+    RenderData rdata = nullptr;         //engine data
     Shape *shape = nullptr;
     uint32_t flag = RenderUpdateFlag::None;
 
@@ -215,24 +215,24 @@ struct Shape::Impl
 
     bool dispose(RenderMethod& renderer)
     {
-        return renderer.dispose(edata);
+        return renderer.dispose(rdata);
     }
 
     bool render(RenderMethod& renderer)
     {
-        return renderer.render(*shape, edata);
+        return renderer.renderShape(rdata, nullptr);
     }
 
-    void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag pFlag)
+    void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag)
     {
-        this->edata = renderer.prepare(*shape, this->edata, transform, opacity, compList, static_cast<RenderUpdateFlag>(pFlag | flag));
+        this->rdata = renderer.prepare(*shape, this->rdata, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag));
         flag = RenderUpdateFlag::None;
-        return this->edata;
+        return this->rdata;
     }
 
     bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
     {
-        return renderer.renderRegion(edata, x, y, w, h);
+        return renderer.renderRegion(rdata, x, y, w, h);
     }
 
     bool bounds(float* x, float* y, float* w, float* h)