Extract stroke dirty bounds planning

This commit is contained in:
2026-06-13 04:35:14 +02:00
parent 458f9bef0c
commit 36861cbf97
8 changed files with 509 additions and 40 deletions

View File

@@ -15,7 +15,12 @@ using pp::paint::Rgba;
using pp::paint::StrokeBlendMode;
using pp::assets::decode_png_rgba8;
using pp::paint_renderer::CanvasBlendGateRequest;
using pp::paint_renderer::CanvasStrokeBox;
using pp::paint_renderer::CanvasStrokeFaceDirtyUpdateRequest;
using pp::paint_renderer::CanvasStrokeMaterialRequest;
using pp::paint_renderer::CanvasStrokePadRegionRequest;
using pp::paint_renderer::CanvasStrokePoint;
using pp::paint_renderer::CanvasStrokeSampleBoundsRequest;
using pp::paint_renderer::CanvasStrokeTextureRole;
using pp::paint_renderer::DocumentFaceCompositeRequest;
using pp::paint_renderer::DocumentFrameCompositeRequest;
@@ -27,9 +32,12 @@ using pp::paint_renderer::composite_document_face;
using pp::paint_renderer::composite_document_frame;
using pp::paint_renderer::export_document_depth_pngs;
using pp::paint_renderer::plan_canvas_blend_gate;
using pp::paint_renderer::plan_canvas_stroke_face_dirty_update;
using pp::paint_renderer::plan_canvas_stroke_feedback;
using pp::paint_renderer::plan_canvas_stroke_material;
using pp::paint_renderer::plan_canvas_stroke_pad_region;
using pp::paint_renderer::plan_canvas_stroke_rasterization;
using pp::paint_renderer::plan_canvas_stroke_sample_bounds;
using pp::paint_renderer::plan_document_depth_export_render;
using pp::paint_renderer::plan_stroke_composite;
using pp::paint_renderer::stroke_composite_path_name;
@@ -1879,6 +1887,169 @@ void plans_canvas_stroke_rasterization_boundary(pp::tests::Harness& h)
PP_EXPECT(h, invalid.status().code == StatusCode::invalid_argument);
}
void canvas_stroke_sample_bounds_empty_vertices_have_no_pixels(pp::tests::Harness& h)
{
const auto plan = plan_canvas_stroke_sample_bounds(
CanvasStrokeSampleBoundsRequest {
.extent = Extent2D { .width = 32, .height = 16 },
.vertices = {},
});
PP_EXPECT(h, !plan.has_pixels);
PP_EXPECT(h, plan.copy_region.width == 0);
PP_EXPECT(h, plan.copy_region.height == 0);
}
void canvas_stroke_sample_bounds_expand_rect_with_one_pixel_pad(pp::tests::Harness& h)
{
const CanvasStrokePoint vertices[] {
{ .x = 10.0F, .y = 20.0F },
{ .x = 10.0F, .y = 30.0F },
{ .x = 30.0F, .y = 30.0F },
{ .x = 30.0F, .y = 20.0F },
};
const auto plan = plan_canvas_stroke_sample_bounds(
CanvasStrokeSampleBoundsRequest {
.extent = Extent2D { .width = 64, .height = 64 },
.vertices = vertices,
});
PP_EXPECT(h, plan.has_pixels);
PP_EXPECT(h, plan.copy_region.x == 9);
PP_EXPECT(h, plan.copy_region.y == 19);
PP_EXPECT(h, plan.copy_region.width == 22);
PP_EXPECT(h, plan.copy_region.height == 12);
PP_EXPECT(h, near(plan.dirty_bounds.min_x, 9.0F));
PP_EXPECT(h, near(plan.dirty_bounds.min_y, 19.0F));
PP_EXPECT(h, near(plan.dirty_bounds.max_x, 31.0F));
PP_EXPECT(h, near(plan.dirty_bounds.max_y, 31.0F));
}
void canvas_stroke_sample_bounds_clamp_out_of_range_vertices(pp::tests::Harness& h)
{
const CanvasStrokePoint vertices[] {
{ .x = -10.0F, .y = -5.0F },
{ .x = 70.0F, .y = 80.0F },
};
const auto plan = plan_canvas_stroke_sample_bounds(
CanvasStrokeSampleBoundsRequest {
.extent = Extent2D { .width = 64, .height = 32 },
.vertices = vertices,
});
PP_EXPECT(h, plan.has_pixels);
PP_EXPECT(h, plan.copy_region.x == 0);
PP_EXPECT(h, plan.copy_region.y == 0);
PP_EXPECT(h, plan.copy_region.width == 64);
PP_EXPECT(h, plan.copy_region.height == 32);
PP_EXPECT(h, near(plan.dirty_bounds.max_x, 64.0F));
PP_EXPECT(h, near(plan.dirty_bounds.max_y, 32.0F));
}
void canvas_stroke_pad_region_clamps_edges_with_twenty_pixel_pad(pp::tests::Harness& h)
{
const auto plan = plan_canvas_stroke_pad_region(
CanvasStrokePadRegionRequest {
.extent = Extent2D { .width = 100, .height = 80 },
.pass_dirty_box = CanvasStrokeBox {
.min_x = 5.0F,
.min_y = 10.0F,
.max_x = 20.0F,
.max_y = 30.0F,
},
});
PP_EXPECT(h, plan.has_pixels);
PP_EXPECT(h, plan.copy_region.x == 0);
PP_EXPECT(h, plan.copy_region.y == 0);
PP_EXPECT(h, plan.copy_region.width == 40);
PP_EXPECT(h, plan.copy_region.height == 50);
PP_EXPECT(h, near(plan.ndc_quad[0].x, -1.0F));
PP_EXPECT(h, near(plan.ndc_quad[0].y, -1.0F));
PP_EXPECT(h, near(plan.ndc_quad[2].x, -0.2F));
PP_EXPECT(h, near(plan.ndc_quad[2].y, 0.25F));
PP_EXPECT(h, near(plan.ndc_quad[5].x, -0.2F));
PP_EXPECT(h, near(plan.ndc_quad[5].y, -1.0F));
}
void canvas_stroke_face_dirty_update_includes_committed_dirty_box(pp::tests::Harness& h)
{
const auto plan = plan_canvas_stroke_face_dirty_update(
CanvasStrokeFaceDirtyUpdateRequest {
.extent = Extent2D { .width = 64, .height = 32 },
.previous_accumulated_dirty_box = CanvasStrokeBox {
.min_x = 64.0F,
.min_y = 32.0F,
.max_x = 0.0F,
.max_y = 0.0F,
},
.previous_pass_dirty_box = CanvasStrokeBox {
.min_x = 64.0F,
.min_y = 32.0F,
.max_x = 0.0F,
.max_y = 0.0F,
},
.sample_dirty_box = CanvasStrokeBox {
.min_x = -5.0F,
.min_y = -3.0F,
.max_x = 80.0F,
.max_y = 90.0F,
},
.include_in_committed_dirty_box = true,
});
PP_EXPECT(h, plan.has_dirty_pixels);
PP_EXPECT(h, plan.committed_dirty);
PP_EXPECT(h, plan.pass_dirty);
PP_EXPECT(h, near(plan.accumulated_dirty_box.min_x, 0.0F));
PP_EXPECT(h, near(plan.accumulated_dirty_box.min_y, 0.0F));
PP_EXPECT(h, near(plan.accumulated_dirty_box.max_x, 64.0F));
PP_EXPECT(h, near(plan.accumulated_dirty_box.max_y, 64.0F));
PP_EXPECT(h, near(plan.pass_dirty_box.min_x, -5.0F));
PP_EXPECT(h, near(plan.pass_dirty_box.max_y, 90.0F));
}
void canvas_stroke_face_dirty_update_can_skip_committed_dirty_box(pp::tests::Harness& h)
{
const auto plan = plan_canvas_stroke_face_dirty_update(
CanvasStrokeFaceDirtyUpdateRequest {
.extent = Extent2D { .width = 64, .height = 32 },
.previous_accumulated_dirty_box = CanvasStrokeBox {
.min_x = 1.0F,
.min_y = 2.0F,
.max_x = 3.0F,
.max_y = 4.0F,
},
.previous_pass_dirty_box = CanvasStrokeBox {
.min_x = 10.0F,
.min_y = 10.0F,
.max_x = 20.0F,
.max_y = 20.0F,
},
.sample_dirty_box = CanvasStrokeBox {
.min_x = 0.0F,
.min_y = 0.0F,
.max_x = 30.0F,
.max_y = 30.0F,
},
.include_in_committed_dirty_box = false,
});
PP_EXPECT(h, plan.has_dirty_pixels);
PP_EXPECT(h, !plan.committed_dirty);
PP_EXPECT(h, plan.pass_dirty);
PP_EXPECT(h, near(plan.accumulated_dirty_box.min_x, 1.0F));
PP_EXPECT(h, near(plan.accumulated_dirty_box.min_y, 2.0F));
PP_EXPECT(h, near(plan.accumulated_dirty_box.max_x, 3.0F));
PP_EXPECT(h, near(plan.accumulated_dirty_box.max_y, 4.0F));
PP_EXPECT(h, near(plan.pass_dirty_box.min_x, 0.0F));
PP_EXPECT(h, near(plan.pass_dirty_box.min_y, 0.0F));
PP_EXPECT(h, near(plan.pass_dirty_box.max_x, 30.0F));
PP_EXPECT(h, near(plan.pass_dirty_box.max_y, 30.0F));
}
}
int main()
@@ -1920,5 +2091,23 @@ int main()
harness.run("plans_canvas_stroke_feedback_paths", plans_canvas_stroke_feedback_paths);
harness.run("canvas_stroke_feedback_preserves_legacy_fallback", canvas_stroke_feedback_preserves_legacy_fallback);
harness.run("plans_canvas_stroke_rasterization_boundary", plans_canvas_stroke_rasterization_boundary);
harness.run(
"canvas_stroke_sample_bounds_empty_vertices_have_no_pixels",
canvas_stroke_sample_bounds_empty_vertices_have_no_pixels);
harness.run(
"canvas_stroke_sample_bounds_expand_rect_with_one_pixel_pad",
canvas_stroke_sample_bounds_expand_rect_with_one_pixel_pad);
harness.run(
"canvas_stroke_sample_bounds_clamp_out_of_range_vertices",
canvas_stroke_sample_bounds_clamp_out_of_range_vertices);
harness.run(
"canvas_stroke_pad_region_clamps_edges_with_twenty_pixel_pad",
canvas_stroke_pad_region_clamps_edges_with_twenty_pixel_pad);
harness.run(
"canvas_stroke_face_dirty_update_includes_committed_dirty_box",
canvas_stroke_face_dirty_update_includes_committed_dirty_box);
harness.run(
"canvas_stroke_face_dirty_update_can_skip_committed_dirty_box",
canvas_stroke_face_dirty_update_can_skip_committed_dirty_box);
return harness.finish();
}