2 * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #ifndef _TVG_SW_SHAPE_H_
18 #define _TVG_SW_SHAPE_H_
20 #include "tvgSwCommon.h"
22 /************************************************************************/
23 /* Internal Class Implementation */
24 /************************************************************************/
26 static void _growOutlineContour(SwOutline& outline, uint32_t n)
30 outline.cntrs = nullptr;
32 outline.reservedCntrsCnt = 0;
35 if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return;
37 //cout << "Grow Cntrs: " << outline.reservedCntrsCnt << " -> " << outline.cntrsCnt + n << endl;;
38 outline.reservedCntrsCnt = n;
39 outline.cntrs = static_cast<uint32_t*>(realloc(outline.cntrs, n * sizeof(uint32_t)));
40 assert(outline.cntrs);
44 static void _growOutlinePoint(SwOutline& outline, uint32_t n)
48 outline.pts = nullptr;
50 outline.types = nullptr;
51 outline.reservedPtsCnt = 0;
56 if (outline.reservedPtsCnt >= outline.ptsCnt + n) return;
58 //cout << "Grow Pts: " << outline.reservedPtsCnt << " -> " << outline.ptsCnt + n << endl;
59 outline.reservedPtsCnt = n;
60 outline.pts = static_cast<SwPoint*>(realloc(outline.pts, n * sizeof(SwPoint)));
62 outline.types = static_cast<uint8_t*>(realloc(outline.types, n * sizeof(uint8_t)));
63 assert(outline.types);
67 static void _freeOutline(SwOutline* outline)
71 if (outline->cntrs) free(outline->cntrs);
72 if (outline->pts) free(outline->pts);
73 if (outline->types) free(outline->types);
78 static void _outlineEnd(SwOutline& outline)
80 _growOutlineContour(outline, 1);
81 if (outline.ptsCnt > 0) {
82 outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
88 static void _outlineMoveTo(SwOutline& outline, const Point* to)
92 _growOutlinePoint(outline, 1);
94 outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
95 outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT;
97 if (outline.ptsCnt > 0) {
98 _growOutlineContour(outline, 1);
99 outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
107 static void _outlineLineTo(SwOutline& outline, const Point* to)
111 _growOutlinePoint(outline, 1);
113 outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
114 outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT;
120 static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to)
122 assert(ctrl1 && ctrl2 && to);
124 _growOutlinePoint(outline, 3);
126 outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl1);
127 outline.types[outline.ptsCnt] = SW_CURVE_TYPE_CUBIC;
130 outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl2);
131 outline.types[outline.ptsCnt] = SW_CURVE_TYPE_CUBIC;
134 outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
135 outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT;
140 static void _outlineClose(SwOutline& outline)
144 if (outline.cntrsCnt > 0) {
145 i = outline.cntrs[outline.cntrsCnt - 1] + 1;
150 //Make sure there is at least one point in the current path
151 if (outline.ptsCnt == i) {
152 outline.opened = true;
157 _growOutlinePoint(outline, 1);
159 outline.pts[outline.ptsCnt] = outline.pts[i];
160 outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT;
163 outline.opened = false;
167 static void _initBBox(SwBBox& bbox)
169 bbox.min.x = bbox.min.y = 0;
170 bbox.max.x = bbox.max.y = 0;
174 static bool _updateBBox(SwOutline* outline, SwBBox& bbox)
176 if (!outline) return false;
178 auto pt = outline->pts;
181 if (outline->ptsCnt <= 0) {
193 for(uint32_t i = 1; i < outline->ptsCnt; ++i, ++pt) {
195 if (xMin > pt->x) xMin = pt->x;
196 if (xMax < pt->x) xMax = pt->x;
197 if (yMin > pt->y) yMin = pt->y;
198 if (yMax < pt->y) yMax = pt->y;
200 bbox.min.x = xMin >> 6;
201 bbox.max.x = (xMax + 63) >> 6;
202 bbox.min.y = yMin >> 6;
203 bbox.max.y = (yMax + 63) >> 6;
205 if (xMax - xMin < 1 || yMax - yMin < 1) return false;
211 static bool _checkValid(SwShape& sdata, const SwSize& clip)
213 assert(sdata.outline);
215 if (sdata.outline->ptsCnt == 0 || sdata.outline->cntrsCnt <= 0) return false;
218 if ((sdata.bbox.min.x > clip.w || sdata.bbox.min.y > clip.h) ||
219 (sdata.bbox.min.x + sdata.bbox.max.x < 0) ||
220 (sdata.bbox.min.y + sdata.bbox.max.y < 0)) return false;
226 /************************************************************************/
227 /* External Class Implementation */
228 /************************************************************************/
230 void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform)
232 auto outline = sdata.outline;
235 for(uint32_t i = 0; i < outline->ptsCnt; ++i) {
236 auto dx = static_cast<float>(outline->pts[i].x >> 6);
237 auto dy = static_cast<float>(outline->pts[i].y >> 6);
238 auto tx = dx * transform.e11 + dy * transform.e12 + transform.e13;
239 auto ty = dx * transform.e21 + dy * transform.e22 + transform.e23;
240 auto pt = Point{tx + transform.e31, ty + transform.e32};
241 outline->pts[i] = TO_SWPOINT(&pt);
246 bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip)
248 if (!_updateBBox(sdata.outline, sdata.bbox)) goto end;
249 if (!_checkValid(sdata, clip)) goto end;
251 sdata.rle = rleRender(sdata.outline, sdata.bbox, clip);
254 if (sdata.rle) return true;
259 void shapeDelOutline(SwShape& sdata)
261 auto outline = sdata.outline;
262 _freeOutline(outline);
263 sdata.outline = nullptr;
267 void shapeReset(SwShape& sdata)
269 shapeDelOutline(sdata);
272 _initBBox(sdata.bbox);
276 bool shapeGenOutline(const Shape& shape, SwShape& sdata)
278 const PathCommand* cmds = nullptr;
279 auto cmdCnt = shape.pathCommands(&cmds);
281 const Point* pts = nullptr;
282 auto ptsCnt = shape.pathCoords(&pts);
284 //No actual shape data
285 if (cmdCnt == 0 || ptsCnt == 0) return false;
288 auto outlinePtsCnt = 0;
289 auto outlineCntrsCnt = 0;
291 for (uint32_t i = 0; i < cmdCnt; ++i) {
292 switch(*(cmds + i)) {
293 case PathCommand::Close: {
297 case PathCommand::MoveTo: {
302 case PathCommand::LineTo: {
306 case PathCommand::CubicTo: {
313 ++outlinePtsCnt; //for close
314 ++outlineCntrsCnt; //for end
316 auto outline = sdata.outline;
317 if (!outline) outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline)));
319 outline->opened = true;
321 _growOutlinePoint(*outline, outlinePtsCnt);
322 _growOutlineContour(*outline, outlineCntrsCnt);
325 while (cmdCnt-- > 0) {
327 case PathCommand::Close: {
328 _outlineClose(*outline);
331 case PathCommand::MoveTo: {
332 _outlineMoveTo(*outline, pts);
336 case PathCommand::LineTo: {
337 _outlineLineTo(*outline, pts);
341 case PathCommand::CubicTo: {
342 _outlineCubicTo(*outline, pts, pts + 1, pts + 2);
350 _outlineEnd(*outline);
353 //outline->flags = SwOutline::FillRule::Winding;
355 sdata.outline = outline;
361 void shapeFree(SwShape* sdata)
365 shapeDelOutline(*sdata);
369 rleFree(sdata->strokeRle);
370 strokeFree(sdata->stroke);
377 void shapeResetStroke(const Shape& shape, SwShape& sdata)
379 if (!sdata.stroke) sdata.stroke = static_cast<SwStroke*>(calloc(1, sizeof(SwStroke)));
380 auto stroke = sdata.stroke;
382 strokeReset(*stroke, shape.strokeWidth(), shape.strokeCap(), shape.strokeJoin());
383 rleFree(sdata.strokeRle);
384 sdata.strokeRle = nullptr;
388 bool shapeGenStrokeRle(const Shape& shape, SwShape& sdata, const SwSize& clip)
390 if (!sdata.outline) {
391 if (!shapeGenOutline(shape, sdata)) return false;
394 if (!_checkValid(sdata, clip)) return false;
396 if (!strokeParseOutline(*sdata.stroke, *sdata.outline)) return false;
398 auto outline = strokeExportOutline(*sdata.stroke);
399 if (!outline) return false;
402 _updateBBox(outline, bbox);
404 sdata.strokeRle = rleRender(outline, bbox, clip);
406 _freeOutline(outline);
411 #endif /* _TVG_SW_SHAPE_H_ */