4 #include "v_ft_raster.h"
5 #include "v_ft_stroker.h"
9 #include "vtaskqueue.h"
17 if (mPointSize) delete[] ft.points;
18 if (mTagSize) delete[] ft.tags;
19 if (mSegmentSize) delete[] ft.contours;
23 void convert(const VPath &path);
24 void convert(CapStyle, JoinStyle, float, float);
25 void moveTo(const VPointF &pt);
26 void lineTo(const VPointF &pt);
27 void cubicTo(const VPointF &ctr1, const VPointF &ctr2, const VPointF end);
30 void transform(const VMatrix &m);
36 SW_FT_Stroker_LineCap ftCap;
37 SW_FT_Stroker_LineJoin ftJoin;
39 SW_FT_Fixed ftMeterLimit;
43 void FTOutline::reset()
45 ft.n_points = ft.n_contours = 0;
49 void FTOutline::grow(int points, int segments)
53 int point_size = (points + segments);
54 int segment_size = (sizeof(short) * segments);
55 int tag_size = (sizeof(char) * (points + segments));
57 if (point_size > mPointSize) {
58 if (mPointSize) delete [] ft.points;
59 ft.points = new SW_FT_Vector[point_size];
60 mPointSize = point_size;
63 if (segment_size > mSegmentSize) {
64 if (mSegmentSize) delete [] ft.contours;
65 ft.contours = new short[segment_size];
66 mSegmentSize = segment_size;
69 if (tag_size > mTagSize) {
70 if (mTagSize) delete [] ft.tags;
71 ft.tags = new char[tag_size];
76 void FTOutline::convert(const VPath &path)
78 const std::vector<VPath::Element> &elements = path.elements();
79 const std::vector<VPointF> & points = path.points();
81 grow(points.size(), path.segments());
84 for (auto element : elements) {
86 case VPath::Element::MoveTo:
87 moveTo(points[index]);
90 case VPath::Element::LineTo:
91 lineTo(points[index]);
94 case VPath::Element::CubicTo:
95 cubicTo(points[index], points[index + 1], points[index + 2]);
98 case VPath::Element::Close:
108 void FTOutline::convert(CapStyle cap, JoinStyle join, float width,
111 ftClosed = (SW_FT_Bool)closed;
113 // map strokeWidth to freetype. It uses as the radius of the pen not the
116 // convert to freetype co-ordinate
117 // IMP: stroker takes radius in 26.6 co-ordinate
118 ftWidth = SW_FT_Fixed(width * (1 << 6));
119 // IMP: stroker takes meterlimit in 16.16 co-ordinate
120 ftMeterLimit = SW_FT_Fixed(meterLimit * (1 << 16));
122 // map to freetype capstyle
124 case CapStyle::Square:
125 ftCap = SW_FT_STROKER_LINECAP_SQUARE;
127 case CapStyle::Round:
128 ftCap = SW_FT_STROKER_LINECAP_ROUND;
131 ftCap = SW_FT_STROKER_LINECAP_BUTT;
135 case JoinStyle::Bevel:
136 ftJoin = SW_FT_STROKER_LINEJOIN_BEVEL;
138 case JoinStyle::Round:
139 ftJoin = SW_FT_STROKER_LINEJOIN_ROUND;
142 ftJoin = SW_FT_STROKER_LINEJOIN_MITER;
147 #define TO_FT_COORD(x) ((x)*64) // to freetype 26.6 coordinate.
149 void FTOutline::moveTo(const VPointF &pt)
151 ft.points[ft.n_points].x = TO_FT_COORD(pt.x());
152 ft.points[ft.n_points].y = TO_FT_COORD(pt.y());
153 ft.tags[ft.n_points] = SW_FT_CURVE_TAG_ON;
155 ft.contours[ft.n_contours] = ft.n_points - 1;
162 void FTOutline::lineTo(const VPointF &pt)
164 ft.points[ft.n_points].x = TO_FT_COORD(pt.x());
165 ft.points[ft.n_points].y = TO_FT_COORD(pt.y());
166 ft.tags[ft.n_points] = SW_FT_CURVE_TAG_ON;
171 void FTOutline::cubicTo(const VPointF &cp1, const VPointF &cp2,
174 ft.points[ft.n_points].x = TO_FT_COORD(cp1.x());
175 ft.points[ft.n_points].y = TO_FT_COORD(cp1.y());
176 ft.tags[ft.n_points] = SW_FT_CURVE_TAG_CUBIC;
179 ft.points[ft.n_points].x = TO_FT_COORD(cp2.x());
180 ft.points[ft.n_points].y = TO_FT_COORD(cp2.y());
181 ft.tags[ft.n_points] = SW_FT_CURVE_TAG_CUBIC;
184 ft.points[ft.n_points].x = TO_FT_COORD(ep.x());
185 ft.points[ft.n_points].y = TO_FT_COORD(ep.y());
186 ft.tags[ft.n_points] = SW_FT_CURVE_TAG_ON;
190 void FTOutline::close()
194 index = ft.contours[ft.n_contours - 1] + 1;
199 // make sure atleast 1 point exists in the segment.
200 if (ft.n_points == index) {
205 ft.points[ft.n_points].x = ft.points[index].x;
206 ft.points[ft.n_points].y = ft.points[index].y;
207 ft.tags[ft.n_points] = SW_FT_CURVE_TAG_ON;
212 void FTOutline::end()
215 ft.contours[ft.n_contours] = ft.n_points - 1;
225 static void rleGenerationCb(int count, const SW_FT_Span *spans, void *user)
227 VRle * rle = (VRle *)user;
228 VRle::Span *rleSpan = (VRle::Span *)spans;
229 rle->addSpan(rleSpan, count);
233 RleTask() { receiver = sender.get_future(); }
234 std::promise<VRle> sender;
235 std::future<VRle> receiver;
244 VRle operator()(FTOutline &outRef, SW_FT_Stroker &stroker);
247 VRle RleTask::operator()(FTOutline &outRef, SW_FT_Stroker &stroker)
250 if (stroke) { // Stroke Task
251 outRef.convert(path);
252 outRef.convert(cap, join, width, meterLimit);
254 uint points, contors;
256 SW_FT_Stroker_Set(stroker, outRef.ftWidth, outRef.ftCap, outRef.ftJoin,
257 outRef.ftMeterLimit);
258 SW_FT_Stroker_ParseOutline(stroker, &outRef.ft, !outRef.ftClosed);
259 SW_FT_Stroker_GetCounts(stroker, &points, &contors);
261 outRef.grow(points, contors);
263 SW_FT_Stroker_Export(stroker, &outRef.ft);
265 SW_FT_Raster_Params params;
267 params.flags = SW_FT_RASTER_FLAG_DIRECT | SW_FT_RASTER_FLAG_AA;
268 params.gray_spans = &rleGenerationCb;
270 params.source = &outRef;
272 sw_ft_grays_raster.raster_render(nullptr, ¶ms);
274 } else { // Fill Task
275 outRef.convert(path);
276 int fillRuleFlag = SW_FT_OUTLINE_NONE;
278 case FillRule::EvenOdd:
279 fillRuleFlag = SW_FT_OUTLINE_EVEN_ODD_FILL;
282 fillRuleFlag = SW_FT_OUTLINE_NONE;
285 outRef.ft.flags = fillRuleFlag;
286 SW_FT_Raster_Params params;
288 params.flags = SW_FT_RASTER_FLAG_DIRECT | SW_FT_RASTER_FLAG_AA;
289 params.gray_spans = &rleGenerationCb;
291 params.source = &outRef.ft;
293 sw_ft_grays_raster.raster_render(nullptr, ¶ms);
295 return std::move(rle);
298 class RleTaskScheduler {
299 const unsigned _count{std::thread::hardware_concurrency()};
300 std::vector<std::thread> _threads;
301 std::vector<TaskQueue<RleTask>> _q{_count};
302 std::atomic<unsigned> _index{0};
307 * initalize per thread objects.
309 FTOutline outlineRef;
310 SW_FT_Stroker stroker;
311 SW_FT_Stroker_New(&stroker);
315 RleTask *task = nullptr;
317 for (unsigned n = 0; n != _count * 32; ++n) {
318 if (_q[(i + n) % _count].try_pop(task)) break;
320 if (!task && !_q[i].pop(task)) break;
322 task->sender.set_value((*task)(outlineRef, stroker));
327 SW_FT_Stroker_Done(stroker);
333 for (unsigned n = 0; n != _count; ++n) {
334 _threads.emplace_back([&, n] { run(n); });
340 for (auto &e : _q) e.done();
342 for (auto &e : _threads) e.join();
345 std::future<VRle> async(RleTask *task)
347 auto receiver = std::move(task->receiver);
350 for (unsigned n = 0; n != _count; ++n) {
351 if (_q[(i + n) % _count].try_push(task)) return receiver;
354 _q[i % _count].push(task);
359 std::future<VRle> strokeRle(const VPath &&path, VRle &&rle, CapStyle cap, JoinStyle join,
360 float width, float meterLimit)
362 RleTask *task = new RleTask();
364 task->path = std::move(path);
365 task->rle = std::move(rle);
369 task->meterLimit = meterLimit;
373 std::future<VRle> fillRle(const VPath &&path, VRle &&rle, FillRule fillRule)
375 RleTask *task = new RleTask();
376 task->path = std::move(path);
377 task->rle = std::move(rle);
378 task->fillRule = fillRule;
379 task->stroke = false;
384 static RleTaskScheduler raster_scheduler;
386 VRaster::VRaster() {}
388 VRaster::~VRaster() {}
390 std::future<VRle> VRaster::generateFillInfo(const VPath &&path, VRle &&rle,
393 if (path.isEmpty()) {
394 std::promise<VRle> promise;
395 promise.set_value(VRle());
396 return promise.get_future();
398 return raster_scheduler.fillRle(std::move(path), std::move(rle), fillRule);
401 std::future<VRle> VRaster::generateStrokeInfo(const VPath &&path, VRle &&rle, CapStyle cap,
402 JoinStyle join, float width,
405 if (path.isEmpty()) {
406 std::promise<VRle> promise;
407 promise.set_value(VRle());
408 return promise.get_future();
410 return raster_scheduler.strokeRle(std::move(path), std::move(rle), cap, join, width, meterLimit);