Migrate the monotonic conversion iterator away from Euclid types

This commit is contained in:
Patrick Walton 2019-01-11 14:21:02 -08:00
parent 2675864ce0
commit c8bbb71dd4
1 changed files with 29 additions and 89 deletions

View File

@ -235,8 +235,8 @@ impl Scene {
let path = UsvgPathToSegments::new(path.segments.iter().cloned()); let path = UsvgPathToSegments::new(path.segments.iter().cloned());
let path = PathTransformingIter::new(path, &transform); let path = PathTransformingIter::new(path, &transform);
let path = SegmentsToPathEvents::new(path);
let path = MonotonicConversionIter::new(path); let path = MonotonicConversionIter::new(path);
let path = SegmentsToPathEvents::new(path);
let outline = Outline::from_path_events(path); let outline = Outline::from_path_events(path);
scene.bounds = scene.bounds.union(&outline.bounds); scene.bounds = scene.bounds.union(&outline.bounds);
@ -257,8 +257,8 @@ impl Scene {
let path = StrokeToFillIter::new(path, StrokeStyle::new(stroke_width)); let path = StrokeToFillIter::new(path, StrokeStyle::new(stroke_width));
let path = PathEventsToSegments::new(path); let path = PathEventsToSegments::new(path);
let path = PathTransformingIter::new(path, &transform); let path = PathTransformingIter::new(path, &transform);
let path = SegmentsToPathEvents::new(path);
let path = MonotonicConversionIter::new(path); let path = MonotonicConversionIter::new(path);
let path = SegmentsToPathEvents::new(path);
let outline = Outline::from_path_events(path); let outline = Outline::from_path_events(path);
scene.bounds = scene.bounds.union(&outline.bounds); scene.bounds = scene.bounds.union(&outline.bounds);
@ -838,12 +838,12 @@ impl<'s> CubicSegment<'s> {
baseline: LineSegmentF32(baseline0), baseline: LineSegmentF32(baseline0),
ctrl: LineSegmentF32(ctrl0), ctrl: LineSegmentF32(ctrl0),
kind: SegmentKind::Cubic, kind: SegmentKind::Cubic,
flags: SegmentFlags::empty(), flags: self.0.flags & SegmentFlags::FIRST_IN_SUBPATH,
}, Segment { }, Segment {
baseline: LineSegmentF32(baseline1), baseline: LineSegmentF32(baseline1),
ctrl: LineSegmentF32(ctrl1), ctrl: LineSegmentF32(ctrl1),
kind: SegmentKind::Cubic, kind: SegmentKind::Cubic,
flags: SegmentFlags::empty(), flags: self.0.flags & SegmentFlags::CLOSES_SUBPATH,
}) })
} }
@ -1971,112 +1971,52 @@ impl<I> PathTransformingIter<I> where I: Iterator<Item = Segment> {
// Monotonic conversion utilities // Monotonic conversion utilities
// TODO(pcwalton): I think we only need to be monotonic in Y, maybe? // TODO(pcwalton): I think we only need to be monotonic in Y, maybe?
struct MonotonicConversionIter<I> where I: Iterator<Item = PathEvent> { struct MonotonicConversionIter<I> where I: Iterator<Item = Segment> {
inner: I, iter: I,
buffer: ArrayVec<[PathEvent; 2]>, buffer: ArrayVec<[Segment; 2]>,
last_point: Point2D<f32>,
} }
impl<I> Iterator for MonotonicConversionIter<I> where I: Iterator<Item = PathEvent> { impl<I> Iterator for MonotonicConversionIter<I> where I: Iterator<Item = Segment> {
type Item = PathEvent; type Item = Segment;
fn next(&mut self) -> Option<PathEvent> { fn next(&mut self) -> Option<Segment> {
if let Some(event) = self.buffer.pop() { if let Some(segment) = self.buffer.pop() {
match event { return Some(segment);
PathEvent::MoveTo(to) |
PathEvent::LineTo(to) |
PathEvent::QuadraticTo(_, to) |
PathEvent::CubicTo(_, _, to) => {
self.last_point = to;
}
PathEvent::Arc(..) | PathEvent::Close => {}
}
return Some(event);
} }
let event = match self.inner.next() { let segment = self.iter.next()?;
None => return None, match segment.kind {
Some(event) => event, SegmentKind::None => self.next(),
}; SegmentKind::Line => Some(segment),
SegmentKind::Cubic => self.handle_cubic(&segment),
match event { SegmentKind::Quadratic => {
PathEvent::MoveTo(to) => {
self.last_point = to;
Some(PathEvent::MoveTo(to))
}
PathEvent::LineTo(to) => {
self.last_point = to;
Some(PathEvent::LineTo(to))
}
PathEvent::CubicTo(ctrl0, ctrl1, to) => {
let mut segment = Segment::none();
segment.baseline = LineSegmentF32::new(&Point2DF32::from_euclid(self.last_point),
&Point2DF32::from_euclid(to));
segment.ctrl = LineSegmentF32::new(&Point2DF32::from_euclid(ctrl0),
&Point2DF32::from_euclid(ctrl1));
segment.kind = SegmentKind::Cubic;
return self.handle_cubic(&segment);
}
PathEvent::QuadraticTo(ctrl, to) => {
// TODO(pcwalton): Don't degree elevate! // TODO(pcwalton): Don't degree elevate!
let mut segment = Segment::none(); self.handle_cubic(&segment.to_cubic())
segment.baseline = LineSegmentF32::new(&Point2DF32::from_euclid(self.last_point),
&Point2DF32::from_euclid(to));
segment.ctrl = LineSegmentF32::new(&Point2DF32::from_euclid(ctrl),
&Point2DF32::default());
segment.kind = SegmentKind::Quadratic;
return self.handle_cubic(&segment.to_cubic());
}
PathEvent::Close => Some(PathEvent::Close),
PathEvent::Arc(a, b, c, d) => {
// FIXME(pcwalton): Make these monotonic too.
Some(PathEvent::Arc(a, b, c, d))
} }
} }
} }
} }
impl<I> MonotonicConversionIter<I> where I: Iterator<Item = PathEvent> { impl<I> MonotonicConversionIter<I> where I: Iterator<Item = Segment> {
fn new(inner: I) -> MonotonicConversionIter<I> { fn new(iter: I) -> MonotonicConversionIter<I> {
MonotonicConversionIter { MonotonicConversionIter { iter, buffer: ArrayVec::new() }
inner,
buffer: ArrayVec::new(),
last_point: Point2D::zero(),
}
} }
fn handle_cubic(&mut self, segment: &Segment) -> Option<PathEvent> { fn handle_cubic(&mut self, segment: &Segment) -> Option<Segment> {
match segment.as_cubic_segment().y_extrema() { match segment.as_cubic_segment().y_extrema() {
(Some(t0), Some(t1)) => { (Some(t0), Some(t1)) => {
let (segments_01, segment_2) = segment.as_cubic_segment().split(t1); let (segments_01, segment_2) = segment.as_cubic_segment().split(t1);
self.buffer.push(PathEvent::CubicTo(segment_2.ctrl.from().as_euclid(), self.buffer.push(segment_2);
segment_2.ctrl.to().as_euclid(),
segment_2.baseline.to().as_euclid()));
let (segment_0, segment_1) = segments_01.as_cubic_segment().split(t0 / t1); let (segment_0, segment_1) = segments_01.as_cubic_segment().split(t0 / t1);
self.buffer.push(PathEvent::CubicTo(segment_1.ctrl.from().as_euclid(), self.buffer.push(segment_1);
segment_1.ctrl.to().as_euclid(), Some(segment_0)
segment_1.baseline.to().as_euclid()));
self.last_point = segment_0.baseline.to().as_euclid();
return Some(PathEvent::CubicTo(segment_0.ctrl.from().as_euclid(),
segment_0.ctrl.to().as_euclid(),
segment_0.baseline.to().as_euclid()));
} }
(Some(t0), None) | (None, Some(t0)) => { (Some(t0), None) | (None, Some(t0)) => {
let (segment_0, segment_1) = segment.as_cubic_segment().split(t0); let (segment_0, segment_1) = segment.as_cubic_segment().split(t0);
self.buffer.push(PathEvent::CubicTo(segment_1.ctrl.from().as_euclid(), self.buffer.push(segment_1);
segment_1.ctrl.to().as_euclid(), Some(segment_0)
segment_1.baseline.to().as_euclid()));
self.last_point = segment_0.baseline.to().as_euclid();
return Some(PathEvent::CubicTo(segment_0.ctrl.from().as_euclid(),
segment_0.ctrl.to().as_euclid(),
segment_0.baseline.to().as_euclid()));
}
(None, None) => {
self.last_point = segment.baseline.to().as_euclid();
return Some(PathEvent::CubicTo(segment.ctrl.from().as_euclid(),
segment.ctrl.to().as_euclid(),
segment.baseline.to().as_euclid()));
} }
(None, None) => Some(*segment),
} }
} }
} }