Flutter Impeller
path_builder.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "path_builder.h"
6 
7 #include <cmath>
8 
9 namespace impeller {
10 
11 PathBuilder::PathBuilder() = default;
12 
13 PathBuilder::~PathBuilder() = default;
14 
16  auto path = prototype_.Clone();
17  path.SetFillType(fill);
18  return path;
19 }
20 
22  auto path = std::move(prototype_);
23  path.SetFillType(fill);
24  path.SetConvexity(convexity_);
25  if (!did_compute_bounds_) {
26  path.ComputeBounds();
27  }
28  did_compute_bounds_ = false;
29  return path;
30 }
31 
32 void PathBuilder::Reserve(size_t point_size, size_t verb_size) {
33  prototype_.points_.reserve(point_size);
34  prototype_.points_.reserve(verb_size);
35 }
36 
37 PathBuilder& PathBuilder::MoveTo(Point point, bool relative) {
38  current_ = relative ? current_ + point : point;
39  subpath_start_ = current_;
40  prototype_.AddContourComponent(current_);
41  return *this;
42 }
43 
45  LineTo(subpath_start_);
46  prototype_.SetContourClosed(true);
47  prototype_.AddContourComponent(current_);
48  return *this;
49 }
50 
51 PathBuilder& PathBuilder::LineTo(Point point, bool relative) {
52  point = relative ? current_ + point : point;
53  prototype_.AddLinearComponent(current_, point);
54  current_ = point;
55  return *this;
56 }
57 
59  Point endpoint =
60  relative ? Point{current_.x + x, current_.y} : Point{x, current_.y};
61  prototype_.AddLinearComponent(current_, endpoint);
62  current_ = endpoint;
63  return *this;
64 }
65 
67  Point endpoint =
68  relative ? Point{current_.x, current_.y + y} : Point{current_.x, y};
69  prototype_.AddLinearComponent(current_, endpoint);
70  current_ = endpoint;
71  return *this;
72 }
73 
75  Point point,
76  bool relative) {
77  point = relative ? current_ + point : point;
78  controlPoint = relative ? current_ + controlPoint : controlPoint;
79  prototype_.AddQuadraticComponent(current_, controlPoint, point);
80  current_ = point;
81  return *this;
82 }
83 
85  convexity_ = value;
86  return *this;
87 }
88 
90  Point controlPoint2,
91  Point point,
92  bool relative) {
93  controlPoint1 = relative ? current_ + controlPoint1 : controlPoint1;
94  controlPoint2 = relative ? current_ + controlPoint2 : controlPoint2;
95  point = relative ? current_ + point : point;
96  prototype_.AddCubicComponent(current_, controlPoint1, controlPoint2, point);
97  current_ = point;
98  return *this;
99 }
100 
102  MoveTo(p1);
103  prototype_.AddQuadraticComponent(p1, cp, p2);
104  return *this;
105 }
106 
108  Point cp1,
109  Point cp2,
110  Point p2) {
111  MoveTo(p1);
112  prototype_.AddCubicComponent(p1, cp1, cp2, p2);
113  return *this;
114 }
115 
117  auto origin = rect.GetOrigin();
118  auto size = rect.GetSize();
119 
120  auto tl = origin;
121  auto bl = origin + Point{0.0, size.height};
122  auto br = origin + size;
123  auto tr = origin + Point{size.width, 0.0};
124 
125  MoveTo(tl);
126  LineTo(tr);
127  LineTo(br);
128  LineTo(bl);
129  Close();
130 
131  return *this;
132 }
133 
135  return AddOval(Rect::MakeXYWH(c.x - r, c.y - r, 2.0f * r, 2.0f * r));
136 }
137 
139  return radius <= 0.0 ? AddRect(rect)
140  : AddRoundedRect(rect, RoundingRadii(radius));
141 }
142 
144  return radii.width <= 0 || radii.height <= 0
145  ? AddRect(rect)
146  : AddRoundedRect(rect, RoundingRadii(radii));
147 }
148 
150  if (radii.AreAllZero()) {
151  return AddRect(rect);
152  }
153 
154  auto rect_origin = rect.GetOrigin();
155  auto rect_size = rect.GetSize();
156 
157  current_ = rect_origin + Point{radii.top_left.x, 0.0};
158 
159  MoveTo({rect_origin.x + radii.top_left.x, rect_origin.y});
160 
161  //----------------------------------------------------------------------------
162  // Top line.
163  //
164  prototype_.AddLinearComponent(
165  {rect_origin.x + radii.top_left.x, rect_origin.y},
166  {rect_origin.x + rect_size.width - radii.top_right.x, rect_origin.y});
167 
168  //----------------------------------------------------------------------------
169  // Top right arc.
170  //
171  AddRoundedRectTopRight(rect, radii);
172 
173  //----------------------------------------------------------------------------
174  // Right line.
175  //
176  prototype_.AddLinearComponent(
177  {rect_origin.x + rect_size.width, rect_origin.y + radii.top_right.y},
178  {rect_origin.x + rect_size.width,
179  rect_origin.y + rect_size.height - radii.bottom_right.y});
180 
181  //----------------------------------------------------------------------------
182  // Bottom right arc.
183  //
184  AddRoundedRectBottomRight(rect, radii);
185 
186  //----------------------------------------------------------------------------
187  // Bottom line.
188  //
189  prototype_.AddLinearComponent(
190  {rect_origin.x + rect_size.width - radii.bottom_right.x,
191  rect_origin.y + rect_size.height},
192  {rect_origin.x + radii.bottom_left.x, rect_origin.y + rect_size.height});
193 
194  //----------------------------------------------------------------------------
195  // Bottom left arc.
196  //
197  AddRoundedRectBottomLeft(rect, radii);
198 
199  //----------------------------------------------------------------------------
200  // Left line.
201  //
202  prototype_.AddLinearComponent(
203  {rect_origin.x, rect_origin.y + rect_size.height - radii.bottom_left.y},
204  {rect_origin.x, rect_origin.y + radii.top_left.y});
205 
206  //----------------------------------------------------------------------------
207  // Top left arc.
208  //
209  AddRoundedRectTopLeft(rect, radii);
210 
211  Close();
212 
213  return *this;
214 }
215 
216 PathBuilder& PathBuilder::AddRoundedRectTopLeft(Rect rect,
217  RoundingRadii radii) {
218  const auto magic_top_left = radii.top_left * kArcApproximationMagic;
219  const auto corner = rect.GetOrigin();
220  prototype_.AddCubicComponent(
221  {corner.x, corner.y + radii.top_left.y},
222  {corner.x, corner.y + radii.top_left.y - magic_top_left.y},
223  {corner.x + radii.top_left.x - magic_top_left.x, corner.y},
224  {corner.x + radii.top_left.x, corner.y});
225  return *this;
226 }
227 
228 PathBuilder& PathBuilder::AddRoundedRectTopRight(Rect rect,
229  RoundingRadii radii) {
230  const auto magic_top_right = radii.top_right * kArcApproximationMagic;
231  const auto corner = rect.GetOrigin() + Point{rect.GetWidth(), 0};
232  prototype_.AddCubicComponent(
233  {corner.x - radii.top_right.x, corner.y},
234  {corner.x - radii.top_right.x + magic_top_right.x, corner.y},
235  {corner.x, corner.y + radii.top_right.y - magic_top_right.y},
236  {corner.x, corner.y + radii.top_right.y});
237  return *this;
238 }
239 
240 PathBuilder& PathBuilder::AddRoundedRectBottomRight(Rect rect,
241  RoundingRadii radii) {
242  const auto magic_bottom_right = radii.bottom_right * kArcApproximationMagic;
243  const auto corner = rect.GetOrigin() + rect.GetSize();
244  prototype_.AddCubicComponent(
245  {corner.x, corner.y - radii.bottom_right.y},
246  {corner.x, corner.y - radii.bottom_right.y + magic_bottom_right.y},
247  {corner.x - radii.bottom_right.x + magic_bottom_right.x, corner.y},
248  {corner.x - radii.bottom_right.x, corner.y});
249  return *this;
250 }
251 
252 PathBuilder& PathBuilder::AddRoundedRectBottomLeft(Rect rect,
253  RoundingRadii radii) {
254  const auto magic_bottom_left = radii.bottom_left * kArcApproximationMagic;
255  const auto corner = rect.GetOrigin() + Point{0, rect.GetHeight()};
256  prototype_.AddCubicComponent(
257  {corner.x + radii.bottom_left.x, corner.y},
258  {corner.x + radii.bottom_left.x - magic_bottom_left.x, corner.y},
259  {corner.x, corner.y - radii.bottom_left.y + magic_bottom_left.y},
260  {corner.x, corner.y - radii.bottom_left.y});
261  return *this;
262 }
263 
265  Radians start,
266  Radians sweep,
267  bool use_center) {
268  if (sweep.radians < 0) {
269  start.radians += sweep.radians;
270  sweep.radians *= -1;
271  }
272  sweep.radians = std::min(k2Pi, sweep.radians);
273  start.radians = std::fmod(start.radians, k2Pi);
274 
275  const Point center = oval_bounds.GetCenter();
276  const Point radius = center - oval_bounds.GetOrigin();
277 
278  Vector2 p1_unit(std::cos(start.radians), std::sin(start.radians));
279 
280  if (use_center) {
281  MoveTo(center);
282  LineTo(center + p1_unit * radius);
283  } else {
284  MoveTo(center + p1_unit * radius);
285  }
286 
287  while (sweep.radians > 0) {
288  Vector2 p2_unit;
289  Scalar quadrant_angle;
290  if (sweep.radians < kPiOver2) {
291  quadrant_angle = sweep.radians;
292  p2_unit = Vector2(std::cos(start.radians + quadrant_angle),
293  std::sin(start.radians + quadrant_angle));
294  } else {
295  quadrant_angle = kPiOver2;
296  p2_unit = Vector2(-p1_unit.y, p1_unit.x);
297  }
298 
299  Vector2 arc_cp_lengths =
300  (quadrant_angle / kPiOver2) * kArcApproximationMagic * radius;
301 
302  Point p1 = center + p1_unit * radius;
303  Point p2 = center + p2_unit * radius;
304  Point cp1 = p1 + Vector2(-p1_unit.y, p1_unit.x) * arc_cp_lengths;
305  Point cp2 = p2 + Vector2(p2_unit.y, -p2_unit.x) * arc_cp_lengths;
306 
307  prototype_.AddCubicComponent(p1, cp1, cp2, p2);
308  current_ = p2;
309 
310  start.radians += quadrant_angle;
311  sweep.radians -= quadrant_angle;
312  p1_unit = p2_unit;
313  }
314 
315  if (use_center) {
316  Close();
317  }
318 
319  return *this;
320 }
321 
323  const Point c = container.GetCenter();
324  const Point r = c - container.GetOrigin();
325  const Point m = r * kArcApproximationMagic;
326 
327  MoveTo({c.x, c.y - r.y});
328 
329  //----------------------------------------------------------------------------
330  // Top right arc.
331  //
332  prototype_.AddCubicComponent({c.x, c.y - r.y}, // p1
333  {c.x + m.x, c.y - r.y}, // cp1
334  {c.x + r.x, c.y - m.y}, // cp2
335  {c.x + r.x, c.y} // p2
336  );
337 
338  //----------------------------------------------------------------------------
339  // Bottom right arc.
340  //
341  prototype_.AddCubicComponent({c.x + r.x, c.y}, // p1
342  {c.x + r.x, c.y + m.y}, // cp1
343  {c.x + m.x, c.y + r.y}, // cp2
344  {c.x, c.y + r.y} // p2
345  );
346 
347  //----------------------------------------------------------------------------
348  // Bottom left arc.
349  //
350  prototype_.AddCubicComponent({c.x, c.y + r.y}, // p1
351  {c.x - m.x, c.y + r.y}, // cp1
352  {c.x - r.x, c.y + m.y}, // cp2
353  {c.x - r.x, c.y} // p2
354  );
355 
356  //----------------------------------------------------------------------------
357  // Top left arc.
358  //
359  prototype_.AddCubicComponent({c.x - r.x, c.y}, // p1
360  {c.x - r.x, c.y - m.y}, // cp1
361  {c.x - m.x, c.y - r.y}, // cp2
362  {c.x, c.y - r.y} // p2
363  );
364 
365  Close();
366 
367  return *this;
368 }
369 
370 PathBuilder& PathBuilder::AddLine(const Point& p1, const Point& p2) {
371  MoveTo(p1);
372  prototype_.AddLinearComponent(p1, p2);
373  return *this;
374 }
375 
377  return prototype_;
378 }
379 
381  auto linear = [&](size_t index, const LinearPathComponent& l) {
382  prototype_.AddLinearComponent(l.p1, l.p2);
383  };
384  auto quadratic = [&](size_t index, const QuadraticPathComponent& q) {
385  prototype_.AddQuadraticComponent(q.p1, q.cp, q.p2);
386  };
387  auto cubic = [&](size_t index, const CubicPathComponent& c) {
388  prototype_.AddCubicComponent(c.p1, c.cp1, c.cp2, c.p2);
389  };
390  auto move = [&](size_t index, const ContourComponent& m) {
391  prototype_.AddContourComponent(m.destination);
392  };
393  path.EnumerateComponents(linear, quadratic, cubic, move);
394  return *this;
395 }
396 
398  prototype_.Shift(offset);
399  return *this;
400 }
401 
403  prototype_.SetBounds(bounds);
404  did_compute_bounds_ = true;
405  return *this;
406 }
407 
408 } // namespace impeller
impeller::PathBuilder::AddQuadraticCurve
PathBuilder & AddQuadraticCurve(Point p1, Point cp, Point p2)
Move to point p1, then insert a quadradic curve from p1 to p2 with the control point cp.
Definition: path_builder.cc:101
impeller::LinearPathComponent
Definition: path_component.h:28
impeller::TPoint::y
Type y
Definition: point.h:26
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::Path::Clone
Path Clone() const
Deeply clone this path and all data associated with it.
Definition: path.cc:76
impeller::TRect< Scalar >::MakeXYWH
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:34
impeller::PathBuilder::SetBounds
PathBuilder & SetBounds(Rect bounds)
Set the bounding box that will be used by Path.GetBoundingBox in place of performing the computation.
Definition: path_builder.cc:402
impeller::PathBuilder::CubicCurveTo
PathBuilder & CubicCurveTo(Point controlPoint1, Point controlPoint2, Point point, bool relative=false)
Insert a cubic curve from the curren position to point using the control points controlPoint1 and con...
Definition: path_builder.cc:89
impeller::PathBuilder::AddPath
PathBuilder & AddPath(const Path &path)
Definition: path_builder.cc:380
impeller::PathBuilder
Definition: path_builder.h:14
impeller::Vector2
Point Vector2
Definition: point.h:312
impeller::Convexity
Convexity
Definition: path.h:38
impeller::PathBuilder::RoundingRadii::AreAllZero
bool AreAllZero() const
Definition: path_builder.h:142
impeller::PathBuilder::AddRoundedRect
PathBuilder & AddRoundedRect(Rect rect, RoundingRadii radii)
Definition: path_builder.cc:149
impeller::PathBuilder::HorizontalLineTo
PathBuilder & HorizontalLineTo(Scalar x, bool relative=false)
Definition: path_builder.cc:58
impeller::Radians::radians
Scalar radians
Definition: scalar.h:39
impeller::TRect::GetCenter
constexpr Point GetCenter() const
Get the center point as a |Point|.
Definition: rect.h:225
impeller::PathBuilder::~PathBuilder
~PathBuilder()
impeller::PathBuilder::SetConvexity
PathBuilder & SetConvexity(Convexity value)
Definition: path_builder.cc:84
impeller::PathBuilder::kArcApproximationMagic
constexpr static const Scalar kArcApproximationMagic
Definition: path_builder.h:23
impeller::TRect::GetOrigin
constexpr TPoint< Type > GetOrigin() const
Returns the upper left corner of the rectangle as specified when it was constructed.
Definition: rect.h:154
impeller::PathBuilder::AddRect
PathBuilder & AddRect(Rect rect)
Definition: path_builder.cc:116
impeller::PathBuilder::RoundingRadii::bottom_right
Point bottom_right
Definition: path_builder.h:111
impeller::kPiOver2
constexpr float kPiOver2
Definition: constants.h:32
path_builder.h
impeller::PathBuilder::RoundingRadii
Definition: path_builder.h:107
impeller::TSize< Scalar >
impeller::Point
TPoint< Scalar > Point
Definition: point.h:308
impeller::k2Pi
constexpr float k2Pi
Definition: constants.h:29
impeller::PathBuilder::Shift
PathBuilder & Shift(Point offset)
Transform the existing path segments and contours by the given offset.
Definition: path_builder.cc:397
impeller::Path::EnumerateComponents
void EnumerateComponents(const Applier< LinearPathComponent > &linear_applier, const Applier< QuadraticPathComponent > &quad_applier, const Applier< CubicPathComponent > &cubic_applier, const Applier< ContourComponent > &contour_applier) const
Definition: path.cc:129
impeller::PathBuilder::QuadraticCurveTo
PathBuilder & QuadraticCurveTo(Point controlPoint, Point point, bool relative=false)
Insert a quadradic curve from the current position to point using the control point controlPoint.
Definition: path_builder.cc:74
impeller::Path
Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments....
Definition: path.h:55
impeller::PathBuilder::LineTo
PathBuilder & LineTo(Point point, bool relative=false)
Insert a line from the current position to point.
Definition: path_builder.cc:51
impeller::PathBuilder::AddCubicCurve
PathBuilder & AddCubicCurve(Point p1, Point cp1, Point cp2, Point p2)
Move to point p1, then insert a cubic curve from p1 to p2 with control points cp1 and cp2.
Definition: path_builder.cc:107
impeller::PathBuilder::RoundingRadii::top_left
Point top_left
Definition: path_builder.h:108
impeller::Radians
Definition: scalar.h:38
impeller::FillType
FillType
Definition: path.h:30
impeller::PathBuilder::AddLine
PathBuilder & AddLine(const Point &p1, const Point &p2)
Move to point p1, then insert a line from p1 to p2.
Definition: path_builder.cc:370
impeller::PathBuilder::TakePath
Path TakePath(FillType fill=FillType::kNonZero)
Definition: path_builder.cc:21
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:488
impeller::TSize::width
Type width
Definition: size.h:22
impeller::TPoint::x
Type x
Definition: point.h:25
impeller::PathBuilder::PathBuilder
PathBuilder()
impeller::CubicPathComponent
Definition: path_component.h:94
impeller::PathBuilder::Reserve
void Reserve(size_t point_size, size_t verb_size)
Reserve [point_size] points and [verb_size] verbs in the underlying path buffer.
Definition: path_builder.cc:32
impeller::PathBuilder::GetCurrentPath
const Path & GetCurrentPath() const
Definition: path_builder.cc:376
impeller::TRect::GetSize
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle as specified when it was constructed and which may be negative in e...
Definition: rect.h:159
impeller::PathBuilder::Close
PathBuilder & Close()
Definition: path_builder.cc:44
impeller::PathBuilder::CopyPath
Path CopyPath(FillType fill=FillType::kNonZero) const
Definition: path_builder.cc:15
impeller::PathBuilder::RoundingRadii::top_right
Point top_right
Definition: path_builder.h:110
impeller::TPoint< Scalar >
impeller::PathBuilder::MoveTo
PathBuilder & MoveTo(Point point, bool relative=false)
Definition: path_builder.cc:37
impeller::PathBuilder::RoundingRadii::bottom_left
Point bottom_left
Definition: path_builder.h:109
impeller::PathBuilder::VerticalLineTo
PathBuilder & VerticalLineTo(Scalar y, bool relative=false)
Definition: path_builder.cc:66
impeller::PathBuilder::AddCircle
PathBuilder & AddCircle(const Point &center, Scalar radius)
Definition: path_builder.cc:134
impeller::TSize::height
Type height
Definition: size.h:23
impeller::PathBuilder::AddOval
PathBuilder & AddOval(const Rect &rect)
Definition: path_builder.cc:322
impeller::ContourComponent
Definition: path_component.h:146
impeller
Definition: aiks_context.cc:10
impeller::QuadraticPathComponent
Definition: path_component.h:52
impeller::TRect< Scalar >
impeller::PathBuilder::AddArc
PathBuilder & AddArc(const Rect &oval_bounds, Radians start, Radians sweep, bool use_center=false)
Definition: path_builder.cc:264