Auto merge of #392 - pcwalton:docs-outline, r=pcwalton

Document the `pathfinder_content::outline` module
This commit is contained in:
bors-servo 2020-07-14 15:08:45 -04:00 committed by GitHub
commit f62f85354f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 159 additions and 29 deletions

View File

@ -8,9 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! Pathfinder's representation of a vector scene. //! Components of a vector scene, and various path utilities.
//!
//! This module also contains various path utilities.
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! A compressed in-memory representation of paths. //! A compressed in-memory representation of a vector path.
use crate::clip::{self, ContourPolygonClipper}; use crate::clip::{self, ContourPolygonClipper};
use crate::dilation::ContourDilator; use crate::dilation::ContourDilator;
@ -25,12 +25,20 @@ use std::f32::consts::PI;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::mem; use std::mem;
/// A vector path to be filled. Outlines (a.k.a. paths) consist of *contours* (a.k.a. subpaths),
/// which can be filled according to a fill rule.
///
/// The names "outline" and "contour" come from the TrueType specification. They were chosen to
/// avoid conflicting with the Rust use of "path" for filesystem paths.
#[derive(Clone)] #[derive(Clone)]
pub struct Outline { pub struct Outline {
pub(crate) contours: Vec<Contour>, pub(crate) contours: Vec<Contour>,
pub(crate) bounds: RectF, pub(crate) bounds: RectF,
} }
/// An individual subpath, consisting of a series of endpoints and/or control points. Contours can
/// be either open (first and last points disconnected) or closed (first point implicitly joined to
/// last point with a line).
#[derive(Clone)] #[derive(Clone)]
pub struct Contour { pub struct Contour {
pub(crate) points: Vec<Vector2F>, pub(crate) points: Vec<Vector2F>,
@ -40,20 +48,29 @@ pub struct Contour {
} }
bitflags! { bitflags! {
/// Flags that each point can have, indicating whether it is on-curve or whether it's a control
/// point.
pub struct PointFlags: u8 { pub struct PointFlags: u8 {
/// This point is the first control point of a cubic Bézier curve or the only control point
/// of a quadratic Bézier curve.
const CONTROL_POINT_0 = 0x01; const CONTROL_POINT_0 = 0x01;
/// This point is the second point of a quadratic Bézier curve.
const CONTROL_POINT_1 = 0x02; const CONTROL_POINT_1 = 0x02;
} }
} }
bitflags! { bitflags! {
pub struct PushSegmentFlags: u8 { // Flags specifying what actions to take when pushing a segment onto a contour.
pub(crate) struct PushSegmentFlags: u8 {
/// The bounds should be updated.
const UPDATE_BOUNDS = 0x01; const UPDATE_BOUNDS = 0x01;
/// The "from" point of the segme
const INCLUDE_FROM_POINT = 0x02; const INCLUDE_FROM_POINT = 0x02;
} }
} }
impl Outline { impl Outline {
/// Creates a new empty outline with no contours.
#[inline] #[inline]
pub fn new() -> Outline { pub fn new() -> Outline {
Outline { Outline {
@ -71,11 +88,9 @@ impl Outline {
} }
} }
/// Creates a new outline from a list of segments.
#[inline] #[inline]
pub fn from_segments<I>(segments: I) -> Outline pub fn from_segments<I>(segments: I) -> Outline where I: Iterator<Item = Segment> {
where
I: Iterator<Item = Segment>,
{
let mut outline = Outline::new(); let mut outline = Outline::new();
let mut current_contour = Contour::new(); let mut current_contour = Contour::new();
@ -120,6 +135,7 @@ impl Outline {
outline outline
} }
/// Creates a new outline that represents a single axis-aligned rectangle.
#[inline] #[inline]
pub fn from_rect(rect: RectF) -> Outline { pub fn from_rect(rect: RectF) -> Outline {
let mut outline = Outline::new(); let mut outline = Outline::new();
@ -127,6 +143,7 @@ impl Outline {
outline outline
} }
/// Creates a new outline that represents a rounded rectangle.
#[inline] #[inline]
pub fn from_rect_rounded(rect: RectF, radius: Vector2F) -> Outline { pub fn from_rect_rounded(rect: RectF, radius: Vector2F) -> Outline {
let mut outline = Outline::new(); let mut outline = Outline::new();
@ -134,16 +151,19 @@ impl Outline {
outline outline
} }
/// Returns the dimensions of an axis-aligned box that encloses the entire outline.
#[inline] #[inline]
pub fn bounds(&self) -> RectF { pub fn bounds(&self) -> RectF {
self.bounds self.bounds
} }
/// Returns a list of the subpaths in this path.
#[inline] #[inline]
pub fn contours(&self) -> &[Contour] { pub fn contours(&self) -> &[Contour] {
&self.contours &self.contours
} }
/// Destroys this outline and returns a list of its subpaths.
#[inline] #[inline]
pub fn into_contours(self) -> Vec<Contour> { pub fn into_contours(self) -> Vec<Contour> {
self.contours self.contours
@ -156,6 +176,7 @@ impl Outline {
self.bounds = RectF::default(); self.bounds = RectF::default();
} }
/// Adds a new subpath to this outline.
pub fn push_contour(&mut self, contour: Contour) { pub fn push_contour(&mut self, contour: Contour) {
if contour.is_empty() { if contour.is_empty() {
return; return;
@ -170,6 +191,7 @@ impl Outline {
self.contours.push(contour); self.contours.push(contour);
} }
/// Removes the last subpath from this outline and returns it.
pub fn pop_contour(&mut self) -> Option<Contour> { pub fn pop_contour(&mut self) -> Option<Contour> {
let last_contour = self.contours.pop(); let last_contour = self.contours.pop();
@ -182,6 +204,7 @@ impl Outline {
last_contour last_contour
} }
/// Applies an affine transform to this outline and all its subpaths.
pub fn transform(&mut self, transform: &Transform2F) { pub fn transform(&mut self, transform: &Transform2F) {
if transform.is_identity() { if transform.is_identity() {
return; return;
@ -195,11 +218,16 @@ impl Outline {
self.bounds = new_bounds.unwrap_or_else(|| RectF::default()); self.bounds = new_bounds.unwrap_or_else(|| RectF::default());
} }
/// Applies an affine transform to this outline and all its subpaths, consuming this outline
/// instead of mutating it.
pub fn transformed(mut self, transform: &Transform2F) -> Outline { pub fn transformed(mut self, transform: &Transform2F) -> Outline {
self.transform(transform); self.transform(transform);
self self
} }
/// Applies a perspective transform to this outline.
#[deprecated]
#[allow(deprecated)]
pub fn apply_perspective(&mut self, perspective: &Perspective) { pub fn apply_perspective(&mut self, perspective: &Perspective) {
let mut new_bounds = None; let mut new_bounds = None;
for contour in &mut self.contours { for contour in &mut self.contours {
@ -209,6 +237,9 @@ impl Outline {
self.bounds = new_bounds.unwrap_or_else(|| RectF::default()); self.bounds = new_bounds.unwrap_or_else(|| RectF::default());
} }
/// Thickens the outline by the given amount.
///
/// This is implemented by pushing vectors out along their normals.
pub fn dilate(&mut self, amount: Vector2F) { pub fn dilate(&mut self, amount: Vector2F) {
let orientation = Orientation::from_outline(self); let orientation = Orientation::from_outline(self);
self.contours self.contours
@ -217,6 +248,10 @@ impl Outline {
self.bounds = self.bounds.dilate(amount); self.bounds = self.bounds.dilate(amount);
} }
/// Returns true if this outline is obviously completely outside the closed polygon with the
/// given vertices, via a quick check.
///
/// Even if the outline is outside the polygon, this might return false.
pub fn is_outside_polygon(&self, clip_polygon: &[Vector2F]) -> bool { pub fn is_outside_polygon(&self, clip_polygon: &[Vector2F]) -> bool {
clip::rect_is_outside_polygon(self.bounds, clip_polygon) clip::rect_is_outside_polygon(self.bounds, clip_polygon)
} }
@ -225,6 +260,9 @@ impl Outline {
clip::rect_is_inside_polygon(self.bounds, clip_polygon) clip::rect_is_inside_polygon(self.bounds, clip_polygon)
} }
/// Clips this outline against the given closed polygon with the given vertices.
///
/// This is implemented with Sutherland-Hodgman clipping.
pub fn clip_against_polygon(&mut self, clip_polygon: &[Vector2F]) { pub fn clip_against_polygon(&mut self, clip_polygon: &[Vector2F]) {
// Quick check. // Quick check.
if self.is_inside_polygon(clip_polygon) { if self.is_inside_polygon(clip_polygon) {
@ -236,11 +274,13 @@ impl Outline {
} }
} }
/// Marks all contours as closed.
#[inline] #[inline]
pub fn close_all_contours(&mut self) { pub fn close_all_contours(&mut self) {
self.contours.iter_mut().for_each(|contour| contour.close()); self.contours.iter_mut().for_each(|contour| contour.close());
} }
/// Returns true if this outline has no points.
#[inline] #[inline]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.contours.iter().all(Contour::is_empty) self.contours.iter().all(Contour::is_empty)
@ -252,7 +292,7 @@ impl Outline {
self.contours.len() self.contours.len()
} }
/// Appends the contours in another outline to this one. /// Appends the contours of another outline to this one.
pub fn push_outline(&mut self, other: Outline) { pub fn push_outline(&mut self, other: Outline) {
if other.is_empty() { if other.is_empty() {
return; return;
@ -281,6 +321,7 @@ impl Debug for Outline {
} }
impl Contour { impl Contour {
/// Creates a new empty unclosed subpath.
#[inline] #[inline]
pub fn new() -> Contour { pub fn new() -> Contour {
Contour { Contour {
@ -291,6 +332,8 @@ impl Contour {
} }
} }
/// Creates a new empty unclosed subpath with space preallocated for the given number of
/// points.
#[inline] #[inline]
pub fn with_capacity(length: usize) -> Contour { pub fn with_capacity(length: usize) -> Contour {
Contour { Contour {
@ -301,6 +344,7 @@ impl Contour {
} }
} }
/// Creates a closed subpath representing the given axis-aligned rectangle.
#[inline] #[inline]
pub fn from_rect(rect: RectF) -> Contour { pub fn from_rect(rect: RectF) -> Contour {
let mut contour = Contour::with_capacity(4); let mut contour = Contour::with_capacity(4);
@ -313,6 +357,7 @@ impl Contour {
contour contour
} }
/// Creates a closed subpath representing the given axis-aligned rounded rectangle.
#[inline] #[inline]
pub fn from_rect_rounded(rect: RectF, radius: Vector2F) -> Contour { pub fn from_rect_rounded(rect: RectF, radius: Vector2F) -> Contour {
use std::f32::consts::SQRT_2; use std::f32::consts::SQRT_2;
@ -397,7 +442,8 @@ impl Contour {
) )
} }
/// restore self to the state of Contour::new(), but keep the points buffer allocated /// Restores this contour to the state of `Contour::new()` but keeps the points buffer
/// allocated.
#[inline] #[inline]
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.points.clear(); self.points.clear();
@ -406,6 +452,7 @@ impl Contour {
self.closed = false; self.closed = false;
} }
/// Returns an iterator over the segments in this contour.
#[inline] #[inline]
pub fn iter(&self, flags: ContourIterFlags) -> ContourIter { pub fn iter(&self, flags: ContourIterFlags) -> ContourIter {
ContourIter { ContourIter {
@ -415,36 +462,46 @@ impl Contour {
} }
} }
/// Returns true if this contour has no points.
#[inline] #[inline]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.points.is_empty() self.points.is_empty()
} }
/// Returns the number of points (including on-curve and control points) in this contour.
#[inline] #[inline]
pub fn len(&self) -> u32 { pub fn len(&self) -> u32 {
self.points.len() as u32 self.points.len() as u32
} }
/// Returns the dimensions of an axis-aligned rectangle that encloses this contour.
#[inline] #[inline]
pub fn bounds(&self) -> RectF { pub fn bounds(&self) -> RectF {
self.bounds self.bounds
} }
/// Returns true if this contour is closed.
#[inline] #[inline]
pub fn is_closed(&self) -> bool { pub fn is_closed(&self) -> bool {
self.closed self.closed
} }
/// Returns the position of the point (which can be an on-curve point or a control point) with
/// the given index.
///
/// Panics if the index is out of bounds.
#[inline] #[inline]
pub fn position_of(&self, index: u32) -> Vector2F { pub fn position_of(&self, index: u32) -> Vector2F {
self.points[index as usize] self.points[index as usize]
} }
/// Returns the position of the first point in this subpath.
#[inline] #[inline]
pub fn first_position(&self) -> Option<Vector2F> { pub fn first_position(&self) -> Option<Vector2F> {
self.points.first().cloned() self.points.first().cloned()
} }
/// Returns the position of the last point in this subpath.
#[inline] #[inline]
pub fn last_position(&self) -> Option<Vector2F> { pub fn last_position(&self) -> Option<Vector2F> {
self.points.last().cloned() self.points.last().cloned()
@ -455,29 +512,39 @@ impl Contour {
self.points[self.points.len() - index as usize] self.points[self.points.len() - index as usize]
} }
/// Returns a set of flags that describes the type of the point with the given index.
///
/// Panics if the index is out of range.
#[inline] #[inline]
pub fn flags_of(&self, index: u32) -> PointFlags { pub fn flags_of(&self, index: u32) -> PointFlags {
self.flags[index as usize] self.flags[index as usize]
} }
/// Adds a new on-curve point at the given position to this contour.
#[inline] #[inline]
pub fn push_endpoint(&mut self, point: Vector2F) { pub fn push_endpoint(&mut self, to: Vector2F) {
self.push_point(point, PointFlags::empty(), true); self.push_point(to, PointFlags::empty(), true);
} }
/// Adds a new quadratic Bézier curve to the given on-curve position and control point to this
/// contour.
#[inline] #[inline]
pub fn push_quadratic(&mut self, ctrl: Vector2F, point: Vector2F) { pub fn push_quadratic(&mut self, ctrl: Vector2F, to: Vector2F) {
self.push_point(ctrl, PointFlags::CONTROL_POINT_0, true); self.push_point(ctrl, PointFlags::CONTROL_POINT_0, true);
self.push_point(point, PointFlags::empty(), true); self.push_point(to, PointFlags::empty(), true);
} }
/// Adds a new cubic Bézier curve to the given on-curve position and control points to this
/// contour.
#[inline] #[inline]
pub fn push_cubic(&mut self, ctrl0: Vector2F, ctrl1: Vector2F, point: Vector2F) { pub fn push_cubic(&mut self, ctrl0: Vector2F, ctrl1: Vector2F, to: Vector2F) {
self.push_point(ctrl0, PointFlags::CONTROL_POINT_0, true); self.push_point(ctrl0, PointFlags::CONTROL_POINT_0, true);
self.push_point(ctrl1, PointFlags::CONTROL_POINT_1, true); self.push_point(ctrl1, PointFlags::CONTROL_POINT_1, true);
self.push_point(point, PointFlags::empty(), true); self.push_point(to, PointFlags::empty(), true);
} }
/// Marks this contour as closed, which results in an implicit line from the end back to the
/// starting point.
#[inline] #[inline]
pub fn close(&mut self) { pub fn close(&mut self) {
self.closed = true; self.closed = true;
@ -526,6 +593,19 @@ impl Contour {
self.push_point(segment.baseline.to(), PointFlags::empty(), update_bounds); self.push_point(segment.baseline.to(), PointFlags::empty(), update_bounds);
} }
/// Adds Bézier curves approximating a possibly-transformed unit arc to this contour.
///
/// Arguments:
///
/// * `transform`: An affine transform to apply to the unit arc. This can be used to reposition
/// and resize the arc.
///
/// * `start_angle`: The starting angle in radians. 0 represents the +x axis.
///
/// * `end_angle`: The ending angle in radians. 0 represents the +x axis.
///
/// * `direction`: Whether the arc should be drawn clockwise or counterclockwise from the +x
/// axis.
pub fn push_arc(&mut self, pub fn push_arc(&mut self,
transform: &Transform2F, transform: &Transform2F,
start_angle: f32, start_angle: f32,
@ -540,6 +620,8 @@ impl Contour {
} }
} }
/// Given the endpoints of a unit arc, adds Bézier curves to approximate that arc to the
/// current contour. The given transform is applied to the resulting arc.
pub fn push_arc_from_unit_chord(&mut self, pub fn push_arc_from_unit_chord(&mut self,
transform: &Transform2F, transform: &Transform2F,
mut chord: LineSegment2F, mut chord: LineSegment2F,
@ -590,12 +672,17 @@ impl Contour {
const EPSILON: f32 = 0.001; const EPSILON: f32 = 0.001;
} }
/// Push a SVG arc /// Adds an arc specified in SVG form to the current contour.
/// ///
/// Draws an ellipse section with radii given in `radius` rotated by `x_axis_rotation` to 'to' in the given `direction`. /// Draws an ellipse section with radii given by `radius` rotated by `x_axis_rotation` in
/// If `large_arc` is true, draws an arc bigger than a 180°, otherwise smaller than 180°. /// radians to `to` in the given direction. If `large_arc` is true, draws an arc bigger than
/// note that `x_axis_rotation` is in radians. /// π radians, otherwise smaller than π radians.
pub fn push_svg_arc(&mut self, radius: Vector2F, x_axis_rotation: f32, large_arc: bool, direction: ArcDirection, to: Vector2F) { pub fn push_svg_arc(&mut self,
radius: Vector2F,
x_axis_rotation: f32,
large_arc: bool,
direction: ArcDirection,
to: Vector2F) {
let r = radius; let r = radius;
let p = to; let p = to;
let last = self.last_position().unwrap_or_default(); let last = self.last_position().unwrap_or_default();
@ -648,6 +735,9 @@ impl Contour {
} }
} }
/// Adds an unit circle to this contour, transformed with the given transform.
///
/// Non-uniform scales can be used to transform this circle into an ellipse.
pub fn push_ellipse(&mut self, transform: &Transform2F) { pub fn push_ellipse(&mut self, transform: &Transform2F) {
let segment = Segment::quarter_circle_arc(); let segment = Segment::quarter_circle_arc();
let mut rotation; let mut rotation;
@ -664,6 +754,11 @@ impl Contour {
PushSegmentFlags::UPDATE_BOUNDS); PushSegmentFlags::UPDATE_BOUNDS);
} }
/// Returns the segment starting at the point with the given index.
///
/// The index must represent an on-curve point.
///
/// Panics if `point_index` is out of range.
#[inline] #[inline]
pub fn segment_after(&self, point_index: u32) -> Segment { pub fn segment_after(&self, point_index: u32) -> Segment {
debug_assert!(self.point_is_endpoint(point_index)); debug_assert!(self.point_is_endpoint(point_index));
@ -694,6 +789,10 @@ impl Contour {
segment segment
} }
/// Returns a line segment from the point with the given index to the next point, whether
/// on-curve or off-curve.
///
/// Panics if `prev_point_index` is not in range.
#[inline] #[inline]
pub fn hull_segment_after(&self, prev_point_index: u32) -> LineSegment2F { pub fn hull_segment_after(&self, prev_point_index: u32) -> LineSegment2F {
let next_point_index = self.next_point_index_of(prev_point_index); let next_point_index = self.next_point_index_of(prev_point_index);
@ -703,12 +802,14 @@ impl Contour {
) )
} }
/// Returns true if the given point is on-curve or false if it is off-curve.
#[inline] #[inline]
pub fn point_is_endpoint(&self, point_index: u32) -> bool { pub fn point_is_endpoint(&self, point_index: u32) -> bool {
!self.flags[point_index as usize] !self.flags[point_index as usize]
.intersects(PointFlags::CONTROL_POINT_0 | PointFlags::CONTROL_POINT_1) .intersects(PointFlags::CONTROL_POINT_0 | PointFlags::CONTROL_POINT_1)
} }
/// Returns `point_index + addend` modulo the number of points in this contour.
#[inline] #[inline]
pub fn add_to_point_index(&self, point_index: u32, addend: u32) -> u32 { pub fn add_to_point_index(&self, point_index: u32, addend: u32) -> u32 {
let (index, limit) = (point_index + addend, self.len()); let (index, limit) = (point_index + addend, self.len());
@ -719,12 +820,10 @@ impl Contour {
} }
} }
#[inline] /// Returns the first on-curve point strictly before the point with the given index.
pub fn point_is_logically_above(&self, a: u32, b: u32) -> bool { ///
let (a_y, b_y) = (self.points[a as usize].y(), self.points[b as usize].y()); /// This takes closed paths into account, so the returned index might be greater than
a_y < b_y || (a_y == b_y && a < b) /// `point_index`.
}
#[inline] #[inline]
pub fn prev_endpoint_index_of(&self, mut point_index: u32) -> u32 { pub fn prev_endpoint_index_of(&self, mut point_index: u32) -> u32 {
loop { loop {
@ -735,6 +834,10 @@ impl Contour {
} }
} }
/// Returns the first on-curve point strictly after the point with the given index.
///
/// This takes closed paths into account, so the returned index might be less than
/// `point_index`.
#[inline] #[inline]
pub fn next_endpoint_index_of(&self, mut point_index: u32) -> u32 { pub fn next_endpoint_index_of(&self, mut point_index: u32) -> u32 {
loop { loop {
@ -745,6 +848,10 @@ impl Contour {
} }
} }
/// Returns the index of the point before the given `point_index`.
///
/// If the index of the first point is passed in, then this returns the index of the last
/// point.
#[inline] #[inline]
pub fn prev_point_index_of(&self, point_index: u32) -> u32 { pub fn prev_point_index_of(&self, point_index: u32) -> u32 {
if point_index == 0 { if point_index == 0 {
@ -754,6 +861,10 @@ impl Contour {
} }
} }
/// Returns the index of the point after the given `point_index`.
///
/// If the index of the last point is passed in, then this returns the index of the first
/// point.
#[inline] #[inline]
pub fn next_point_index_of(&self, point_index: u32) -> u32 { pub fn next_point_index_of(&self, point_index: u32) -> u32 {
if point_index == self.len() - 1 { if point_index == self.len() - 1 {
@ -763,6 +874,7 @@ impl Contour {
} }
} }
/// Applies the given affine transform to this subpath.
pub fn transform(&mut self, transform: &Transform2F) { pub fn transform(&mut self, transform: &Transform2F) {
if transform.is_identity() { if transform.is_identity() {
return; return;
@ -774,12 +886,16 @@ impl Contour {
} }
} }
/// Applies the given affine transform to this contour, returning a new contour instead of
/// mutating this one.
#[inline] #[inline]
pub fn transformed(mut self, transform: &Transform2F) -> Contour { pub fn transformed(mut self, transform: &Transform2F) -> Contour {
self.transform(transform); self.transform(transform);
self self
} }
/// Applies a perspective transform to this subpath.
#[deprecated]
pub fn apply_perspective(&mut self, perspective: &Perspective) { pub fn apply_perspective(&mut self, perspective: &Perspective) {
for (point_index, point) in self.points.iter_mut().enumerate() { for (point_index, point) in self.points.iter_mut().enumerate() {
*point = *perspective * *point; *point = *perspective * *point;
@ -787,6 +903,8 @@ impl Contour {
} }
} }
/// Thickens the outline by the given amount. The `orientation` parameter specifies the winding
/// of the path (clockwise or counterclockwise) and is necessary to avoid flipped normals.
pub fn dilate(&mut self, amount: Vector2F, orientation: Orientation) { pub fn dilate(&mut self, amount: Vector2F, orientation: Orientation) {
ContourDilator::new(self, amount, orientation).dilate(); ContourDilator::new(self, amount, orientation).dilate();
self.bounds = self.bounds.dilate(amount); self.bounds = self.bounds.dilate(amount);
@ -858,10 +976,14 @@ impl Debug for Contour {
} }
} }
/// The index of a point within an outline, either on-curve or off-curve.
///
/// This packs a contour index with a point index into a single 32-bit value.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
pub struct PointIndex(u32); pub struct PointIndex(u32);
impl PointIndex { impl PointIndex {
/// Packs a contour index and the index of a point within that contour into a single value.
#[inline] #[inline]
pub fn new(contour: u32, point: u32) -> PointIndex { pub fn new(contour: u32, point: u32) -> PointIndex {
debug_assert!(contour <= 0xfff); debug_assert!(contour <= 0xfff);
@ -869,17 +991,20 @@ impl PointIndex {
PointIndex((contour << 20) | point) PointIndex((contour << 20) | point)
} }
/// Extracts the index of the contour and returns it.
#[inline] #[inline]
pub fn contour(self) -> u32 { pub fn contour(self) -> u32 {
self.0 >> 20 self.0 >> 20
} }
/// Extracts the index of the point within that contour and returns it.
#[inline] #[inline]
pub fn point(self) -> u32 { pub fn point(self) -> u32 {
self.0 & 0x000f_ffff self.0 & 0x000f_ffff
} }
} }
/// Iterates over all Bézier segments within a contour.
pub struct ContourIter<'a> { pub struct ContourIter<'a> {
contour: &'a Contour, contour: &'a Contour,
index: u32, index: u32,
@ -933,14 +1058,20 @@ impl<'a> Iterator for ContourIter<'a> {
} }
} }
/// The direction of an arc: clockwise or counterclockwise.
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub enum ArcDirection { pub enum ArcDirection {
/// Clockwise, starting from the +x axis.
CW, CW,
/// Counterclockwise, starting from the +x axis.
CCW, CCW,
} }
bitflags! { bitflags! {
/// Flags that control the behavior of `Contour::iter()`.
pub struct ContourIterFlags: u8 { pub struct ContourIterFlags: u8 {
/// Set to true to avoid iterating over the implicit line segment that joins the last point
/// to the first point for closed contours.
const IGNORE_CLOSE_SEGMENT = 1; const IGNORE_CLOSE_SEGMENT = 1;
} }
} }

View File

@ -221,6 +221,7 @@ impl Scene {
self.epoch.next(); self.epoch.next();
} }
#[allow(deprecated)]
pub(crate) fn apply_render_options(&self, pub(crate) fn apply_render_options(&self,
original_outline: &Outline, original_outline: &Outline,
options: &PreparedBuildOptions) options: &PreparedBuildOptions)