Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 6c74888

Browse files
committed
[Impeller] Curve components in stroke path use start directions as their initial offsets
1 parent d468d00 commit 6c74888

File tree

4 files changed

+126
-59
lines changed

4 files changed

+126
-59
lines changed

impeller/aiks/aiks_unittests.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,16 @@ TEST_P(AiksTest, CanRenderCurvedStrokes) {
246246
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
247247
}
248248

249+
TEST_P(AiksTest, CanRenderThickCurvedStrokes) {
250+
Canvas canvas;
251+
Paint paint;
252+
paint.color = Color::Red();
253+
paint.stroke_width = 250.0;
254+
paint.style = Paint::Style::kStroke;
255+
canvas.DrawPath(PathBuilder{}.AddCircle({500, 500}, 250).TakePath(), paint);
256+
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
257+
}
258+
249259
TEST_P(AiksTest, CanRenderClips) {
250260
Canvas canvas;
251261
Paint paint;

impeller/entity/geometry/stroke_path_geometry.cc

Lines changed: 110 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -242,18 +242,102 @@ StrokePathGeometry::CreateSolidStrokeVertices(
242242
Point offset;
243243
Point previous_offset; // Used for computing joins.
244244

245-
auto compute_offset = [&polyline, &offset, &previous_offset,
246-
&stroke_width](size_t point_i) {
245+
// Computes offset by calculating the direction from point_i - 1 to point_i if
246+
// point_i is within `contour_start_point_i` and `contour_end_point_i`;
247+
// Otherwise, it uses direction from contour.
248+
auto compute_offset = [&polyline, &offset, &previous_offset, &stroke_width](
249+
const size_t point_i,
250+
const size_t contour_start_point_i,
251+
const size_t contour_end_point_i,
252+
const Path::PolylineContour& contour) {
253+
Point direction;
254+
if (point_i >= contour_end_point_i) {
255+
direction = contour.end_direction;
256+
} else if (point_i <= contour_start_point_i) {
257+
direction = -contour.start_direction;
258+
} else {
259+
direction =
260+
(polyline.points[point_i] - polyline.points[point_i - 1]).Normalize();
261+
}
247262
previous_offset = offset;
248-
Point direction =
249-
(polyline.points[point_i] - polyline.points[point_i - 1]).Normalize();
250263
offset = Vector2{-direction.y, direction.x} * stroke_width * 0.5;
251264
};
252265

266+
auto add_vertices_for_linear_compoent =
267+
[&vtx_builder, &offset, &previous_offset, &vtx, &polyline,
268+
&compute_offset, scaled_miter_limit, scale, &join_proc](
269+
const size_t component_start_index, const size_t component_end_index,
270+
const size_t contour_start_point_i, const size_t contour_end_point_i,
271+
const Path::PolylineContour& contour) {
272+
auto is_last_component =
273+
component_start_index ==
274+
contour.components.back().component_start_index;
275+
276+
for (size_t point_i = component_start_index;
277+
point_i < component_end_index; point_i++) {
278+
auto is_end_of_component = point_i == component_end_index - 1;
279+
vtx.position = polyline.points[point_i] + offset;
280+
vtx_builder.AppendVertex(vtx);
281+
vtx.position = polyline.points[point_i] - offset;
282+
vtx_builder.AppendVertex(vtx);
283+
284+
// For line components, two additional points need to be appended
285+
// prior to appending a join connecting the next component.
286+
vtx.position = polyline.points[point_i + 1] + offset;
287+
vtx_builder.AppendVertex(vtx);
288+
vtx.position = polyline.points[point_i + 1] - offset;
289+
vtx_builder.AppendVertex(vtx);
290+
291+
compute_offset(point_i + 2, contour_start_point_i,
292+
contour_end_point_i, contour);
293+
if (!is_last_component && is_end_of_component) {
294+
// Generate join from the current line to the next line.
295+
join_proc(vtx_builder, polyline.points[point_i + 1],
296+
previous_offset, offset, scaled_miter_limit, scale);
297+
}
298+
}
299+
};
300+
301+
auto add_vertices_for_curve_compoent =
302+
[&vtx_builder, &offset, &previous_offset, &vtx, &polyline,
303+
&compute_offset, scaled_miter_limit, scale, &join_proc](
304+
const size_t component_start_index, const size_t component_end_index,
305+
const size_t contour_start_point_i, const size_t contour_end_point_i,
306+
const Path::PolylineContour& contour) {
307+
auto is_last_component =
308+
component_start_index ==
309+
contour.components.back().component_start_index;
310+
311+
for (size_t point_i = component_start_index;
312+
point_i < component_end_index; point_i++) {
313+
auto is_end_of_component = point_i == component_end_index - 1;
314+
315+
vtx.position = polyline.points[point_i] + offset;
316+
vtx_builder.AppendVertex(vtx);
317+
vtx.position = polyline.points[point_i] - offset;
318+
vtx_builder.AppendVertex(vtx);
319+
320+
compute_offset(point_i + 2, contour_start_point_i,
321+
contour_end_point_i, contour);
322+
// For curve components, the polyline is detailed enough such that
323+
// it can avoid worrying about joins altogether.
324+
if (is_end_of_component) {
325+
vtx.position = polyline.points[point_i + 1] + offset;
326+
vtx_builder.AppendVertex(vtx);
327+
vtx.position = polyline.points[point_i + 1] - offset;
328+
vtx_builder.AppendVertex(vtx);
329+
// Generate join from the current line to the next line.
330+
if (!is_last_component) {
331+
join_proc(vtx_builder, polyline.points[point_i + 1],
332+
previous_offset, offset, scaled_miter_limit, scale);
333+
}
334+
}
335+
}
336+
};
337+
253338
for (size_t contour_i = 0; contour_i < polyline.contours.size();
254339
contour_i++) {
255340
auto contour = polyline.contours[contour_i];
256-
size_t contour_component_i = 0;
257341
size_t contour_start_point_i, contour_end_point_i;
258342
std::tie(contour_start_point_i, contour_end_point_i) =
259343
polyline.GetContourPointBounds(contour_i);
@@ -271,8 +355,8 @@ StrokePathGeometry::CreateSolidStrokeVertices(
271355
break;
272356
}
273357

274-
// The first point's offset is always the same as the second point.
275-
compute_offset(contour_start_point_i + 1);
358+
compute_offset(contour_start_point_i, contour_start_point_i,
359+
contour_end_point_i, contour);
276360
const Point contour_first_offset = offset;
277361

278362
if (contour_i > 0) {
@@ -306,53 +390,26 @@ StrokePathGeometry::CreateSolidStrokeVertices(
306390
scale, true);
307391
}
308392

309-
// Generate contour geometry.
310-
for (size_t point_i = contour_start_point_i + 1;
311-
point_i < contour_end_point_i; point_i++) {
312-
if ((contour_component_i + 1 >= contour.components.size()) &&
313-
contour.components[contour_component_i + 1].component_start_index <=
314-
point_i) {
315-
// The point_i has entered the next component in this contour.
316-
contour_component_i += 1;
317-
}
318-
// Generate line rect.
319-
vtx.position = polyline.points[point_i - 1] + offset;
320-
vtx_builder.AppendVertex(vtx);
321-
vtx.position = polyline.points[point_i - 1] - offset;
322-
vtx_builder.AppendVertex(vtx);
323-
324-
auto is_end_of_contour = point_i == contour_end_point_i - 1;
325-
326-
if (!contour.components[contour_component_i].is_curve) {
327-
// For line components, two additional points need to be appended prior
328-
// to appending a join connecting the next component.
329-
vtx.position = polyline.points[point_i] + offset;
330-
vtx_builder.AppendVertex(vtx);
331-
vtx.position = polyline.points[point_i] - offset;
332-
vtx_builder.AppendVertex(vtx);
333-
334-
if (!is_end_of_contour) {
335-
compute_offset(point_i + 1);
336-
// Generate join from the current line to the next line.
337-
join_proc(vtx_builder, polyline.points[point_i], previous_offset,
338-
offset, scaled_miter_limit, scale);
339-
}
393+
for (size_t contour_component_i = 0;
394+
contour_component_i < contour.components.size();
395+
contour_component_i++) {
396+
auto component = contour.components[contour_component_i];
397+
auto is_last_component =
398+
contour_component_i == contour.components.size() - 1;
399+
400+
auto component_start_index = component.component_start_index;
401+
auto component_end_index =
402+
is_last_component ? contour_end_point_i - 1
403+
: contour.components[contour_component_i + 1]
404+
.component_start_index;
405+
if (component.is_curve) {
406+
add_vertices_for_curve_compoent(
407+
component_start_index, component_end_index, contour_start_point_i,
408+
contour_end_point_i, contour);
340409
} else {
341-
// For curve components, the polyline is detailed enough such that
342-
// it can avoid worrying about joins altogether.
343-
if (!is_end_of_contour) {
344-
compute_offset(point_i + 1);
345-
} else {
346-
// If this is a curve and is the end of the contour, two end points
347-
// need to be drawn with the contour end_direction.
348-
auto end_offset =
349-
Vector2(-contour.end_direction.y, contour.end_direction.x) *
350-
stroke_width * 0.5;
351-
vtx.position = polyline.points[contour_end_point_i - 1] + end_offset;
352-
vtx_builder.AppendVertex(vtx);
353-
vtx.position = polyline.points[contour_end_point_i - 1] - end_offset;
354-
vtx_builder.AppendVertex(vtx);
355-
}
410+
add_vertices_for_linear_compoent(
411+
component_start_index, component_end_index, contour_start_point_i,
412+
contour_end_point_i, contour);
356413
}
357414
}
358415

impeller/geometry/path.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -367,23 +367,23 @@ Path::Polyline Path::CreatePolyline(Scalar scale) const {
367367
switch (component.type) {
368368
case ComponentType::kLinear:
369369
components.push_back({
370-
.component_start_index = polyline.points.size(),
370+
.component_start_index = polyline.points.size() - 1,
371371
.is_curve = false,
372372
});
373373
collect_points(linears_[component.index].CreatePolyline());
374374
previous_path_component_index = component_i;
375375
break;
376376
case ComponentType::kQuadratic:
377377
components.push_back({
378-
.component_start_index = polyline.points.size(),
378+
.component_start_index = polyline.points.size() - 1,
379379
.is_curve = true,
380380
});
381381
collect_points(quads_[component.index].CreatePolyline(scale));
382382
previous_path_component_index = component_i;
383383
break;
384384
case ComponentType::kCubic:
385385
components.push_back({
386-
.component_start_index = polyline.points.size(),
386+
.component_start_index = polyline.points.size() - 1,
387387
.is_curve = true,
388388
});
389389
collect_points(cubics_[component.index].CreatePolyline(scale));

impeller/geometry/path_builder.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,9 @@ PathBuilder& PathBuilder::AddRect(Rect rect) {
187187
auto tr = rect.origin + Point{rect.size.width, 0.0};
188188

189189
MoveTo(tl);
190-
prototype_.AddLinearComponent(tl, tr)
191-
.AddLinearComponent(tr, br)
192-
.AddLinearComponent(br, bl);
190+
LineTo(tr);
191+
LineTo(br);
192+
LineTo(bl);
193193
Close();
194194

195195
return *this;

0 commit comments

Comments
 (0)