xref: /aosp_15_r20/external/skia/modules/bentleyottmann/src/Contour.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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