1 // Copyright 2023 Google LLC
2 // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3
4 #include "modules/bentleyottmann/include/Contour.h"
5
6 #include "include/core/SkPath.h"
7 #include "include/core/SkPoint.h"
8 #include "include/core/SkScalar.h"
9 #include "include/private/base/SkTo.h"
10 #include "modules/bentleyottmann/include/Myers.h"
11
12 #include <algorithm>
13 #include <vector>
14
15 namespace contour {
Make(SkPath path)16 Contours Contours::Make(SkPath path) {
17 SkPoint pts[4];
18 SkPath::Iter iter(path, false);
19 SkPath::Verb verb;
20 Contours contours;
21 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
22 switch (verb) {
23 case SkPath::kConic_Verb: {
24 SK_ABORT("Not implemented");
25 break;
26 }
27 case SkPath::kMove_Verb:
28 contours.closeContourIfNeeded();
29 contours.moveToStartOfContour(pts[0]);
30 break;
31 case SkPath::kLine_Verb: {
32 contours.addPointToCurrentContour(pts[1]);
33 break;
34 }
35 case SkPath::kQuad_Verb: {
36 SK_ABORT("Not implemented");
37 break;
38 }
39 case SkPath::kCubic_Verb: {
40 SK_ABORT("Not implemented");
41 break;
42 }
43 case SkPath::kClose_Verb: {
44 contours.closeContourIfNeeded();
45 break;
46 }
47 case SkPath::kDone_Verb:
48 SK_ABORT("The while loop above failed.");
49 }
50 }
51
52 // Close the remaining contour.
53 contours.closeContourIfNeeded();
54
55 return contours;
56 }
57
segments() const58 std::vector<myers::Segment> Contours::segments() const {
59 SK_ABORT("Not implemented");
60 }
61
extend_rect(SkIRect r,Point p)62 static SkIRect extend_rect(SkIRect r, Point p) {
63 int32_t left = std::min(p.x, r.fLeft),
64 top = std::min(p.y, r.fTop),
65 right = std::max(p.x, r.fRight),
66 bottom = std::max(p.y, r.fBottom);
67 return {left, top, right, bottom};
68 }
69
RoundSkPoint(SkPoint p)70 Point Contours::RoundSkPoint(SkPoint p) {
71 return {SkScalarRoundToInt(p.x() * kScaleFactor), SkScalarRoundToInt(p.y() * kScaleFactor)};
72 }
73
currentContourIsEmpty() const74 bool Contours::currentContourIsEmpty() const {
75 int32_t lastEnd = fContours.empty() ? 0 : fContours.back().end;
76 return lastEnd == SkToS32(fPoints.size());
77 }
78
addPointToCurrentContour(SkPoint p)79 void Contours::addPointToCurrentContour(SkPoint p) {
80 if (this->currentContourIsEmpty()) {
81 fPoints.push_back(fContourStart);
82 fContourBounds = extend_rect(fContourBounds, fContourStart);
83 }
84 Point point = RoundSkPoint(p);
85 fPoints.push_back(point);
86 fContourBounds = extend_rect(fContourBounds, point);
87 }
88
moveToStartOfContour(SkPoint p)89 void Contours::moveToStartOfContour(SkPoint p) {
90 fContourStart = RoundSkPoint(p);
91 }
92
closeContourIfNeeded()93 void Contours::closeContourIfNeeded() {
94 if (this->currentContourIsEmpty()) {
95 // The current contour is empty. Don't record it.
96 return;
97 }
98 fContours.push_back({fContourBounds, SkToS32(fPoints.size())});
99 fContourBounds = kEmptyRect;
100 }
101 } // namespace contour
102