diff --git a/Userland/Libraries/LibGfx/EdgeFlagPathRasterizer.cpp b/Userland/Libraries/LibGfx/EdgeFlagPathRasterizer.cpp index 61f905b071..42d9d110bc 100644 --- a/Userland/Libraries/LibGfx/EdgeFlagPathRasterizer.cpp +++ b/Userland/Libraries/LibGfx/EdgeFlagPathRasterizer.cpp @@ -141,7 +141,11 @@ void EdgeFlagPathRasterizer::fill_internal(Painter& painter, Pa // FIXME: We could probably clip some of the egde plotting if we know it won't be shown. // Though care would have to be taken to ensure the active edges are correct at the first drawn scaline. - auto for_each_sample = [&](Detail::Edge& edge, int start_subpixel_y, int end_subpixel_y, auto callback) { + auto empty_edge_extent = [&] { + return EdgeExtent { m_size.width() - 1, 0 }; + }; + + auto for_each_sample = [&](Detail::Edge& edge, int start_subpixel_y, int end_subpixel_y, EdgeExtent& edge_extent, auto callback) { for (int y = start_subpixel_y; y < end_subpixel_y; y++) { int xi = static_cast(edge.x + SubpixelSample::nrooks_subpixel_offsets[y]); if (xi < 0 || xi >= (int)m_scanline.size()) { @@ -154,20 +158,23 @@ void EdgeFlagPathRasterizer::fill_internal(Painter& painter, Pa SampleType sample = 1 << y; callback(xi, y, sample); edge.x += edge.dxdy; + edge_extent.min_x = min(edge_extent.min_x, xi); + edge_extent.max_x = max(edge_extent.max_x, xi); } }; Detail::Edge* active_edges = nullptr; if (winding_rule == Painter::WindingRule::EvenOdd) { - auto plot_edge = [&](Detail::Edge& edge, int start_subpixel_y, int end_subpixel_y) { - for_each_sample(edge, start_subpixel_y, end_subpixel_y, [&](int xi, int, SampleType sample) { + auto plot_edge = [&](Detail::Edge& edge, int start_subpixel_y, int end_subpixel_y, EdgeExtent& edge_extent) { + for_each_sample(edge, start_subpixel_y, end_subpixel_y, edge_extent, [&](int xi, int, SampleType sample) { m_scanline[xi] ^= sample; }); }; for (int scanline = min_scanline; scanline <= max_scanline; scanline++) { - active_edges = plot_edges_for_scanline(scanline, plot_edge, active_edges); - accumulate_even_odd_scanline(painter, scanline, color_or_function); + auto edge_extent = empty_edge_extent(); + active_edges = plot_edges_for_scanline(scanline, plot_edge, edge_extent, active_edges); + accumulate_even_odd_scanline(painter, scanline, edge_extent, color_or_function); } } else { VERIFY(winding_rule == Painter::WindingRule::Nonzero); @@ -176,15 +183,16 @@ void EdgeFlagPathRasterizer::fill_internal(Painter& painter, Pa if (m_windings.is_empty()) m_windings.resize(m_size.width()); - auto plot_edge = [&](Detail::Edge& edge, int start_subpixel_y, int end_subpixel_y) { - for_each_sample(edge, start_subpixel_y, end_subpixel_y, [&](int xi, int y, SampleType sample) { + auto plot_edge = [&](Detail::Edge& edge, int start_subpixel_y, int end_subpixel_y, EdgeExtent& edge_extent) { + for_each_sample(edge, start_subpixel_y, end_subpixel_y, edge_extent, [&](int xi, int y, SampleType sample) { m_scanline[xi] |= sample; m_windings[xi].counts[y] += edge.winding; }); }; for (int scanline = min_scanline; scanline <= max_scanline; scanline++) { - active_edges = plot_edges_for_scanline(scanline, plot_edge, active_edges); - accumulate_non_zero_scanline(painter, scanline, color_or_function); + auto edge_extent = empty_edge_extent(); + active_edges = plot_edges_for_scanline(scanline, plot_edge, edge_extent, active_edges); + accumulate_non_zero_scanline(painter, scanline, edge_extent, color_or_function); } } } @@ -205,7 +213,7 @@ Color EdgeFlagPathRasterizer::scanline_color(int scanline, int } template -Detail::Edge* EdgeFlagPathRasterizer::plot_edges_for_scanline(int scanline, auto plot_edge, Detail::Edge* active_edges) +Detail::Edge* EdgeFlagPathRasterizer::plot_edges_for_scanline(int scanline, auto plot_edge, EdgeExtent& edge_extent, Detail::Edge* active_edges) { auto y_subpixel = [](int y) { return y & (SamplesPerPixel - 1); @@ -220,7 +228,7 @@ Detail::Edge* EdgeFlagPathRasterizer::plot_edges_for_scanline(i int end_scanline = current_edge->max_y / SamplesPerPixel; if (scanline == end_scanline) { // This edge ends this scanline. - plot_edge(*current_edge, 0, y_subpixel(current_edge->max_y)); + plot_edge(*current_edge, 0, y_subpixel(current_edge->max_y), edge_extent); // Remove this edge from the AET current_edge = current_edge->next_edge; if (prev_edge) @@ -229,7 +237,7 @@ Detail::Edge* EdgeFlagPathRasterizer::plot_edges_for_scanline(i active_edges = current_edge; } else { // This egde sticks around for a few more scanlines. - plot_edge(*current_edge, 0, SamplesPerPixel); + plot_edge(*current_edge, 0, SamplesPerPixel, edge_extent); prev_edge = current_edge; current_edge = current_edge->next_edge; } @@ -242,10 +250,10 @@ Detail::Edge* EdgeFlagPathRasterizer::plot_edges_for_scanline(i int end_scanline = current_edge->max_y / SamplesPerPixel; if (scanline == end_scanline) { // This edge will end this scanlines (no need to add to AET). - plot_edge(*current_edge, y_subpixel(current_edge->min_y), y_subpixel(current_edge->max_y)); + plot_edge(*current_edge, y_subpixel(current_edge->min_y), y_subpixel(current_edge->max_y), edge_extent); } else { // This edge will live on for a few more scanlines. - plot_edge(*current_edge, y_subpixel(current_edge->min_y), SamplesPerPixel); + plot_edge(*current_edge, y_subpixel(current_edge->min_y), SamplesPerPixel, edge_extent); // Add this edge to the AET if (prev_edge) prev_edge->next_edge = current_edge; @@ -278,18 +286,18 @@ void EdgeFlagPathRasterizer::write_pixel(Painter& painter, int } template -void EdgeFlagPathRasterizer::accumulate_even_odd_scanline(Painter& painter, int scanline, auto& color_or_function) +void EdgeFlagPathRasterizer::accumulate_even_odd_scanline(Painter& painter, int scanline, EdgeExtent edge_extent, auto& color_or_function) { auto dest_y = m_blit_origin.y() + scanline; if (!m_clip.contains_vertically(dest_y)) { // FIXME: This memset only really needs to be done on transition from clipped to not clipped, // or not at all if we properly clipped egde plotting. - memset(m_scanline.data(), 0, sizeof(SampleType) * m_scanline.size()); + edge_extent.memset_extent(m_scanline.data(), 0); return; } SampleType sample = 0; - for (int x = 0; x < m_size.width(); x += 1) { + for (int x = edge_extent.min_x; x <= edge_extent.max_x; x += 1) { sample ^= m_scanline[x]; write_pixel(painter, scanline, x, sample, color_or_function); m_scanline[x] = 0; @@ -297,19 +305,19 @@ void EdgeFlagPathRasterizer::accumulate_even_odd_scanline(Paint } template -void EdgeFlagPathRasterizer::accumulate_non_zero_scanline(Painter& painter, int scanline, auto& color_or_function) +void EdgeFlagPathRasterizer::accumulate_non_zero_scanline(Painter& painter, int scanline, EdgeExtent edge_extent, auto& color_or_function) { // NOTE: Same FIXMEs apply from accumulate_even_odd_scanline() auto dest_y = m_blit_origin.y() + scanline; if (!m_clip.contains_vertically(dest_y)) { - memset(m_scanline.data(), 0, sizeof(SampleType) * m_scanline.size()); - memset(m_windings.data(), 0, sizeof(WindingCounts) * m_windings.size()); + edge_extent.memset_extent(m_scanline.data(), 0); + edge_extent.memset_extent(m_windings.data(), 0); return; } SampleType sample = 0; WindingCounts sum_winding = {}; - for (int x = 0; x < m_size.width(); x += 1) { + for (int x = edge_extent.min_x; x <= edge_extent.max_x; x += 1) { if (auto edges = m_scanline[x]) { // We only need to process the windings when we hit some edges. for (auto y_sub = 0u; y_sub < SamplesPerPixel; y_sub++) { diff --git a/Userland/Libraries/LibGfx/EdgeFlagPathRasterizer.h b/Userland/Libraries/LibGfx/EdgeFlagPathRasterizer.h index f74289b116..3a9a81b1ce 100644 --- a/Userland/Libraries/LibGfx/EdgeFlagPathRasterizer.h +++ b/Userland/Libraries/LibGfx/EdgeFlagPathRasterizer.h @@ -160,10 +160,22 @@ private: return (coverage << alpha_shift) - 1; } + struct EdgeExtent { + int min_x; + int max_x; + + template + void memset_extent(T* data, int value) + { + if (min_x <= max_x) + memset(data + min_x, value, (max_x - min_x + 1) * sizeof(T)); + } + }; + void fill_internal(Painter&, Path const&, auto color_or_function, Painter::WindingRule, FloatPoint offset); - Detail::Edge* plot_edges_for_scanline(int scanline, auto plot_edge, Detail::Edge* active_edges = nullptr); - void accumulate_even_odd_scanline(Painter&, int scanline, auto& color_or_function); - void accumulate_non_zero_scanline(Painter&, int scanline, auto& color_or_function); + Detail::Edge* plot_edges_for_scanline(int scanline, auto plot_edge, EdgeExtent&, Detail::Edge* active_edges = nullptr); + void accumulate_even_odd_scanline(Painter&, int scanline, EdgeExtent, auto& color_or_function); + void accumulate_non_zero_scanline(Painter&, int scanline, EdgeExtent, auto& color_or_function); Color scanline_color(int scanline, int offset, u8 alpha, auto& color_or_function); void write_pixel(Painter&, int scanline, int offset, SampleType sample, auto& color_or_function);