diff --git a/src/examples/ClipPath.cpp b/src/examples/ClipPath.cpp index a780b386..bfe81ef5 100644 --- a/src/examples/ClipPath.cpp +++ b/src/examples/ClipPath.cpp @@ -111,7 +111,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) star3->translate(400, 0); auto clipRect = tvg::Shape::gen(); - clipRect->appendRect(480, 110, 200, 200, 0, 0); //x, y, w, h, rx, ry + clipRect->appendRect(500, 120, 200, 200, 0, 0); //x, y, w, h, rx, ry clipRect->fill(255, 255, 255, 255); // clip object must have alpha. clipRect->translate(20, 20); diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index cbc13de0..40f67871 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -234,6 +234,19 @@ RenderData GlRenderer::prepare(const Shape& shape, RenderData data, const Render } +RenderRegion GlRenderer::viewport() +{ + return {0, 0, UINT32_MAX, UINT32_MAX}; +} + + +bool GlRenderer::viewport(TVG_UNUSED const RenderRegion& vp) +{ + //TODO: + return true; +} + + int GlRenderer::init(uint32_t threads) { if ((initEngineCnt++) > 0) return true; diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 7e288b74..0c0ecac1 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -38,6 +38,8 @@ public: bool postRender() override; bool dispose(RenderData data) override;; RenderRegion region(RenderData data) override; + RenderRegion viewport() override; + bool viewport(const RenderRegion& vp) override; bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); bool sync() override; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 0b800815..d30bf43c 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -296,16 +296,16 @@ SwFixed mathLength(const SwPoint& pt); bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut); SwFixed mathMean(SwFixed angle1, SwFixed angle2); SwPoint mathTransform(const Point* to, const Matrix* transform); -bool mathUpdateOutlineBBox(const SwOutline* outline, SwBBox& bbox, const SwSize& clip); +bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, SwBBox& renderRegion); void shapeReset(SwShape* shape); bool shapeGenOutline(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform); -bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const SwSize& clip, const Matrix* transform, SwBBox& bbox); +bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion); bool shapePrepared(const SwShape* shape); bool shapeGenRle(SwShape* shape, const Shape* sdata, bool antiAlias, bool hasComposite); void shapeDelOutline(SwShape* shape, uint32_t tid); void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transform); -bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwSize& clip, SwBBox& bbox); +bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion); void shapeFree(SwShape* shape); void shapeDelStroke(SwShape* shape); bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint32_t opacity, bool ctable); @@ -320,9 +320,9 @@ bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline); SwOutline* strokeExportOutline(SwStroke* stroke, unsigned tid); void strokeFree(SwStroke* stroke); -bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const SwSize& clip, const Matrix* transform, SwBBox& bbox); +bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion); bool imagePrepared(const SwImage* image); -bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwBBox& bbox, bool antiAlias, bool hasComposite); +bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwBBox& renderRegion, bool antiAlias); void imageDelOutline(SwImage* image, uint32_t tid); void imageReset(SwImage* image); bool imageGenOutline(SwImage* image, const Picture* pdata, unsigned tid, const Matrix* transform); @@ -334,7 +334,7 @@ void fillFree(SwFill* fill); void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t offset, uint32_t len); void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); -SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& bbox, bool antiAlias); +SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& renderRegion, bool antiAlias); void rleFree(SwRleData* rle); void rleReset(SwRleData* rle); void rleClipPath(SwRleData *rle, const SwRleData *clip); diff --git a/src/lib/sw_engine/tvgSwImage.cpp b/src/lib/sw_engine/tvgSwImage.cpp index 80a139f2..03bf1748 100644 --- a/src/lib/sw_engine/tvgSwImage.cpp +++ b/src/lib/sw_engine/tvgSwImage.cpp @@ -33,16 +33,10 @@ /************************************************************************/ -bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const SwSize& clip, const Matrix* transform, SwBBox& bbox) +bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion) { if (!imageGenOutline(image, pdata, tid, transform)) return false; - if (!mathUpdateOutlineBBox(image->outline, bbox, clip)) return false; - - //Guarantee boundary from mathUpdateOutlineBBox() - bbox.min.x = max(bbox.min.x, TO_SWCOORD(0)); - bbox.min.y = max(bbox.min.y, TO_SWCOORD(0)); - - return true; + return mathUpdateOutlineBBox(image->outline, clipRegion, renderRegion); } @@ -52,9 +46,9 @@ bool imagePrepared(const SwImage* image) } -bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwBBox& bbox, bool antiAlias, TVG_UNUSED bool hasComposite) +bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwBBox& renderRegion, bool antiAlias) { - if ((image->rle = rleRender(image->rle, image->outline, bbox, antiAlias))) return true; + if ((image->rle = rleRender(image->rle, image->outline, renderRegion, antiAlias))) return true; return false; } diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp index 03f9cbf2..77c8b8f1 100644 --- a/src/lib/sw_engine/tvgSwMath.cpp +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -429,14 +429,14 @@ SwPoint mathTransform(const Point* to, const Matrix* transform) } -bool mathUpdateOutlineBBox(const SwOutline* outline, SwBBox& bbox, const SwSize& clip) +bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, SwBBox& renderRegion) { if (!outline) return false; auto pt = outline->pts; if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) { - bbox.reset(); + renderRegion.reset(); return false; } @@ -453,20 +453,22 @@ bool mathUpdateOutlineBBox(const SwOutline* outline, SwBBox& bbox, const SwSize& if (yMin > pt->y) yMin = pt->y; if (yMax < pt->y) yMax = pt->y; } - bbox.min.x = xMin >> 6; - bbox.max.x = (xMax + 63) >> 6; - bbox.min.y = yMin >> 6; - bbox.max.y = (yMax + 63) >> 6; + renderRegion.min.x = xMin >> 6; + renderRegion.max.x = (xMax + 63) >> 6; + renderRegion.min.y = yMin >> 6; + renderRegion.max.y = (yMax + 63) >> 6; - //Guarantee surface boundary - bbox.max.x = min(bbox.max.x, clip.w); - bbox.max.y = min(bbox.max.y, clip.h); + renderRegion.max.x = min(renderRegion.max.x, clipRegion.max.x); + renderRegion.max.y = min(renderRegion.max.y, clipRegion.max.y); + renderRegion.min.x = max(renderRegion.min.x, clipRegion.min.x); + renderRegion.min.y = max(renderRegion.min.y, clipRegion.min.y); //Check valid region - if (bbox.max.x - bbox.min.x < 1 && bbox.max.y - bbox.min.y < 1) return false; + if (renderRegion.max.x - renderRegion.min.x < 1 && renderRegion.max.y - renderRegion.min.y < 1) return false; //Check boundary - if (bbox.min.x >= clip.w || bbox.min.y >= clip.h || bbox.max.x <= 0 || bbox.max.y <= 0) return false; + if (renderRegion.min.x >= clipRegion.max.x || renderRegion.min.y >= clipRegion.max.y || + renderRegion.max.x <= clipRegion.min.x || renderRegion.max.y <= clipRegion.min.y) return false; return true; } \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index f5cfaa9e..1564f5d0 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -86,19 +86,6 @@ static bool _identify(const Matrix* transform) } -static SwBBox _clipRegion(const Surface* surface, const SwBBox& in) -{ - auto bbox = in; - - if (bbox.min.x < 0) bbox.min.x = 0; - if (bbox.min.y < 0) bbox.min.y = 0; - if (bbox.max.x > static_cast(surface->w)) bbox.max.x = surface->w; - if (bbox.max.y > static_cast(surface->h)) bbox.max.y = surface->h; - - return bbox; -} - - static bool _translucent(const SwSurface* surface, uint8_t a) { if (a < 255) return true; @@ -799,9 +786,8 @@ bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id) { //Fast Track if (shape->rect) { - auto region = _clipRegion(surface, shape->bbox); - if (id == FILL_ID_LINEAR) return _rasterLinearGradientRect(surface, region, shape->fill); - return _rasterRadialGradientRect(surface, region, shape->fill); + if (id == FILL_ID_LINEAR) return _rasterLinearGradientRect(surface, shape->bbox, shape->fill); + return _rasterRadialGradientRect(surface, shape->bbox, shape->fill); } else { if (id == FILL_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->rle, shape->fill); return _rasterRadialGradientRle(surface, shape->rle, shape->fill); @@ -821,9 +807,8 @@ bool rasterSolidShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, //Fast Track if (shape->rect) { - auto region = _clipRegion(surface, shape->bbox); - if (translucent) return _rasterTranslucentRect(surface, region, color); - return _rasterSolidRect(surface, region, color); + if (translucent) return _rasterTranslucentRect(surface, shape->bbox, color); + return _rasterSolidRect(surface, shape->bbox, color); } if (translucent) { return _rasterTranslucentRle(surface, shape->rle, color); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 549f6746..de908c32 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -47,7 +47,6 @@ struct SwTask : Task //Range over? region.x = bbox.min.x > 0 ? bbox.min.x : 0; region.y = bbox.min.y > 0 ? bbox.min.y : 0; - region.w = bbox.max.x - region.x; region.h = bbox.max.y - region.y; @@ -79,8 +78,7 @@ struct SwShapeTask : SwTask sdata->strokeColor(nullptr, nullptr, nullptr, &strokeAlpha); } bool validStroke = (strokeAlpha > 0) || sdata->strokeFill(); - - SwSize clip = {static_cast(surface->w), static_cast(surface->h)}; + auto clipRegion = bbox; //invisible shape turned to visible by alpha. auto prepareShape = false; @@ -94,7 +92,7 @@ struct SwShapeTask : SwTask bool renderShape = (alpha > 0 || sdata->fill()); if (renderShape || validStroke) { shapeReset(&shape); - if (!shapePrepare(&shape, sdata, tid, clip, transform, bbox)) goto err; + if (!shapePrepare(&shape, sdata, tid, transform, clipRegion, bbox)) goto err; if (renderShape) { /* We assume that if stroke width is bigger than 2, shape outline below stroke could be full covered by stroke drawing. @@ -123,7 +121,7 @@ struct SwShapeTask : SwTask if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { if (validStroke) { shapeResetStroke(&shape, sdata, transform); - if (!shapeGenStrokeRle(&shape, sdata, tid, transform, clip, bbox)) goto err; + if (!shapeGenStrokeRle(&shape, sdata, tid, transform, clipRegion, bbox)) goto err; ++addStroking; if (auto fill = sdata->strokeFill()) { @@ -177,7 +175,7 @@ struct SwImageTask : SwTask void run(unsigned tid) override { - SwSize clip = {static_cast(surface->w), static_cast(surface->h)}; + auto clipRegion = bbox; //Invisible shape turned to visible by alpha. auto prepareImage = false; @@ -185,11 +183,11 @@ struct SwImageTask : SwTask if (prepareImage) { imageReset(&image); - if (!imagePrepare(&image, pdata, tid, clip, transform, bbox)) goto end; + if (!imagePrepare(&image, pdata, tid, transform, clipRegion, bbox)) goto end; //Clip Path? if (clips.count > 0) { - if (!imageGenRle(&image, pdata, bbox, false, true)) goto end; + if (!imageGenRle(&image, pdata, bbox, false)) goto end; if (image.rle) { for (auto clip = clips.data; clip < (clips.data + clips.count); ++clip) { auto clipper = &static_cast(*clip)->shape; @@ -241,6 +239,12 @@ bool SwRenderer::clear() for (auto task = tasks.data; task < (tasks.data + tasks.count); ++task) (*task)->done(); tasks.clear(); + if (surface) { + vport.x = vport.y = 0; + vport.w = surface->w; + vport.h = surface->h; + } + return true; } @@ -251,6 +255,20 @@ bool SwRenderer::sync() } +RenderRegion SwRenderer::viewport() +{ + return vport; +} + + +bool SwRenderer::viewport(const RenderRegion& vp) +{ + this->vport = vp; + + return true; +} + + bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs) { if (!buffer || stride == 0 || w == 0 || h == 0) return false; @@ -266,6 +284,10 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t surface->h = h; surface->cs = cs; + vport.x = vport.y = 0; + vport.w = surface->w; + vport.h = surface->h; + return rasterCompositor(surface); } @@ -348,6 +370,7 @@ bool SwRenderer::renderShape(RenderData data) return true; } + RenderRegion SwRenderer::region(RenderData data) { return static_cast(data)->bounds(); @@ -514,6 +537,10 @@ void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, task->opacity = opacity; task->surface = surface; task->flags = flags; + task->bbox.min.x = max(static_cast(0), static_cast(vport.x)); + task->bbox.min.y = max(static_cast(0), static_cast(vport.y)); + task->bbox.max.x = min(static_cast(surface->w), static_cast(vport.x + vport.w)); + task->bbox.max.y = min(static_cast(surface->h), static_cast(vport.y + vport.h)); tasks.push(task); TaskScheduler::request(task); diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 999db0d5..ef8b5585 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -42,6 +42,8 @@ public: bool postRender() override; bool dispose(RenderData data) override; RenderRegion region(RenderData data) override; + RenderRegion viewport() override; + bool viewport(const RenderRegion& vp) override; bool clear() override; bool sync() override; @@ -59,6 +61,7 @@ private: SwSurface* surface = nullptr; //active surface Array tasks; //async task list Array compositors; //render targets cache list + RenderRegion vport; //viewport SwRenderer(){}; ~SwRenderer(); diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 5c4719a4..ec8e35e9 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -159,7 +159,7 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor y += rw.cellMin.y; //Clip Y range - if (y < 0 || y >= rw.cellMax.y) return; + if (y < rw.cellMin.y || y >= rw.cellMax.y) return; /* compute the coverage line's coverage, depending on the outline fill rule */ /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */ @@ -198,14 +198,14 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor //Clip x range SwCoord xOver = 0; if (x + acount >= rw.cellMax.x) xOver -= (x + acount - rw.cellMax.x); - if (x < 0) xOver += x; + if (x < rw.cellMin.x) xOver -= (rw.cellMin.x - x); //span->len += (acount + xOver) - 1; span->len += (acount + xOver); return; } - if (count >= MAX_SPANS) { + if (count >= MAX_SPANS) { _genSpan(rw.rle, rw.spans, count); rw.spansCnt = 0; rw.ySpan = 0; @@ -217,9 +217,9 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor //Clip x range SwCoord xOver = 0; if (x + acount >= rw.cellMax.x) xOver -= (x + acount - rw.cellMax.x); - if (x < 0) { - xOver += x; - x = 0; + if (x < rw.cellMin.x) { + xOver -= (rw.cellMin.x - x); + x = rw.cellMin.x; } //Nothing to draw @@ -317,11 +317,10 @@ static void _setCell(RleWorker& rw, SwPoint pos) /* All cells that are on the left of the clipping region go to the min_ex - 1 horizontal position. */ + pos.x -= rw.cellMin.x; pos.y -= rw.cellMin.y; if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x; - pos.x -= rw.cellMin.x; - if (pos.x < 0) pos.x = -1; //Are we moving to a different cell? if (pos != rw.cellPos) { @@ -340,7 +339,6 @@ static void _startCell(RleWorker& rw, SwPoint pos) { if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x; if (pos.x < rw.cellMin.x) pos.x = rw.cellMin.x; - //if (pos.x < rw.cellMin.x) pos.x = (rw.cellMin.x - 1); rw.area = 0; rw.cover = 0; @@ -373,10 +371,9 @@ static void _lineTo(RleWorker& rw, const SwPoint& to) auto e2 = TRUNC(to); //vertical clipping - if ((e1.y >= rw.cellMax.y && e2.y >= rw.cellMax.y) || - (e1.y < rw.cellMin.y && e2.y < rw.cellMin.y)) { - rw.pos = to; - return; + if ((e1.y >= rw.cellMax.y && e2.y >= rw.cellMax.y) || (e1.y < rw.cellMin.y && e2.y < rw.cellMin.y)) { + rw.pos = to; + return; } auto diff = to - rw.pos; @@ -782,7 +779,7 @@ void _replaceClipSpan(SwRleData *rle, SwSpan* clippedSpans, uint32_t size) /* External Class Implementation */ /************************************************************************/ -SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& bbox, bool antiAlias) +SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& renderRegion, bool antiAlias) { constexpr auto RENDER_POOL_SIZE = 16384L; constexpr auto BAND_SIZE = 40; @@ -801,8 +798,8 @@ SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& bbo rw.area = 0; rw.cover = 0; rw.invalid = true; - rw.cellMin = bbox.min; - rw.cellMax = bbox.max; + rw.cellMin = renderRegion.min; + rw.cellMax = renderRegion.max; rw.cellXCnt = rw.cellMax.x - rw.cellMin.x; rw.cellYCnt = rw.cellMax.y - rw.cellMin.y; rw.ySpan = 0; diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index cd951ddd..4dcb91c3 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -367,12 +367,20 @@ bool _fastTrack(const SwOutline* outline) /* External Class Implementation */ /************************************************************************/ -bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const SwSize& clip, const Matrix* transform, SwBBox& bbox) +bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion) { if (!shapeGenOutline(shape, sdata, tid, transform)) return false; - if (!mathUpdateOutlineBBox(shape->outline, shape->bbox, clip)) return false; + if (!mathUpdateOutlineBBox(shape->outline, clipRegion, renderRegion)) return false; - bbox = shape->bbox; + //Keep it for Rasterization Region + shape->bbox = renderRegion; + + //Check valid region + if (renderRegion.max.x - renderRegion.min.x < 1 && renderRegion.max.y - renderRegion.min.y < 1) return false; + + //Check boundary + if (renderRegion.min.x >= clipRegion.max.x || renderRegion.min.y >= clipRegion.max.y || + renderRegion.max.x <= clipRegion.min.x || renderRegion.max.y <= clipRegion.min.y) return false; return true; } @@ -393,7 +401,7 @@ bool shapeGenRle(SwShape* shape, TVG_UNUSED const Shape* sdata, bool antiAlias, //Case A: Fast Track Rectangle Drawing if (!hasComposite && (shape->rect = _fastTrack(shape->outline))) return true; //Case B: Normale Shape RLE Drawing - if ((shape->rle = rleRender(shape->rle, shape->outline, shape->bbox, antiAlias))) return true; + if ((shape->rle = rleRender(shape->rle, shape->outline, shape->bbox,antiAlias))) return true; return false; } @@ -535,7 +543,7 @@ void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transfor } -bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwSize& clip, SwBBox& bbox) +bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion) { SwOutline* shapeOutline = nullptr; SwOutline* strokeOutline = nullptr; @@ -566,12 +574,12 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const M goto fail; } - if (!mathUpdateOutlineBBox(strokeOutline, bbox, clip)) { + if (!mathUpdateOutlineBBox(strokeOutline, clipRegion, renderRegion)) { ret = false; goto fail; } - shape->strokeRle = rleRender(shape->strokeRle, strokeOutline, bbox, true); + shape->strokeRle = rleRender(shape->strokeRle, strokeOutline, renderRegion, true); fail: if (freeOutline) { diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h index 464de437..7ba2d16b 100644 --- a/src/lib/tvgPaint.h +++ b/src/lib/tvgPaint.h @@ -26,6 +26,58 @@ #include #include "tvgRender.h" +static inline bool FLT_SAME(float a, float b) +{ + return (fabsf(a - b) < FLT_EPSILON); +} + +static bool _clipPathFastTrack(Paint* cmpTarget, const RenderTransform* transform, RenderRegion& viewport) +{ + /* Access Shape class by Paint is bad... but it's ok still it's an internal usage. */ + auto shape = static_cast(cmpTarget); + + //Rectangle Candidates? + const Point* pts; + if (shape->pathCoords(&pts) != 4) return false; + + //No Rotation? + if (transform) { + if (transform->m.e12 != 0 || transform->m.e21 != 0 || transform->m.e11 != transform->m.e22) return false; + } + + //Othogonal Rectangle? + auto pt1 = pts + 0; + auto pt2 = pts + 1; + auto pt3 = pts + 2; + auto pt4 = pts + 3; + + if ((FLT_SAME(pt1->x, pt2->x) && FLT_SAME(pt2->y, pt3->y) && FLT_SAME(pt3->x, pt4->x) && FLT_SAME(pt1->y, pt4->y)) || + (FLT_SAME(pt2->x, pt3->x) && FLT_SAME(pt1->y, pt2->y) && FLT_SAME(pt1->x, pt4->x) && FLT_SAME(pt3->y, pt4->y))) { + + auto x1 = pt1->x; + auto y1 = pt1->y; + auto x2 = pt3->x; + auto y2 = pt3->y; + + if (transform) { + x1 = x1 * transform->m.e11 + transform->m.e13; + y1 = y1 * transform->m.e22 + transform->m.e23; + x2 = x2 * transform->m.e11 + transform->m.e13; + y2 = y2 * transform->m.e22 + transform->m.e23; + } + + viewport.x = static_cast(x1); + viewport.y = static_cast(y1); + viewport.w = static_cast(roundf(x2 - x1 + 0.5f)); + viewport.h = static_cast(roundf(y2 - y1 + 0.5f)); + + return true; + } + + return false; +} + + namespace tvg { enum class PaintType { Shape = 0, Scene, Picture }; @@ -150,13 +202,29 @@ namespace tvg } } + /* 1. Composition Pre Processing */ void *cmpData = nullptr; + RenderRegion viewport; + bool cmpFastTrack = false; if (cmpTarget) { - cmpData = cmpTarget->pImpl->update(renderer, pTransform, 255, clips, pFlag); - if (cmpMethod == CompositeMethod::ClipPath) clips.push(cmpData); + /* If transform has no rotation factors && ClipPath is a simple rectangle, + we can avoid regular ClipPath sequence but use viewport for performance */ + if (cmpMethod == CompositeMethod::ClipPath) { + RenderRegion viewport2; + if ((cmpFastTrack = _clipPathFastTrack(cmpTarget, pTransform, viewport2))) { + viewport = renderer.viewport(); + renderer.viewport(viewport2); + } + } + + if (!cmpFastTrack) { + cmpData = cmpTarget->pImpl->update(renderer, pTransform, 255, clips, pFlag); + if (cmpMethod == CompositeMethod::ClipPath) clips.push(cmpData); + } } + /* 2. Main Update */ void *edata = nullptr; auto newFlag = static_cast(pFlag | flag); flag = RenderUpdateFlag::None; @@ -170,7 +238,9 @@ namespace tvg edata = smethod->update(renderer, outTransform, opacity, clips, newFlag); } - if (cmpData && cmpMethod == CompositeMethod::ClipPath) clips.pop(); + /* 3. Composition Post Processing */ + if (cmpFastTrack) renderer.viewport(viewport); + else if (cmpData && cmpMethod == CompositeMethod::ClipPath) clips.pop(); return edata; } diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index d2cb529c..7b06fb7d 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -34,9 +34,9 @@ struct Surface { //TODO: Union for multiple types uint32_t* buffer; - uint32_t stride; - uint32_t w, h; - uint32_t cs; + uint32_t stride; + uint32_t w, h; + uint32_t cs; }; using RenderData = void*; @@ -78,6 +78,8 @@ public: virtual bool postRender() = 0; virtual bool dispose(RenderData data) = 0; virtual RenderRegion region(RenderData data) = 0; + virtual RenderRegion viewport() = 0; + virtual bool viewport(const RenderRegion& vp) = 0; virtual bool clear() = 0; virtual bool sync() = 0;