Skip to content

Commit

Permalink
Add support for the even-odd fill rule in the demo.
Browse files Browse the repository at this point in the history
  • Loading branch information
pcwalton committed Dec 21, 2017
1 parent 2deb4fa commit c2d89ab
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 22 deletions.
4 changes: 2 additions & 2 deletions demo/client/src/reference-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
20 changes: 17 additions & 3 deletions demo/client/src/svg-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -34,6 +34,8 @@ declare global {
}
}

type FillRule = 'evenodd' | 'winding';

export abstract class SVGPath {
element: SVGPathElement;
color: glmatrix.vec4;
Expand All @@ -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';
}
}

Expand Down Expand Up @@ -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);
}
}
Expand Down
71 changes: 54 additions & 17 deletions demo/server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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)]
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<u32>,
fill_rule: FillRule,
}

#[derive(Clone, Serialize, Deserialize)]
struct PartitionSvgPathCommand {
#[serde(rename = "type")]
Expand All @@ -207,12 +229,15 @@ struct PathPartitioningResult {
}

impl PathPartitioningResult {
fn compute(partitioner: &mut Partitioner, subpath_indices: &[Range<u32>])
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();
Expand Down Expand Up @@ -370,7 +395,7 @@ fn partition_font(request: Json<PartitionFontRequest>) -> Result<PartitionRespon

// Read glyph info.
let mut path_buffer = PathBuffer::new();
let subpath_indices: Vec<_> = 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();
Expand All @@ -384,22 +409,27 @@ fn partition_font(request: Json<PartitionFontRequest>) -> Result<PartitionRespon

let last_subpath_index = path_buffer.subpaths.len();

(first_subpath_index as u32)..(last_subpath_index as u32)
PathDescriptor {
subpath_indices: (first_subpath_index as u32)..(last_subpath_index as u32),
fill_rule: FillRule::Winding,
}
}).collect();

// Partition the decoded glyph outlines.
let mut library = MeshLibrary::new();
for (path_index, subpath_range) in subpath_indices.iter().enumerate() {
let stream = PathBufferStream::subpath_range(&path_buffer, (*subpath_range).clone());
for (path_index, path_descriptor) in path_descriptors.iter().enumerate() {
let stream = PathBufferStream::subpath_range(&path_buffer,
path_descriptor.subpath_indices.clone());
library.push_segments((path_index + 1) as u16, stream);
let stream = PathBufferStream::subpath_range(&path_buffer, (*subpath_range).clone());
let stream = PathBufferStream::subpath_range(&path_buffer,
path_descriptor.subpath_indices.clone());
library.push_normals(stream);
}

let mut partitioner = Partitioner::new(library);
partitioner.init_with_path_buffer(&path_buffer);
let path_partitioning_result = PathPartitioningResult::compute(&mut partitioner,
&subpath_indices);
&path_descriptors);

// Build the response.
let elapsed_ms = path_partitioning_result.elapsed_ms();
Expand Down Expand Up @@ -464,11 +494,13 @@ fn partition_svg_paths(request: Json<PartitionSvgPathsRequest>)
}
}

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();
Expand All @@ -477,13 +509,18 @@ fn partition_svg_paths(request: Json<PartitionSvgPathsRequest>)
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.
Expand Down

0 comments on commit c2d89ab

Please sign in to comment.