#include "tvgCommon.h"
using namespace tvg;
+using SwPoint = Point;
+constexpr auto SW_CURVE_TAG_CONIC = 0;
constexpr auto SW_CURVE_TAG_ON = 1;
constexpr auto SW_CURVE_TAG_CUBIC = 2;
struct SwOutline
{
- size_t* cntrs; //the contour end points
- size_t cntrsCnt; //number of contours in glyph
- size_t reservedCntrsCnt;
- Point* pts; //the outline's points
- size_t ptsCnt; //number of points in the glyph
- size_t reservedPtsCnt;
- char* tags; //the points flags
- size_t flags; //outline masks
+ size_t* cntrs; //the contour end points
+ size_t cntrsCnt; //number of contours in glyph
+ size_t reservedCntrsCnt;
+ SwPoint* pts; //the outline's points
+ size_t ptsCnt; //number of points in the glyph
+ size_t reservedPtsCnt;
+ char* tags; //the points flags
+ size_t flags; //outline masks
+};
+
+struct SwSpan
+{
+ size_t x;
+ size_t y;
+ size_t len;
+ uint8_t coverage;
+};
+
+struct SwRleData
+{
+ size_t alloc;
+ size_t size;
+ SwSpan *spans;
+};
+
+struct SwBBox
+{
+ size_t xMin, yMin;
+ size_t xMax, yMax;
};
struct SwShape
{
-// SwRleRaster raster;
SwOutline* outline;
+ SwRleData rle;
+ SwBBox bbox;
};
bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata);
void shapeDelOutline(const ShapeNode& shape, SwShape& sdata);
bool shapeGenRle(const ShapeNode& shape, SwShape& sdata);
-bool shapeUpdateBBox(const ShapeNode& shape, SwShape& sdata);
+void shapeDelRle(const ShapeNode& shape, SwShape& sdata);
+bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata);
+
+bool rleRender(SwShape& sdata);
#endif /* _TVG_SW_COMMON_H_ */
static SwRaster* pInst = nullptr;
+
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
-void* SwRaster::prepare(const ShapeNode& shape, void* data)
+void* SwRaster::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
{
//prepare shape data
SwShape* sdata = static_cast<SwShape*>(data);
assert(sdata);
}
+ if (flags == UpdateFlag::None) return nullptr;
+
//invisible?
size_t alpha;
shape.fill(nullptr, nullptr, nullptr, &alpha);
if (alpha == 0) return sdata;
- if (!shapeGenOutline(shape, *sdata)) return sdata;
-
- //TODO: From below sequence starts threading?
- if (!shapeGenRle(shape, *sdata)) return sdata;
- if (!shapeUpdateBBox(shape, *sdata)) return sdata;
-
- shapeDelOutline(shape, *sdata);
+ if (flags & UpdateFlag::Path) {
+ if (!shapeGenOutline(shape, *sdata)) return sdata;
+ //TODO: From below sequence starts threading?
+ if (!shapeTransformOutline(shape, *sdata)) return sdata;
+ if (!shapeGenRle(shape, *sdata)) return sdata;
+ shapeDelOutline(shape, *sdata);
+ }
return sdata;
}
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef _TVG_SW_RLE_H_
+#define _TVG_SW_RLE_H_
+
+#include <setjmp.h>
+#include "tvgSwCommon.h"
+
+/************************************************************************/
+/* Internal Class Implementation */
+/************************************************************************/
+constexpr auto MAX_SPANS = 256;
+
+using SwPtrDist = ptrdiff_t;
+using TPos = long;
+using TCoord = long;
+using TArea = int;
+
+struct TBand
+{
+ TPos min, max;
+};
+
+struct TCell
+{
+ TPos x;
+ TCoord cover;
+ TArea area;
+ TCell *next;
+};
+
+struct RleWorker
+{
+ TCoord ex, ey;
+ TPos exMin, exMax;
+ TPos eyMin, eyMax;
+ TPos exCnt, eyCnt;
+
+ TArea area;
+ TCoord cover;
+
+ TCell* cells;
+ SwPtrDist maxCells;
+ SwPtrDist numCells;
+
+ TPos x, y;
+
+ Point bezStack[32 * 3 + 1];
+ int levStack[32];
+
+ SwOutline* outline;
+ //SwBBox clipBox;
+
+ SwSpan spans[MAX_SPANS];
+ int spansCnt;
+
+ //render_span
+ //render_span_data;
+ int ySpan;
+
+ int bandSize;
+ int bandShoot;
+
+ jmp_buf jmpBuf;
+
+ void* buffer;
+ long bufferSize;
+
+ TCell** yCells;
+ TPos yCnt;
+
+ bool invalid;
+};
+
+static bool rleSweep(RleWorker& rw)
+{
+ //TODO:
+ return true;
+}
+
+static bool moveTo(SwPoint& pt)
+{
+ printf("moveTo = %f %f\n", pt.x, pt.y);
+ return true;
+}
+
+
+static bool lineTo(SwPoint& pt)
+{
+ printf("lineTo = %f %f\n", pt.x, pt.y);
+ return true;
+}
+
+
+static bool cubicTo(SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& pt)
+{
+ printf("cubicTo = ctrl1(%f %f) ctrl2(%f %f) pt(%f %f)\n", ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, pt.x, pt.y);
+ return true;
+}
+
+
+static bool decomposeOutline(RleWorker& rw)
+{
+ printf("decomposOutline\n");
+ auto outline = rw.outline;
+ assert(outline);
+
+ auto first = 0; //index of first point in contour
+
+ for (size_t n = 0; n < outline->cntrsCnt; ++n) {
+ auto last = outline->cntrs[n];
+ if (last < 0) goto invalid_outline;
+
+ auto limit = outline->pts + last;
+ assert(limit);
+
+ auto pt = outline->pts + first;
+ auto tags = outline->tags + first;
+
+ /* A contour cannot start with a cubic control point! */
+ if (tags[0] == SW_CURVE_TAG_CUBIC) goto invalid_outline;
+
+ if (!moveTo(outline->pts[first])) return false;
+
+ while (pt < limit) {
+ assert(++pt);
+ assert(++tags);
+
+ //emit a single line_to
+ if (tags[0] == SW_CURVE_TAG_ON) {
+ if (!lineTo(*pt)) return false;
+ continue;
+ //tag cubic
+ } else {
+ if (pt + 1 > limit || tags[1] != SW_CURVE_TAG_CUBIC)
+ goto invalid_outline;
+
+ pt += 2;
+ tags += 2;
+
+ if (pt <= limit) {
+ if (!cubicTo(pt[-2], pt[-1], pt[0])) return false;
+ continue;
+ }
+ if (!cubicTo(pt[-2], pt[-1], outline->pts[first])) return false;
+ goto close;
+ }
+ }
+
+ //Close the contour with a line segment?
+ //if (!lineTo(outline->pts[first]));
+ close:
+ first = last + 1;
+ }
+
+ return true;
+
+invalid_outline:
+ cout << "Invalid Outline!" << endl;
+ return false;
+}
+
+
+static TCell* findCell(RleWorker& rw)
+{
+ //TODO:
+ return nullptr;
+}
+
+
+static void recordCell(RleWorker& rw)
+{
+ if (rw.area | rw.cover) {
+ TCell* cell = findCell(rw);
+ assert(cell);
+ cell->area += rw.area;
+ cell->cover += rw.cover;
+ }
+}
+
+
+static bool genRle(RleWorker& rw)
+{
+ bool ret = false;
+
+ if (setjmp(rw.jmpBuf) == 0) {
+ ret = decomposeOutline(rw);
+ if (!rw.invalid) recordCell(rw);
+ } else {
+ cout << "Memory Overflow" << endl;
+ }
+ return ret;
+}
+
+
+/************************************************************************/
+/* External Class Implementation */
+/************************************************************************/
+
+bool rleRender(SwShape& sdata)
+{
+ constexpr auto RENDER_POOL_SIZE = 16384L;
+ constexpr auto BAND_SIZE = 40;
+
+ auto outline = sdata.outline;
+ assert(outline);
+
+ if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return false;
+
+ assert(outline->cntrs && outline->pts);
+ assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1);
+
+ //TODO: We can preserve several static workers in advance
+ RleWorker rw;
+ TCell buffer[RENDER_POOL_SIZE / sizeof(TCell)];
+
+ //Init Cells
+ rw.buffer = buffer;
+ rw.bufferSize = sizeof(buffer);
+ rw.yCells = reinterpret_cast<TCell**>(buffer);
+ rw.cells = nullptr;
+ rw.maxCells = 0;
+ rw.numCells = 0;
+ rw.area = 0;
+ rw.cover = 0;
+ rw.invalid = true;
+ rw.exMin = sdata.bbox.xMin;
+ rw.exMax = sdata.bbox.xMax;
+ rw.eyMin = sdata.bbox.yMin;
+ rw.eyMax = sdata.bbox.yMax;
+ rw.exCnt = rw.exMax - rw.exMin;
+ rw.eyCnt = rw.eyMax - rw.eyMin;
+ rw.outline = outline;
+ rw.bandSize = rw.bufferSize / (sizeof(TCell) * 8); //bandSize: 64
+ rw.bandShoot = 0;
+ //printf("bufferSize = %d, bbox(%d %d %d %d), exCnt(%d), eyCnt(%d), bandSize(%d)\n", rw.bufferSize, rw.exMin, rw.eyMin, rw.exMax, rw.eyMax, rw.exCnt, rw.eyCnt, rw.bandSize);
+
+ //Generate RLE
+ TBand bands[BAND_SIZE];
+ TBand* band;
+
+ /* set up vertical bands */
+ auto bandCnt = (rw.eyMax - rw.eyMin) / rw.bandSize;
+ if (bandCnt == 0) bandCnt = 1;
+ else if (bandCnt >= BAND_SIZE) bandCnt = BAND_SIZE - 1;
+
+ auto min = rw.eyMin;
+ auto yMax = rw.eyMax;
+ TPos max;
+//printf("bandCnt(%d)\n", bandCnt);
+
+ for (int n = 0; n < bandCnt; ++n, min = max) {
+ max = min + rw.bandSize;
+ if (n == bandCnt -1 || max > yMax) max = yMax;
+
+ bands[0].min = min;
+ bands[0].max = max;
+ band = bands;
+
+ while (band >= bands) {
+ rw.yCells = static_cast<TCell**>(rw.buffer);
+ rw.yCnt = band->max - band->min;
+
+ auto cellStart = sizeof(TCell*) * rw.yCnt;
+ auto cellMod = cellStart % sizeof(TCell);
+
+ if (cellMod > 0) cellStart += sizeof(TCell) - cellMod;
+
+ auto cellEnd = rw.bufferSize;
+ cellEnd -= cellEnd % sizeof(TCell);
+//printf("n:%d, cellStart(%d), cellEnd(%d) cellMod(%d)\n", n, cellStart, cellEnd, cellMod);
+
+ auto cellsMax = reinterpret_cast<TCell*>((char*)rw.buffer + cellEnd);
+ rw.cells = reinterpret_cast<TCell*>((char*)rw.buffer + cellStart);
+
+ if (rw.cells >= cellsMax) goto reduce_bands;
+
+ rw.maxCells = cellsMax - rw.cells;
+ if (rw.maxCells < 2) goto reduce_bands;
+
+ for (auto y = 0; y < rw.yCnt; ++y)
+ rw.yCells[y] = nullptr;
+
+ rw.numCells = 0;
+ rw.invalid = true;
+ rw.eyMin = band->min;
+ rw.eyMax = band->max;
+ rw.eyCnt = band->max - band->min;
+
+ if (!genRle(rw)) return -1;
+
+ rleSweep(rw);
+ --band;
+ continue;
+
+ reduce_bands:
+ /* render pool overflow: we will reduce the render band by half */
+ auto bottom = band->min;
+ auto top = band->max;
+ auto middle = bottom + ((top - bottom) >> 1);
+
+ /* This is too complex for a single scanline; there must
+ be some problems */
+ if (middle == bottom) return -1;
+
+ if (bottom - top >= rw.bandSize) ++rw.bandShoot;
+
+ band[1].min = bottom;
+ band[1].max = middle;
+ band[0].min = middle;
+ band[0].max = top;
+ ++band;
+ }
+ }
+
+ if (rw.bandShoot > 8 && rw.bandSize > 16)
+ rw.bandSize = rw.bandSize / 2;
+
+ return true;
+}
+
+#endif /* _TVG_SW_RLE_H_ */
growOutlineContour(outline, 1);
if (outline.ptsCnt > 0) {
outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
- ++outline.cntrs;
+ ++outline.cntrsCnt;
}
}
}
-/************************************************************************/
-/* External Class Implementation */
-/************************************************************************/
+static void initBBox(SwShape& sdata)
+{
+ sdata.bbox.xMin = sdata.bbox.yMin = 0;
+ sdata.bbox.xMax = sdata.bbox.yMax = 0;
+}
-bool shapeGenRle(const ShapeNode& shape, SwShape& sdata)
+
+static bool updateBBox(SwShape& sdata)
{
- //TODO: rle
+ auto outline = sdata.outline;
+ assert(outline);
+
+ auto pt = outline->pts;
+ assert(pt);
+
+ if (outline->ptsCnt <= 0) {
+ initBBox(sdata);
+ return false;
+ }
+
+ auto xMin = pt->x;
+ auto xMax = pt->y;
+ auto yMin = pt->y;
+ auto yMax = pt->y;
+
+ ++pt;
+
+ for(size_t i = 1; i < outline->ptsCnt; ++i, ++pt) {
+ assert(pt);
+ if (xMin > pt->x) xMin = pt->x;
+ if (xMax < pt->y) xMax = pt->x;
+ if (yMin > pt->y) yMin = pt->y;
+ if (yMax < pt->y) yMax = pt->y;
+ }
+ sdata.bbox.xMin = round(xMin - 0.49);
+ sdata.bbox.xMax = round(xMax + 0.49);
+ sdata.bbox.yMin = round(yMin - 0.49);
+ sdata.bbox.yMax = round(yMax + 0.49);
+
+ if (xMax - xMin < 1 || yMax - yMin < 1) return false;
return true;
}
-bool shapeUpdateBBox(const ShapeNode& shape, SwShape& sdata)
+/************************************************************************/
+/* External Class Implementation */
+/************************************************************************/
+
+bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata)
{
//TODO:
return true;
}
+void shapeDelRle(const ShapeNode& shape, SwShape& sdata)
+{
+ if (sdata.rle.spans) free(sdata.rle.spans);
+ sdata.rle.spans = nullptr;
+}
+
+
+bool shapeGenRle(const ShapeNode& shape, SwShape& sdata)
+{
+ shapeDelRle(shape, sdata);
+ if (!updateBBox(sdata)) return false;
+ return rleRender(sdata);
+}
+
+
void shapeDelOutline(const ShapeNode& shape, SwShape& sdata)
{
if (!sdata.outline) return;
bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
{
+ initBBox(sdata);
+
const PathCommand* cmds = nullptr;
auto cmdCnt = shape.pathCommands(&cmds);
cout << "Outline was already allocated? How?" << endl;
}
+ //TODO: Probabry we can copy pts from shape directly.
growOutlinePoint(*outline, outlinePtsCnt);
growOutlineContour(*outline, outlineCntrsCnt);
outlineEnd(*outline);
+ //FIXME:
+ //outline->flags = SwOutline::FillRule::Winding;
+
sdata.outline = outline;
return true;