Don't include the closing segment when printing a path as a string.
Closes #279. Closes #282.
This commit is contained in:
parent
6239356d89
commit
b6762cecb8
|
@ -44,6 +44,9 @@ const DEFAULT_FONT_SIZE: f32 = 10.0;
|
||||||
#[cfg_attr(not(feature = "pf-text"), path = "text_no_text.rs")]
|
#[cfg_attr(not(feature = "pf-text"), path = "text_no_text.rs")]
|
||||||
mod text;
|
mod text;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
pub struct CanvasRenderingContext2D {
|
pub struct CanvasRenderingContext2D {
|
||||||
scene: Scene,
|
scene: Scene,
|
||||||
current_state: State,
|
current_state: State,
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
// pathfinder/canvas/src/tests.rs
|
||||||
|
//
|
||||||
|
// For this file only, any copyright is dedicated to the Public Domain.
|
||||||
|
// https://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
|
||||||
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
|
use super::Path2D;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_path2d_formatting() {
|
||||||
|
let mut path = Path2D::new();
|
||||||
|
path.move_to(Vector2F::new(0.0, 1.0));
|
||||||
|
path.line_to(Vector2F::new(2.0, 3.0));
|
||||||
|
assert_eq!(format!("{:?}", path), "M 0 1 L 2 3");
|
||||||
|
path.line_to(Vector2F::new(4.0, 5.0));
|
||||||
|
assert_eq!(format!("{:?}", path), "M 0 1 L 2 3 L 4 5");
|
||||||
|
path.close_path();
|
||||||
|
assert_eq!(format!("{:?}", path), "M 0 1 L 2 3 L 4 5 z");
|
||||||
|
}
|
|
@ -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.
|
||||||
|
|
||||||
use crate::outline::{Contour, PointFlags, PushSegmentFlags};
|
use crate::outline::{Contour, ContourIterFlags, PointFlags, PushSegmentFlags};
|
||||||
use crate::segment::{CubicSegment, Segment};
|
use crate::segment::{CubicSegment, Segment};
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
|
@ -200,7 +200,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
let input = self.contour_mut().take();
|
let input = self.contour_mut().take();
|
||||||
for segment in input.iter() {
|
for segment in input.iter(ContourIterFlags::empty()) {
|
||||||
self.clip_segment_against(segment, &edge);
|
self.clip_segment_against(segment, &edge);
|
||||||
}
|
}
|
||||||
if input.is_closed() {
|
if input.is_closed() {
|
||||||
|
@ -266,7 +266,7 @@ where
|
||||||
|
|
||||||
fn check_for_fast_clip(&mut self, edge: &Self::Edge) -> FastClipResult {
|
fn check_for_fast_clip(&mut self, edge: &Self::Edge) -> FastClipResult {
|
||||||
let mut result = None;
|
let mut result = None;
|
||||||
for segment in self.contour_mut().iter() {
|
for segment in self.contour_mut().iter(ContourIterFlags::empty()) {
|
||||||
let location = edge.trivially_test_segment(&segment);
|
let location = edge.trivially_test_segment(&segment);
|
||||||
match (result, location) {
|
match (result, location) {
|
||||||
(None, EdgeRelativeLocation::Outside) => {
|
(None, EdgeRelativeLocation::Outside) => {
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
//! Line dashing support.
|
//! Line dashing support.
|
||||||
|
|
||||||
use crate::outline::{Contour, Outline, PushSegmentFlags};
|
use crate::outline::{Contour, ContourIterFlags, Outline, PushSegmentFlags};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
const EPSILON: f32 = 0.0001;
|
const EPSILON: f32 = 0.0001;
|
||||||
|
@ -54,7 +54,8 @@ impl<'a, 'b, 'c> ContourDash<'a, 'b, 'c> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dash(&mut self) {
|
fn dash(&mut self) {
|
||||||
let (mut iterator, mut queued_segment) = (self.input.iter(), None);
|
let mut iterator = self.input.iter(ContourIterFlags::empty());
|
||||||
|
let mut queued_segment = None;
|
||||||
loop {
|
loop {
|
||||||
if queued_segment.is_none() {
|
if queued_segment.is_none() {
|
||||||
match iterator.next() {
|
match iterator.next() {
|
||||||
|
|
|
@ -282,10 +282,11 @@ impl Contour {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter(&self) -> ContourIter {
|
pub fn iter(&self, flags: ContourIterFlags) -> ContourIter {
|
||||||
ContourIter {
|
ContourIter {
|
||||||
contour: self,
|
contour: self,
|
||||||
index: 1,
|
index: 1,
|
||||||
|
flags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -743,7 +744,8 @@ impl Contour {
|
||||||
|
|
||||||
impl Debug for Contour {
|
impl Debug for Contour {
|
||||||
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||||
for (segment_index, segment) in self.iter().enumerate() {
|
for (segment_index, segment) in self.iter(ContourIterFlags::IGNORE_CLOSE_SEGMENT)
|
||||||
|
.enumerate() {
|
||||||
if segment_index == 0 {
|
if segment_index == 0 {
|
||||||
write!(
|
write!(
|
||||||
formatter,
|
formatter,
|
||||||
|
@ -821,6 +823,7 @@ impl PointIndex {
|
||||||
pub struct ContourIter<'a> {
|
pub struct ContourIter<'a> {
|
||||||
contour: &'a Contour,
|
contour: &'a Contour,
|
||||||
index: u32,
|
index: u32,
|
||||||
|
flags: ContourIterFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for ContourIter<'a> {
|
impl<'a> Iterator for ContourIter<'a> {
|
||||||
|
@ -829,8 +832,11 @@ impl<'a> Iterator for ContourIter<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<Segment> {
|
fn next(&mut self) -> Option<Segment> {
|
||||||
let contour = self.contour;
|
let contour = self.contour;
|
||||||
if (self.index == contour.len() && !self.contour.closed) || self.index == contour.len() + 1
|
|
||||||
{
|
let include_close_segment = self.contour.closed &&
|
||||||
|
!self.flags.contains(ContourIterFlags::IGNORE_CLOSE_SEGMENT);
|
||||||
|
if (self.index == contour.len() && !include_close_segment) ||
|
||||||
|
self.index == contour.len() + 1 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -873,6 +879,12 @@ pub enum ArcDirection {
|
||||||
CCW,
|
CCW,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub struct ContourIterFlags: u8 {
|
||||||
|
const IGNORE_CLOSE_SEGMENT = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn union_rect(bounds: &mut RectF, new_point: Vector2F, first: bool) {
|
pub(crate) fn union_rect(bounds: &mut RectF, new_point: Vector2F, first: bool) {
|
||||||
if first {
|
if first {
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
//! Utilities for converting path strokes to fills.
|
//! Utilities for converting path strokes to fills.
|
||||||
|
|
||||||
use crate::outline::{ArcDirection, Contour, Outline, PushSegmentFlags};
|
use crate::outline::{ArcDirection, Contour, ContourIterFlags, Outline, PushSegmentFlags};
|
||||||
use crate::segment::Segment;
|
use crate::segment::Segment;
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
|
@ -161,7 +161,7 @@ impl<'a> ContourStrokeToFill<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn offset_forward(&mut self) {
|
fn offset_forward(&mut self) {
|
||||||
for (segment_index, segment) in self.input.iter().enumerate() {
|
for (segment_index, segment) in self.input.iter(ContourIterFlags::empty()).enumerate() {
|
||||||
// FIXME(pcwalton): We negate the radius here so that round end caps can be drawn
|
// FIXME(pcwalton): We negate the radius here so that round end caps can be drawn
|
||||||
// clockwise. Of course, we should just implement anticlockwise arcs to begin with...
|
// clockwise. Of course, we should just implement anticlockwise arcs to begin with...
|
||||||
let join = if segment_index == 0 { LineJoin::Bevel } else { self.join };
|
let join = if segment_index == 0 { LineJoin::Bevel } else { self.join };
|
||||||
|
@ -172,7 +172,7 @@ impl<'a> ContourStrokeToFill<'a> {
|
||||||
fn offset_backward(&mut self) {
|
fn offset_backward(&mut self) {
|
||||||
let mut segments: Vec<_> = self
|
let mut segments: Vec<_> = self
|
||||||
.input
|
.input
|
||||||
.iter()
|
.iter(ContourIterFlags::empty())
|
||||||
.map(|segment| segment.reversed())
|
.map(|segment| segment.reversed())
|
||||||
.collect();
|
.collect();
|
||||||
segments.reverse();
|
segments.reverse();
|
||||||
|
|
|
@ -8,6 +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.
|
||||||
|
|
||||||
|
use pathfinder_content::outline::ContourIterFlags;
|
||||||
use pathfinder_content::segment::SegmentKind;
|
use pathfinder_content::segment::SegmentKind;
|
||||||
use pathfinder_renderer::paint::Paint;
|
use pathfinder_renderer::paint::Paint;
|
||||||
use pathfinder_renderer::scene::Scene;
|
use pathfinder_renderer::scene::Scene;
|
||||||
|
@ -87,7 +88,7 @@ fn export_pdf<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
for contour in outline.contours() {
|
for contour in outline.contours() {
|
||||||
for (segment_index, segment) in contour.iter().enumerate() {
|
for (segment_index, segment) in contour.iter(ContourIterFlags::empty()).enumerate() {
|
||||||
if segment_index == 0 {
|
if segment_index == 0 {
|
||||||
pdf.move_to(tr(segment.baseline.from()));
|
pdf.move_to(tr(segment.baseline.from()));
|
||||||
}
|
}
|
||||||
|
@ -103,7 +104,11 @@ fn export_pdf<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
||||||
let c2 = Vector2F::splat(2./3.) * c + Vector2F::splat(1./3.) * p;
|
let c2 = Vector2F::splat(2./3.) * c + Vector2F::splat(1./3.) * p;
|
||||||
pdf.cubic_to(c1, c2, p);
|
pdf.cubic_to(c1, c2, p);
|
||||||
}
|
}
|
||||||
SegmentKind::Cubic => pdf.cubic_to(tr(segment.ctrl.from()), tr(segment.ctrl.to()), tr(segment.baseline.to()))
|
SegmentKind::Cubic => {
|
||||||
|
pdf.cubic_to(tr(segment.ctrl.from()),
|
||||||
|
tr(segment.ctrl.to()),
|
||||||
|
tr(segment.baseline.to()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +152,7 @@ fn export_ps<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
for contour in outline.contours() {
|
for contour in outline.contours() {
|
||||||
for (segment_index, segment) in contour.iter().enumerate() {
|
for (segment_index, segment) in contour.iter(ContourIterFlags::empty()).enumerate() {
|
||||||
if segment_index == 0 {
|
if segment_index == 0 {
|
||||||
writeln!(writer, "{} moveto", P(segment.baseline.from()))?;
|
writeln!(writer, "{} moveto", P(segment.baseline.from()))?;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue