2017-08-10 18:26:27 -04:00
|
|
|
// pathfinder/demo/server/main.rs
|
|
|
|
//
|
2017-10-02 18:45:56 -04:00
|
|
|
// Copyright © 2017 The Pathfinder Project Developers.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// 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
|
2017-08-10 18:26:27 -04:00
|
|
|
|
|
|
|
#![feature(plugin)]
|
|
|
|
#![plugin(rocket_codegen)]
|
|
|
|
|
|
|
|
extern crate app_units;
|
|
|
|
extern crate base64;
|
2017-09-02 02:45:51 -04:00
|
|
|
extern crate env_logger;
|
2017-08-10 18:26:27 -04:00
|
|
|
extern crate euclid;
|
|
|
|
extern crate fontsan;
|
|
|
|
extern crate pathfinder_font_renderer;
|
|
|
|
extern crate pathfinder_partitioner;
|
2017-09-08 16:09:00 -04:00
|
|
|
extern crate pathfinder_path_utils;
|
2017-08-10 18:26:27 -04:00
|
|
|
extern crate rocket;
|
|
|
|
extern crate rocket_contrib;
|
|
|
|
|
|
|
|
#[macro_use]
|
|
|
|
extern crate serde_derive;
|
|
|
|
|
|
|
|
use app_units::Au;
|
2017-10-02 18:45:56 -04:00
|
|
|
use euclid::{Point2D, Transform2D};
|
2017-09-08 16:09:00 -04:00
|
|
|
use pathfinder_font_renderer::{FontContext, FontInstanceKey, FontKey, GlyphKey};
|
2017-10-02 18:50:19 -04:00
|
|
|
use pathfinder_partitioner::mesh_library::MeshLibrary;
|
2017-08-10 18:26:27 -04:00
|
|
|
use pathfinder_partitioner::partitioner::Partitioner;
|
2017-09-22 20:15:19 -04:00
|
|
|
use pathfinder_path_utils::cubic::CubicCurve;
|
2017-09-12 12:35:57 -04:00
|
|
|
use pathfinder_path_utils::monotonic::MonotonicPathSegmentStream;
|
2017-09-08 19:49:15 -04:00
|
|
|
use pathfinder_path_utils::stroke;
|
2017-09-12 12:35:57 -04:00
|
|
|
use pathfinder_path_utils::{PathBuffer, PathBufferStream, PathSegment, Transform2DPathStream};
|
2017-08-12 00:26:25 -04:00
|
|
|
use rocket::http::{ContentType, Status};
|
|
|
|
use rocket::request::Request;
|
2017-08-31 22:47:58 -04:00
|
|
|
use rocket::response::{NamedFile, Redirect, Responder, Response};
|
2017-08-10 18:26:27 -04:00
|
|
|
use rocket_contrib::json::Json;
|
2017-08-12 00:26:25 -04:00
|
|
|
use std::fs::File;
|
2017-10-02 18:17:21 -04:00
|
|
|
use std::io::{self, Cursor, Read};
|
2017-08-10 18:26:27 -04:00
|
|
|
use std::path::{Path, PathBuf};
|
2017-09-26 18:38:50 -04:00
|
|
|
use std::time::{Duration, Instant};
|
2017-08-28 19:47:27 -04:00
|
|
|
use std::u32;
|
2017-08-10 18:26:27 -04:00
|
|
|
|
2017-09-29 19:30:17 -04:00
|
|
|
const CUBIC_ERROR_TOLERANCE: f32 = 0.1;
|
|
|
|
|
2017-08-31 02:25:58 -04:00
|
|
|
static STATIC_INDEX_PATH: &'static str = "../client/index.html";
|
2017-08-29 21:57:43 -04:00
|
|
|
static STATIC_TEXT_DEMO_PATH: &'static str = "../client/text-demo.html";
|
|
|
|
static STATIC_SVG_DEMO_PATH: &'static str = "../client/svg-demo.html";
|
2017-08-29 22:46:18 -04:00
|
|
|
static STATIC_3D_DEMO_PATH: &'static str = "../client/3d-demo.html";
|
2017-09-11 14:22:19 -04:00
|
|
|
static STATIC_TOOLS_BENCHMARK_PATH: &'static str = "../client/benchmark.html";
|
2017-09-02 01:29:05 -04:00
|
|
|
static STATIC_TOOLS_MESH_DEBUGGER_PATH: &'static str = "../client/mesh-debugger.html";
|
2017-08-31 22:47:58 -04:00
|
|
|
static STATIC_DOC_API_PATH: &'static str = "../../font-renderer/target/doc";
|
2017-08-10 18:26:27 -04:00
|
|
|
static STATIC_CSS_BOOTSTRAP_PATH: &'static str = "../client/node_modules/bootstrap/dist/css";
|
2017-08-30 20:01:28 -04:00
|
|
|
static STATIC_CSS_OCTICONS_PATH: &'static str = "../client/node_modules/octicons/build";
|
2017-08-25 22:40:08 -04:00
|
|
|
static STATIC_CSS_PATHFINDER_PATH: &'static str = "../client/css/pathfinder.css";
|
2017-08-10 18:26:27 -04:00
|
|
|
static STATIC_JS_BOOTSTRAP_PATH: &'static str = "../client/node_modules/bootstrap/dist/js";
|
|
|
|
static STATIC_JS_JQUERY_PATH: &'static str = "../client/node_modules/jquery/dist";
|
2017-08-30 12:51:15 -04:00
|
|
|
static STATIC_JS_POPPER_JS_PATH: &'static str = "../client/node_modules/popper.js/dist/umd";
|
2017-08-25 23:20:45 -04:00
|
|
|
static STATIC_JS_PATHFINDER_PATH: &'static str = "../client";
|
2017-08-30 20:01:28 -04:00
|
|
|
static STATIC_SVG_OCTICONS_PATH: &'static str = "../client/node_modules/octicons/build/svg";
|
2017-09-28 18:23:52 -04:00
|
|
|
static STATIC_WOFF2_INTER_UI_PATH: &'static str = "../../resources/fonts/inter-ui";
|
2017-08-12 00:26:25 -04:00
|
|
|
static STATIC_GLSL_PATH: &'static str = "../../shaders";
|
2017-09-07 01:50:07 -04:00
|
|
|
static STATIC_DATA_PATH: &'static str = "../../resources/data";
|
2017-08-10 18:26:27 -04:00
|
|
|
|
2017-08-31 22:47:58 -04:00
|
|
|
static STATIC_DOC_API_INDEX_URI: &'static str = "/doc/api/pathfinder_font_renderer/index.html";
|
|
|
|
|
2017-09-28 18:23:52 -04:00
|
|
|
static BUILTIN_FONTS: [(&'static str, &'static str); 4] = [
|
2017-08-30 22:48:18 -04:00
|
|
|
("open-sans", "../../resources/fonts/open-sans/OpenSans-Regular.ttf"),
|
|
|
|
("nimbus-sans", "../../resources/fonts/nimbus-sans/NimbusSanL-Regu.ttf"),
|
|
|
|
("eb-garamond", "../../resources/fonts/eb-garamond/EBGaramond12-Regular.ttf"),
|
2017-09-28 18:23:52 -04:00
|
|
|
("inter-ui", "../../resources/fonts/inter-ui/Inter-UI-Regular.ttf"),
|
2017-08-30 22:48:18 -04:00
|
|
|
];
|
|
|
|
|
|
|
|
static BUILTIN_SVGS: [(&'static str, &'static str); 1] = [
|
|
|
|
("tiger", "../../resources/svg/Ghostscript_Tiger.svg"),
|
|
|
|
];
|
|
|
|
|
2017-08-28 19:47:27 -04:00
|
|
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
|
|
|
struct SubpathRange {
|
|
|
|
start: u32,
|
|
|
|
end: u32,
|
|
|
|
}
|
|
|
|
|
2017-08-10 18:26:27 -04:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
|
|
|
struct PartitionFontRequest {
|
2017-08-30 22:48:18 -04:00
|
|
|
face: PartitionFontRequestFace,
|
|
|
|
#[serde(rename = "fontIndex")]
|
|
|
|
font_index: u32,
|
2017-08-19 19:34:02 -04:00
|
|
|
glyphs: Vec<PartitionGlyph>,
|
2017-08-30 22:48:18 -04:00
|
|
|
#[serde(rename = "pointSize")]
|
|
|
|
point_size: f64,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
|
|
|
enum PartitionFontRequestFace {
|
|
|
|
/// One of the builtin fonts in `BUILTIN_FONTS`.
|
|
|
|
Builtin(String),
|
|
|
|
/// Base64-encoded OTF data.
|
|
|
|
Custom(String),
|
2017-08-10 18:26:27 -04:00
|
|
|
}
|
|
|
|
|
2017-08-19 19:34:02 -04:00
|
|
|
#[derive(Clone, Copy, Serialize, Deserialize)]
|
|
|
|
struct PartitionGlyph {
|
|
|
|
id: u32,
|
|
|
|
transform: Transform2D<f32>,
|
|
|
|
}
|
|
|
|
|
2017-08-10 18:26:27 -04:00
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
|
|
|
struct PartitionFontResponse {
|
2017-08-28 19:47:27 -04:00
|
|
|
#[serde(rename = "pathData")]
|
2017-10-02 18:17:21 -04:00
|
|
|
path_data: String,
|
2017-09-26 18:38:50 -04:00
|
|
|
time: f64,
|
2017-08-28 19:47:27 -04:00
|
|
|
}
|
|
|
|
|
2017-08-10 18:26:27 -04:00
|
|
|
#[derive(Clone, Copy, Serialize, Deserialize)]
|
|
|
|
enum PartitionFontError {
|
2017-08-30 22:48:18 -04:00
|
|
|
UnknownBuiltinFont,
|
2017-08-10 18:26:27 -04:00
|
|
|
Base64DecodingFailed,
|
|
|
|
FontSanitizationFailed,
|
|
|
|
FontLoadingFailed,
|
|
|
|
Unimplemented,
|
|
|
|
}
|
|
|
|
|
2017-08-28 19:47:27 -04:00
|
|
|
#[derive(Clone, Copy, Serialize, Deserialize)]
|
|
|
|
enum PartitionSvgPathsError {
|
|
|
|
UnknownSvgPathSegmentType,
|
|
|
|
Unimplemented,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
|
|
|
struct PartitionSvgPathsRequest {
|
|
|
|
paths: Vec<PartitionSvgPath>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
|
|
|
struct PartitionSvgPath {
|
|
|
|
segments: Vec<PartitionSvgPathSegment>,
|
2017-09-08 19:49:15 -04:00
|
|
|
kind: PartitionSvgPathKind,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Serialize, Deserialize)]
|
|
|
|
enum PartitionSvgPathKind {
|
|
|
|
Fill,
|
|
|
|
Stroke(f32),
|
2017-08-28 19:47:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
|
|
|
struct PartitionSvgPathSegment {
|
|
|
|
#[serde(rename = "type")]
|
|
|
|
kind: char,
|
|
|
|
values: Vec<f64>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Serialize, Deserialize)]
|
|
|
|
struct PartitionSvgPathsResponse {
|
|
|
|
#[serde(rename = "pathData")]
|
2017-10-02 18:17:21 -04:00
|
|
|
path_data: String,
|
2017-08-28 19:47:27 -04:00
|
|
|
}
|
|
|
|
|
2017-09-26 18:38:50 -04:00
|
|
|
struct PathPartitioningResult {
|
2017-10-02 18:17:21 -04:00
|
|
|
encoded_data: String,
|
2017-09-26 18:38:50 -04:00
|
|
|
time: Duration,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PathPartitioningResult {
|
|
|
|
fn compute(partitioner: &mut Partitioner, subpath_indices: &[SubpathRange])
|
|
|
|
-> PathPartitioningResult {
|
|
|
|
let timestamp_before = Instant::now();
|
|
|
|
|
2017-10-02 17:03:56 -04:00
|
|
|
partitioner.library_mut().clear();
|
2017-09-26 18:38:50 -04:00
|
|
|
|
|
|
|
for (path_index, subpath_range) in subpath_indices.iter().enumerate() {
|
2017-10-02 18:50:19 -04:00
|
|
|
partitioner.partition((path_index + 1) as u16, subpath_range.start, subpath_range.end);
|
2017-08-28 19:47:27 -04:00
|
|
|
}
|
|
|
|
|
2017-10-02 18:36:39 -04:00
|
|
|
partitioner.library_mut().optimize();
|
2017-09-26 18:38:50 -04:00
|
|
|
|
|
|
|
let time_elapsed = timestamp_before.elapsed();
|
|
|
|
|
2017-10-02 18:17:21 -04:00
|
|
|
let mut data_buffer = Cursor::new(vec![]);
|
|
|
|
drop(partitioner.library().serialize_into(&mut data_buffer));
|
|
|
|
let data_string = base64::encode(data_buffer.get_ref());
|
2017-08-28 19:47:27 -04:00
|
|
|
|
2017-09-26 18:38:50 -04:00
|
|
|
PathPartitioningResult {
|
2017-10-02 18:17:21 -04:00
|
|
|
encoded_data: data_string,
|
2017-09-26 18:38:50 -04:00
|
|
|
time: time_elapsed,
|
|
|
|
}
|
2017-09-06 21:28:23 -04:00
|
|
|
}
|
2017-08-28 19:47:27 -04:00
|
|
|
}
|
|
|
|
|
2017-08-10 18:26:27 -04:00
|
|
|
#[post("/partition-font", format = "application/json", data = "<request>")]
|
|
|
|
fn partition_font(request: Json<PartitionFontRequest>)
|
|
|
|
-> Json<Result<PartitionFontResponse, PartitionFontError>> {
|
2017-08-30 22:48:18 -04:00
|
|
|
// Fetch the OTF data.
|
|
|
|
let otf_data = match request.face {
|
|
|
|
PartitionFontRequestFace::Builtin(ref builtin_font_name) => {
|
|
|
|
// Read in the builtin font.
|
|
|
|
match BUILTIN_FONTS.iter().filter(|& &(name, _)| name == builtin_font_name).next() {
|
|
|
|
Some(&(_, path)) => {
|
|
|
|
let mut data = vec![];
|
|
|
|
File::open(path).expect("Couldn't find builtin font!")
|
|
|
|
.read_to_end(&mut data)
|
|
|
|
.expect("Couldn't read builtin font!");
|
|
|
|
data
|
|
|
|
}
|
|
|
|
None => return Json(Err(PartitionFontError::UnknownBuiltinFont)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PartitionFontRequestFace::Custom(ref encoded_data) => {
|
|
|
|
// Decode Base64-encoded OTF data.
|
|
|
|
let unsafe_otf_data = match base64::decode(encoded_data) {
|
|
|
|
Ok(unsafe_otf_data) => unsafe_otf_data,
|
|
|
|
Err(_) => return Json(Err(PartitionFontError::Base64DecodingFailed)),
|
|
|
|
};
|
|
|
|
|
|
|
|
// Sanitize.
|
|
|
|
match fontsan::process(&unsafe_otf_data) {
|
|
|
|
Ok(otf_data) => otf_data,
|
|
|
|
Err(_) => return Json(Err(PartitionFontError::FontSanitizationFailed)),
|
|
|
|
}
|
|
|
|
}
|
2017-08-10 18:26:27 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// Parse glyph data.
|
|
|
|
let font_key = FontKey::new();
|
|
|
|
let font_instance_key = FontInstanceKey {
|
|
|
|
font_key: font_key,
|
2017-08-30 22:48:18 -04:00
|
|
|
size: Au::from_f64_px(request.point_size),
|
2017-08-10 18:26:27 -04:00
|
|
|
};
|
|
|
|
let mut font_context = FontContext::new();
|
2017-08-30 22:48:18 -04:00
|
|
|
if font_context.add_font_from_memory(&font_key, otf_data, request.font_index).is_err() {
|
2017-08-10 18:26:27 -04:00
|
|
|
return Json(Err(PartitionFontError::FontLoadingFailed))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read glyph info.
|
2017-09-08 16:09:00 -04:00
|
|
|
let mut path_buffer = PathBuffer::new();
|
2017-08-28 19:47:27 -04:00
|
|
|
let subpath_indices: Vec<_> = request.glyphs.iter().map(|glyph| {
|
2017-08-19 19:34:02 -04:00
|
|
|
let glyph_key = GlyphKey::new(glyph.id);
|
2017-08-10 18:26:27 -04:00
|
|
|
|
2017-09-08 16:09:00 -04:00
|
|
|
let first_subpath_index = path_buffer.subpaths.len();
|
2017-08-10 18:26:27 -04:00
|
|
|
|
|
|
|
// This might fail; if so, just leave it blank.
|
2017-09-08 16:09:00 -04:00
|
|
|
if let Ok(glyph_outline) = font_context.glyph_outline(&font_instance_key, &glyph_key) {
|
2017-09-12 12:35:57 -04:00
|
|
|
let stream = Transform2DPathStream::new(glyph_outline, &glyph.transform);
|
|
|
|
let stream = MonotonicPathSegmentStream::new(stream);
|
|
|
|
path_buffer.add_stream(stream)
|
2017-09-08 16:09:00 -04:00
|
|
|
}
|
2017-08-10 18:26:27 -04:00
|
|
|
|
2017-09-08 16:09:00 -04:00
|
|
|
let last_subpath_index = path_buffer.subpaths.len();
|
2017-08-10 18:26:27 -04:00
|
|
|
|
2017-08-28 19:47:27 -04:00
|
|
|
SubpathRange {
|
|
|
|
start: first_subpath_index as u32,
|
|
|
|
end: last_subpath_index as u32,
|
2017-08-10 18:26:27 -04:00
|
|
|
}
|
|
|
|
}).collect();
|
|
|
|
|
|
|
|
// Partition the decoded glyph outlines.
|
2017-10-02 17:03:56 -04:00
|
|
|
let mut partitioner = Partitioner::new(MeshLibrary::new());
|
2017-09-08 16:09:00 -04:00
|
|
|
partitioner.init_with_path_buffer(&path_buffer);
|
2017-09-26 18:38:50 -04:00
|
|
|
let path_partitioning_result = PathPartitioningResult::compute(&mut partitioner,
|
|
|
|
&subpath_indices);
|
2017-08-19 19:34:02 -04:00
|
|
|
|
2017-09-26 18:38:50 -04:00
|
|
|
let time = path_partitioning_result.time.as_secs() as f64 +
|
|
|
|
path_partitioning_result.time.subsec_nanos() as f64 * 1e-9;
|
|
|
|
|
2017-08-10 18:26:27 -04:00
|
|
|
// Return the response.
|
|
|
|
Json(Ok(PartitionFontResponse {
|
2017-09-26 18:38:50 -04:00
|
|
|
path_data: path_partitioning_result.encoded_data,
|
|
|
|
time: time,
|
2017-08-28 19:47:27 -04:00
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[post("/partition-svg-paths", format = "application/json", data = "<request>")]
|
|
|
|
fn partition_svg_paths(request: Json<PartitionSvgPathsRequest>)
|
|
|
|
-> Json<Result<PartitionSvgPathsResponse, PartitionSvgPathsError>> {
|
|
|
|
// Parse the SVG path.
|
|
|
|
//
|
|
|
|
// The client has already normalized it, so we only have to handle `M`, `L`, `C`, and `Z`
|
|
|
|
// commands.
|
2017-09-08 16:09:00 -04:00
|
|
|
let mut path_buffer = PathBuffer::new();
|
2017-08-28 19:47:27 -04:00
|
|
|
let mut paths = vec![];
|
2017-09-22 20:15:19 -04:00
|
|
|
let mut last_point = Point2D::zero();
|
|
|
|
|
2017-08-28 19:47:27 -04:00
|
|
|
for path in &request.paths {
|
2017-09-08 19:49:15 -04:00
|
|
|
let mut stream = vec![];
|
|
|
|
|
2017-09-08 16:09:00 -04:00
|
|
|
let first_subpath_index = path_buffer.subpaths.len() as u32;
|
2017-08-28 19:47:27 -04:00
|
|
|
|
|
|
|
for segment in &path.segments {
|
|
|
|
match segment.kind {
|
|
|
|
'M' => {
|
2017-09-22 20:15:19 -04:00
|
|
|
last_point = Point2D::new(segment.values[0] as f32, segment.values[1] as f32);
|
|
|
|
stream.push(PathSegment::MoveTo(last_point))
|
2017-08-28 19:47:27 -04:00
|
|
|
}
|
|
|
|
'L' => {
|
2017-09-22 20:15:19 -04:00
|
|
|
last_point = Point2D::new(segment.values[0] as f32, segment.values[1] as f32);
|
|
|
|
stream.push(PathSegment::LineTo(last_point))
|
2017-08-28 19:47:27 -04:00
|
|
|
}
|
|
|
|
'C' => {
|
|
|
|
// FIXME(pcwalton): Do real cubic-to-quadratic conversion.
|
|
|
|
let control_point_0 = Point2D::new(segment.values[0] as f32,
|
|
|
|
segment.values[1] as f32);
|
|
|
|
let control_point_1 = Point2D::new(segment.values[2] as f32,
|
|
|
|
segment.values[3] as f32);
|
2017-09-22 20:15:19 -04:00
|
|
|
let endpoint_1 = Point2D::new(segment.values[4] as f32,
|
|
|
|
segment.values[5] as f32);
|
|
|
|
let cubic = CubicCurve::new(&last_point,
|
|
|
|
&control_point_0,
|
|
|
|
&control_point_1,
|
|
|
|
&endpoint_1);
|
|
|
|
last_point = endpoint_1;
|
2017-09-29 19:30:17 -04:00
|
|
|
stream.extend(cubic.approximate_curve(CUBIC_ERROR_TOLERANCE)
|
|
|
|
.map(|curve| curve.to_path_segment()));
|
2017-08-28 19:47:27 -04:00
|
|
|
}
|
2017-09-08 19:49:15 -04:00
|
|
|
'Z' => stream.push(PathSegment::ClosePath),
|
2017-08-28 19:47:27 -04:00
|
|
|
_ => return Json(Err(PartitionSvgPathsError::UnknownSvgPathSegmentType)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-08 19:49:15 -04:00
|
|
|
match path.kind {
|
2017-09-12 12:35:57 -04:00
|
|
|
PartitionSvgPathKind::Fill => {
|
|
|
|
path_buffer.add_stream(MonotonicPathSegmentStream::new(stream.into_iter()))
|
|
|
|
}
|
2017-09-08 19:49:15 -04:00
|
|
|
PartitionSvgPathKind::Stroke(stroke_width) => {
|
2017-09-12 12:35:57 -04:00
|
|
|
let mut temp_path_buffer = PathBuffer::new();
|
|
|
|
stroke::stroke(&mut temp_path_buffer, stream.into_iter(), stroke_width);
|
2017-09-22 16:40:41 -04:00
|
|
|
|
2017-09-12 12:35:57 -04:00
|
|
|
let stream = PathBufferStream::new(&temp_path_buffer);
|
|
|
|
let stream = MonotonicPathSegmentStream::new(stream);
|
|
|
|
path_buffer.add_stream(stream)
|
2017-09-08 19:49:15 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-08 16:09:00 -04:00
|
|
|
let last_subpath_index = path_buffer.subpaths.len() as u32;
|
2017-09-08 19:49:15 -04:00
|
|
|
|
2017-08-28 19:47:27 -04:00
|
|
|
paths.push(SubpathRange {
|
|
|
|
start: first_subpath_index,
|
|
|
|
end: last_subpath_index,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Partition the paths.
|
2017-10-02 17:03:56 -04:00
|
|
|
let mut partitioner = Partitioner::new(MeshLibrary::new());
|
2017-09-08 16:09:00 -04:00
|
|
|
partitioner.init_with_path_buffer(&path_buffer);
|
2017-09-26 18:38:50 -04:00
|
|
|
let path_partitioning_result = PathPartitioningResult::compute(&mut partitioner, &paths);
|
2017-08-28 19:47:27 -04:00
|
|
|
|
|
|
|
// Return the response.
|
|
|
|
Json(Ok(PartitionSvgPathsResponse {
|
2017-09-26 18:38:50 -04:00
|
|
|
path_data: path_partitioning_result.encoded_data,
|
2017-08-10 18:26:27 -04:00
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Static files
|
|
|
|
#[get("/")]
|
2017-08-31 02:25:58 -04:00
|
|
|
fn static_index() -> io::Result<NamedFile> {
|
|
|
|
NamedFile::open(STATIC_INDEX_PATH)
|
|
|
|
}
|
|
|
|
#[get("/demo/text")]
|
2017-08-30 22:48:18 -04:00
|
|
|
fn static_demo_text() -> io::Result<NamedFile> {
|
2017-08-25 22:40:08 -04:00
|
|
|
NamedFile::open(STATIC_TEXT_DEMO_PATH)
|
|
|
|
}
|
2017-08-29 21:57:43 -04:00
|
|
|
#[get("/demo/svg")]
|
2017-08-30 22:48:18 -04:00
|
|
|
fn static_demo_svg() -> io::Result<NamedFile> {
|
2017-08-25 22:40:08 -04:00
|
|
|
NamedFile::open(STATIC_SVG_DEMO_PATH)
|
2017-08-10 18:26:27 -04:00
|
|
|
}
|
2017-08-29 22:46:18 -04:00
|
|
|
#[get("/demo/3d")]
|
2017-08-30 22:48:18 -04:00
|
|
|
fn static_demo_3d() -> io::Result<NamedFile> {
|
2017-08-29 22:46:18 -04:00
|
|
|
NamedFile::open(STATIC_3D_DEMO_PATH)
|
|
|
|
}
|
2017-09-11 14:22:19 -04:00
|
|
|
#[get("/tools/benchmark")]
|
|
|
|
fn static_tools_benchmark() -> io::Result<NamedFile> {
|
|
|
|
NamedFile::open(STATIC_TOOLS_BENCHMARK_PATH)
|
|
|
|
}
|
2017-09-02 01:29:05 -04:00
|
|
|
#[get("/tools/mesh-debugger")]
|
|
|
|
fn static_tools_mesh_debugger() -> io::Result<NamedFile> {
|
|
|
|
NamedFile::open(STATIC_TOOLS_MESH_DEBUGGER_PATH)
|
2017-09-01 21:11:44 -04:00
|
|
|
}
|
2017-08-31 22:47:58 -04:00
|
|
|
#[get("/doc/api")]
|
|
|
|
fn static_doc_api_index() -> Redirect {
|
|
|
|
Redirect::to(STATIC_DOC_API_INDEX_URI)
|
|
|
|
}
|
|
|
|
#[get("/doc/api/<file..>")]
|
|
|
|
fn static_doc_api(file: PathBuf) -> Option<NamedFile> {
|
|
|
|
NamedFile::open(Path::new(STATIC_DOC_API_PATH).join(file)).ok()
|
|
|
|
}
|
2017-08-10 18:26:27 -04:00
|
|
|
#[get("/css/bootstrap/<file..>")]
|
|
|
|
fn static_css_bootstrap(file: PathBuf) -> Option<NamedFile> {
|
|
|
|
NamedFile::open(Path::new(STATIC_CSS_BOOTSTRAP_PATH).join(file)).ok()
|
|
|
|
}
|
2017-08-30 20:01:28 -04:00
|
|
|
#[get("/css/octicons/<file..>")]
|
|
|
|
fn static_css_octicons(file: PathBuf) -> Option<NamedFile> {
|
|
|
|
NamedFile::open(Path::new(STATIC_CSS_OCTICONS_PATH).join(file)).ok()
|
|
|
|
}
|
2017-08-25 22:40:08 -04:00
|
|
|
#[get("/css/pathfinder.css")]
|
|
|
|
fn static_css_pathfinder_css() -> io::Result<NamedFile> {
|
|
|
|
NamedFile::open(STATIC_CSS_PATHFINDER_PATH)
|
|
|
|
}
|
2017-08-10 18:26:27 -04:00
|
|
|
#[get("/js/bootstrap/<file..>")]
|
|
|
|
fn static_js_bootstrap(file: PathBuf) -> Option<NamedFile> {
|
|
|
|
NamedFile::open(Path::new(STATIC_JS_BOOTSTRAP_PATH).join(file)).ok()
|
|
|
|
}
|
|
|
|
#[get("/js/jquery/<file..>")]
|
|
|
|
fn static_js_jquery(file: PathBuf) -> Option<NamedFile> {
|
|
|
|
NamedFile::open(Path::new(STATIC_JS_JQUERY_PATH).join(file)).ok()
|
|
|
|
}
|
2017-08-30 12:51:15 -04:00
|
|
|
#[get("/js/popper.js/<file..>")]
|
|
|
|
fn static_js_popper_js(file: PathBuf) -> Option<NamedFile> {
|
|
|
|
NamedFile::open(Path::new(STATIC_JS_POPPER_JS_PATH).join(file)).ok()
|
|
|
|
}
|
2017-08-25 23:20:45 -04:00
|
|
|
#[get("/js/pathfinder/<file..>")]
|
|
|
|
fn static_js_pathfinder(file: PathBuf) -> Option<NamedFile> {
|
|
|
|
NamedFile::open(Path::new(STATIC_JS_PATHFINDER_PATH).join(file)).ok()
|
|
|
|
}
|
2017-08-30 20:01:28 -04:00
|
|
|
#[get("/svg/octicons/<file..>")]
|
|
|
|
fn static_svg_octicons(file: PathBuf) -> Option<NamedFile> {
|
|
|
|
NamedFile::open(Path::new(STATIC_SVG_OCTICONS_PATH).join(file)).ok()
|
|
|
|
}
|
2017-09-28 18:23:52 -04:00
|
|
|
#[get("/woff2/inter-ui/<file..>")]
|
|
|
|
fn static_woff2_inter_ui(file: PathBuf) -> Option<NamedFile> {
|
|
|
|
NamedFile::open(Path::new(STATIC_WOFF2_INTER_UI_PATH).join(file)).ok()
|
|
|
|
}
|
2017-08-12 00:26:25 -04:00
|
|
|
#[get("/glsl/<file..>")]
|
|
|
|
fn static_glsl(file: PathBuf) -> Option<Shader> {
|
|
|
|
Shader::open(Path::new(STATIC_GLSL_PATH).join(file)).ok()
|
|
|
|
}
|
2017-08-30 22:48:18 -04:00
|
|
|
#[get("/otf/demo/<font_name>")]
|
|
|
|
fn static_otf_demo(font_name: String) -> Option<NamedFile> {
|
|
|
|
BUILTIN_FONTS.iter()
|
|
|
|
.filter(|& &(name, _)| name == font_name)
|
|
|
|
.next()
|
|
|
|
.and_then(|&(_, path)| NamedFile::open(Path::new(path)).ok())
|
|
|
|
}
|
|
|
|
#[get("/svg/demo/<svg_name>")]
|
|
|
|
fn static_svg_demo(svg_name: String) -> Option<NamedFile> {
|
|
|
|
BUILTIN_SVGS.iter()
|
|
|
|
.filter(|& &(name, _)| name == svg_name)
|
|
|
|
.next()
|
|
|
|
.and_then(|&(_, path)| NamedFile::open(Path::new(path)).ok())
|
|
|
|
}
|
2017-09-07 01:50:07 -04:00
|
|
|
#[get("/data/<file..>")]
|
|
|
|
fn static_data(file: PathBuf) -> Option<NamedFile> {
|
|
|
|
NamedFile::open(Path::new(STATIC_DATA_PATH).join(file)).ok()
|
|
|
|
}
|
2017-08-12 00:26:25 -04:00
|
|
|
|
|
|
|
struct Shader {
|
|
|
|
file: File,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Shader {
|
|
|
|
fn open(path: PathBuf) -> io::Result<Shader> {
|
|
|
|
File::open(path).map(|file| Shader {
|
|
|
|
file: file,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Responder<'a> for Shader {
|
|
|
|
fn respond_to(self, _: &Request) -> Result<Response<'a>, Status> {
|
|
|
|
Response::build().header(ContentType::Plain).streamed_body(self.file).ok()
|
|
|
|
}
|
|
|
|
}
|
2017-08-10 18:26:27 -04:00
|
|
|
|
2017-08-09 18:36:41 -04:00
|
|
|
fn main() {
|
2017-09-02 02:45:51 -04:00
|
|
|
drop(env_logger::init());
|
|
|
|
|
2017-08-10 18:26:27 -04:00
|
|
|
rocket::ignite().mount("/", routes![
|
|
|
|
partition_font,
|
2017-08-28 19:47:27 -04:00
|
|
|
partition_svg_paths,
|
2017-08-31 02:25:58 -04:00
|
|
|
static_index,
|
2017-08-30 22:48:18 -04:00
|
|
|
static_demo_text,
|
|
|
|
static_demo_svg,
|
|
|
|
static_demo_3d,
|
2017-09-11 14:22:19 -04:00
|
|
|
static_tools_benchmark,
|
2017-09-02 01:29:05 -04:00
|
|
|
static_tools_mesh_debugger,
|
2017-08-31 22:47:58 -04:00
|
|
|
static_doc_api_index,
|
|
|
|
static_doc_api,
|
2017-08-10 18:26:27 -04:00
|
|
|
static_css_bootstrap,
|
2017-08-30 20:01:28 -04:00
|
|
|
static_css_octicons,
|
2017-08-25 22:40:08 -04:00
|
|
|
static_css_pathfinder_css,
|
2017-08-10 18:26:27 -04:00
|
|
|
static_js_bootstrap,
|
|
|
|
static_js_jquery,
|
2017-08-30 12:51:15 -04:00
|
|
|
static_js_popper_js,
|
2017-08-25 23:20:45 -04:00
|
|
|
static_js_pathfinder,
|
2017-08-30 20:01:28 -04:00
|
|
|
static_svg_octicons,
|
2017-09-28 18:23:52 -04:00
|
|
|
static_woff2_inter_ui,
|
2017-08-12 00:26:25 -04:00
|
|
|
static_glsl,
|
2017-08-30 22:48:18 -04:00
|
|
|
static_otf_demo,
|
|
|
|
static_svg_demo,
|
2017-09-07 01:50:07 -04:00
|
|
|
static_data,
|
2017-08-10 18:26:27 -04:00
|
|
|
]).launch();
|
2017-08-09 18:36:41 -04:00
|
|
|
}
|