From c2d89aba9189f7eeb8f9372e5949809020a0a60d Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 21 Dec 2017 13:53:38 -0800 Subject: [PATCH] Add support for the even-odd fill rule in the demo. Closes #59. --- demo/client/src/reference-test.ts | 4 +- demo/client/src/svg-loader.ts | 20 +++++++-- demo/server/src/main.rs | 71 +++++++++++++++++++++++-------- 3 files changed, 73 insertions(+), 22 deletions(-) diff --git a/demo/client/src/reference-test.ts b/demo/client/src/reference-test.ts index 269a21e6..9ae7c869 100644 --- a/demo/client/src/reference-test.ts +++ b/demo/client/src/reference-test.ts @@ -23,14 +23,14 @@ import {PathfinderMeshData} from './meshes'; import {PathTransformBuffers, Renderer} from "./renderer"; import {ShaderMap, ShaderProgramSource} from "./shader-loader"; import SSAAStrategy from './ssaa-strategy'; +import {BUILTIN_SVG_URI, SVGLoader} from './svg-loader'; +import {SVGRenderer} from './svg-renderer'; import {BUILTIN_FONT_URI, computeStemDarkeningAmount, ExpandedMeshData, GlyphStore} from "./text"; import {Hint} from "./text"; import {PathfinderFont, TextFrame, TextRun} from "./text"; import {unwrapNull} from "./utils"; import {DemoView} from "./view"; import {AdaptiveMonochromeXCAAStrategy} from './xcaa-strategy'; -import { SVGRenderer } from './svg-renderer'; -import { SVGLoader, BUILTIN_SVG_URI } from './svg-loader'; const FONT: string = 'open-sans'; const TEXT_COLOR: number[] = [0, 0, 0, 255]; diff --git a/demo/client/src/svg-loader.ts b/demo/client/src/svg-loader.ts index d8de7bab..9e9598be 100644 --- a/demo/client/src/svg-loader.ts +++ b/demo/client/src/svg-loader.ts @@ -15,7 +15,7 @@ import * as _ from 'lodash'; import 'path-data-polyfill.js'; import {parseServerTiming, PathfinderMeshData} from "./meshes"; import {AlphaMaskCompositingOperation, RenderTask, RenderTaskType} from './render-task'; -import {panic, Range, unwrapNull, unwrapUndef, lerp} from "./utils"; +import {lerp, panic, Range, unwrapNull, unwrapUndef} from "./utils"; export const BUILTIN_SVG_URI: string = "/svg/demo"; @@ -34,6 +34,8 @@ declare global { } } +type FillRule = 'evenodd' | 'winding'; + export abstract class SVGPath { element: SVGPathElement; color: glmatrix.vec4; @@ -47,8 +49,17 @@ export abstract class SVGPath { } export class SVGFill extends SVGPath { + fillRule: FillRule; + + get pathfinderFillRule(): string { + return { evenodd: 'EvenOdd', winding: 'Winding' }[this.fillRule]; + } + constructor(element: SVGPathElement) { super(element, 'fill'); + + const style = window.getComputedStyle(element); + this.fillRule = style.fillRule === 'evenodd' ? 'evenodd' : 'winding'; } } @@ -185,10 +196,13 @@ export class SVGLoader { glmatrix.vec2.max(svgTopRight, svgTopRight, topRight); if (instance instanceof SVGFill) { - this.paths.push({ segments: segments, kind: 'Fill' }); + this.paths.push({ + kind: { Fill: instance.pathfinderFillRule }, + segments: segments, + }); this.pathBounds.push(pathBounds); } else if (instance instanceof SVGStroke) { - this.paths.push({ segments: segments, kind: { Stroke: instance.width } }); + this.paths.push({ kind: { Stroke: instance.width }, segments: segments }); this.pathBounds.push(pathBounds); } } diff --git a/demo/server/src/main.rs b/demo/server/src/main.rs index c47a6bc6..848229c8 100644 --- a/demo/server/src/main.rs +++ b/demo/server/src/main.rs @@ -6,7 +6,7 @@ // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // , at your // option. This file may not be copied, modified, or distributed -// except according to those terms.// Copyright © 2017 Mozilla Foundation +// except according to those terms. #![feature(plugin)] #![plugin(rocket_codegen)] @@ -35,6 +35,7 @@ use image::{DynamicImage, ImageBuffer, ImageFormat, ImageRgba8}; use lru_cache::LruCache; use pathfinder_font_renderer::{FontContext, FontInstance, FontKey, GlyphImage}; use pathfinder_font_renderer::{GlyphKey, SubpixelOffset}; +use pathfinder_partitioner::FillRule; use pathfinder_partitioner::mesh_library::MeshLibrary; use pathfinder_partitioner::partitioner::Partitioner; use pathfinder_path_utils::cubic::CubicCurve; @@ -190,10 +191,31 @@ struct PartitionSvgPath { #[derive(Clone, Copy, Serialize, Deserialize)] enum PartitionSvgPathKind { - Fill, + Fill(PartitionSvgFillRule), Stroke(f32), } +#[derive(Clone, Copy, Serialize, Deserialize)] +enum PartitionSvgFillRule { + Winding, + EvenOdd, +} + +impl PartitionSvgFillRule { + fn to_fill_rule(self) -> FillRule { + match self { + PartitionSvgFillRule::Winding => FillRule::Winding, + PartitionSvgFillRule::EvenOdd => FillRule::EvenOdd, + } + } +} + +#[derive(Clone)] +struct PathDescriptor { + subpath_indices: Range, + fill_rule: FillRule, +} + #[derive(Clone, Serialize, Deserialize)] struct PartitionSvgPathCommand { #[serde(rename = "type")] @@ -207,12 +229,15 @@ struct PathPartitioningResult { } impl PathPartitioningResult { - fn compute(partitioner: &mut Partitioner, subpath_indices: &[Range]) + fn compute(partitioner: &mut Partitioner, path_descriptors: &[PathDescriptor]) -> PathPartitioningResult { let timestamp_before = Instant::now(); - for (path_index, subpath_range) in subpath_indices.iter().enumerate() { - partitioner.partition((path_index + 1) as u16, subpath_range.start, subpath_range.end); + for (path_index, path_descriptor) in path_descriptors.iter().enumerate() { + partitioner.set_fill_rule(path_descriptor.fill_rule); + partitioner.partition((path_index + 1) as u16, + path_descriptor.subpath_indices.start, + path_descriptor.subpath_indices.end); } partitioner.library_mut().optimize(); @@ -370,7 +395,7 @@ fn partition_font(request: Json) -> Result = request.glyphs.iter().map(|glyph| { + let path_descriptors: Vec<_> = request.glyphs.iter().map(|glyph| { let glyph_key = GlyphKey::new(glyph.id, SubpixelOffset(0)); let first_subpath_index = path_buffer.subpaths.len(); @@ -384,22 +409,27 @@ fn partition_font(request: Json) -> Result) } } - match path.kind { - PartitionSvgPathKind::Fill => { + let fill_rule = match path.kind { + PartitionSvgPathKind::Fill(fill_rule) => { let stream = MonotonicPathCommandStream::new(stream.into_iter()); library.push_segments((path_index + 1) as u16, stream.clone()); - path_buffer.add_stream(stream) + path_buffer.add_stream(stream); + + fill_rule.to_fill_rule() } PartitionSvgPathKind::Stroke(stroke_width) => { let mut temp_path_buffer = PathBuffer::new(); @@ -477,13 +509,18 @@ fn partition_svg_paths(request: Json) let stream = PathBufferStream::new(&temp_path_buffer); let stream = MonotonicPathCommandStream::new(stream); library.push_segments((path_index + 1) as u16, stream.clone()); - path_buffer.add_stream(stream) + path_buffer.add_stream(stream); + + FillRule::Winding } - } + }; let last_subpath_index = path_buffer.subpaths.len() as u32; - paths.push(first_subpath_index..last_subpath_index) + paths.push(PathDescriptor { + subpath_indices: first_subpath_index..last_subpath_index, + fill_rule: fill_rule, + }) } // Partition the paths.