Skip to content

Commit 37a3285

Browse files
authored
Auto merge of #419 - pcwalton:tile-iteration-cap, r=pcwalton
Clip line segments before tiling them, and remove the cap on the number of iterations when tiling. Closes #416.
2 parents 4c8699a + 441051a commit 37a3285

File tree

3 files changed

+86
-10
lines changed

3 files changed

+86
-10
lines changed

content/src/clip.rs

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use arrayvec::ArrayVec;
1818
use pathfinder_geometry::line_segment::LineSegment2F;
1919
use pathfinder_geometry::rect::RectF;
2020
use pathfinder_geometry::util::lerp;
21-
use pathfinder_geometry::vector::{Vector2F, Vector4F};
21+
use pathfinder_geometry::vector::{Vector2F, Vector4F, vec2f};
2222
use smallvec::SmallVec;
2323
use std::fmt::Debug;
2424
use std::mem;
@@ -490,6 +490,80 @@ pub(crate) fn rect_is_inside_polygon(rect: RectF, polygon_points: &[Vector2F]) -
490490
true
491491
}
492492

493+
/// Clips a line segment to an axis-aligned rectangle using Cohen-Sutherland clipping.
494+
pub fn clip_line_segment_to_rect(mut line_segment: LineSegment2F, rect: RectF)
495+
-> Option<LineSegment2F> {
496+
let mut outcode_from = compute_outcode(line_segment.from(), rect);
497+
let mut outcode_to = compute_outcode(line_segment.to(), rect);
498+
499+
loop {
500+
if outcode_from.is_empty() && outcode_to.is_empty() {
501+
return Some(line_segment);
502+
}
503+
if !(outcode_from & outcode_to).is_empty() {
504+
return None;
505+
}
506+
507+
let clip_from = outcode_from.bits() > outcode_to.bits();
508+
let (mut point, outcode) = if clip_from {
509+
(line_segment.from(), outcode_from)
510+
} else {
511+
(line_segment.to(), outcode_to)
512+
};
513+
514+
if outcode.contains(Outcode::LEFT) {
515+
point = vec2f(rect.min_x(),
516+
lerp(line_segment.from_y(),
517+
line_segment.to_y(),
518+
(line_segment.min_x() - line_segment.from_x()) /
519+
(line_segment.max_x() - line_segment.min_x())));
520+
} else if outcode.contains(Outcode::RIGHT) {
521+
point = vec2f(rect.max_x(),
522+
lerp(line_segment.from_y(),
523+
line_segment.to_y(),
524+
(line_segment.max_x() - line_segment.from_x()) /
525+
(line_segment.max_x() - line_segment.min_x())));
526+
} else if outcode.contains(Outcode::TOP) {
527+
point = vec2f(lerp(line_segment.from_x(),
528+
line_segment.to_x(),
529+
(line_segment.min_y() - line_segment.from_y()) /
530+
(line_segment.max_y() - line_segment.min_y())),
531+
rect.min_y());
532+
} else if outcode.contains(Outcode::LEFT) {
533+
point = vec2f(lerp(line_segment.from_x(),
534+
line_segment.to_x(),
535+
(line_segment.max_y() - line_segment.from_y()) /
536+
(line_segment.max_y() - line_segment.min_y())),
537+
rect.min_y());
538+
}
539+
540+
if clip_from {
541+
line_segment.set_from(point);
542+
outcode_from = compute_outcode(point, rect);
543+
} else {
544+
line_segment.set_to(point);
545+
outcode_to = compute_outcode(point, rect);
546+
}
547+
}
548+
549+
fn compute_outcode(point: Vector2F, rect: RectF) -> Outcode {
550+
let mut outcode = Outcode::empty();
551+
if point.x() < rect.min_x() {
552+
outcode.insert(Outcode::LEFT);
553+
}
554+
if point.y() < rect.min_y() {
555+
outcode.insert(Outcode::TOP);
556+
}
557+
if point.x() > rect.max_x() {
558+
outcode.insert(Outcode::RIGHT);
559+
}
560+
if point.y() > rect.max_y() {
561+
outcode.insert(Outcode::BOTTOM);
562+
}
563+
outcode
564+
}
565+
}
566+
493567
bitflags! {
494568
struct Outcode: u8 {
495569
const LEFT = 0x01;

renderer/src/builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const CURVE_IS_CUBIC: u32 = 0x40000000;
5050
const MAX_CLIP_BATCHES: u32 = 32;
5151

5252
pub(crate) struct SceneBuilder<'a, 'b, 'c, 'd> {
53-
scene: &'a mut Scene,
53+
pub(crate) scene: &'a mut Scene,
5454
built_options: &'b PreparedBuildOptions,
5555
next_alpha_tile_indices: [AtomicUsize; ALPHA_TILE_LEVEL_COUNT],
5656
pub(crate) sink: &'c mut SceneSink<'d>,

renderer/src/tiler.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ use crate::gpu_data::AlphaTileId;
1717
use crate::options::PrepareMode;
1818
use crate::scene::{ClipPathId, PathId};
1919
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH, TilingPathInfo};
20+
use pathfinder_content::clip;
2021
use pathfinder_content::fill::FillRule;
2122
use pathfinder_content::outline::{ContourIterFlags, Outline};
2223
use pathfinder_content::segment::Segment;
2324
use pathfinder_geometry::line_segment::LineSegment2F;
2425
use pathfinder_geometry::rect::RectF;
2526
use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2f, vec2i};
2627
use pathfinder_simd::default::{F32x2, U32x2};
28+
use std::f32::NEG_INFINITY;
2729

2830
const FLATTENING_TOLERANCE: f32 = 0.25;
2931

@@ -189,6 +191,14 @@ fn process_segment(segment: &Segment,
189191
fn process_line_segment(line_segment: LineSegment2F,
190192
scene_builder: &SceneBuilder,
191193
object_builder: &mut ObjectBuilder) {
194+
let view_box = scene_builder.scene.view_box();
195+
let clip_box = RectF::from_points(vec2f(view_box.min_x(), NEG_INFINITY),
196+
view_box.lower_right());
197+
let line_segment = match clip::clip_line_segment_to_rect(line_segment, clip_box) {
198+
None => return,
199+
Some(line_segment) => line_segment,
200+
};
201+
192202
let tile_size = vec2f(TILE_WIDTH as f32, TILE_HEIGHT as f32);
193203
let tile_size_recip = Vector2F::splat(1.0) / tile_size;
194204

@@ -214,12 +224,8 @@ fn process_line_segment(line_segment: LineSegment2F,
214224

215225
let (mut current_position, mut tile_coords) = (line_segment.from(), from_tile_coords);
216226
let mut last_step_direction = None;
217-
let mut iteration = 0;
218227

219228
loop {
220-
// Quick check to catch missing the end tile.
221-
debug_assert!(iteration < MAX_ITERATIONS);
222-
223229
let next_step_direction = if t_max.x() < t_max.y() {
224230
StepDirection::X
225231
} else if t_max.x() > t_max.y() {
@@ -292,11 +298,7 @@ fn process_line_segment(line_segment: LineSegment2F,
292298

293299
current_position = next_position;
294300
last_step_direction = next_step_direction;
295-
296-
iteration += 1;
297301
}
298-
299-
const MAX_ITERATIONS: u32 = 1024;
300302
}
301303

302304
#[derive(Clone, Copy, PartialEq, Debug)]

0 commit comments

Comments
 (0)