diff --git a/demo/client/package.json b/demo/client/package.json index a8b7a9c0..2131b2bf 100644 --- a/demo/client/package.json +++ b/demo/client/package.json @@ -10,6 +10,7 @@ "license": "MIT OR Apache-2.0", "dependencies": { "@types/node": "^8.0.19", + "base64-js": "^1.2.1", "bootstrap": "^4.0.0-alpha.6", "opentype.js": "^0.7.3", "ts-loader": "^2.3.2", diff --git a/demo/client/src/index.ts b/demo/client/src/index.ts index 22f54490..0bded376 100644 --- a/demo/client/src/index.ts +++ b/demo/client/src/index.ts @@ -1,11 +1,30 @@ // pathfinder/demo/src/index.ts +const base64js = require('base64-js'); const opentype = require('opentype.js'); -class AppController { - constructor() { +const TEXT: string = "A"; +const FONT_SIZE: number = 16.0; + +const PARTITION_FONT_ENDPOINT_URL: string = "/partition-font"; + +class PathfinderMeshes { + constructor(encodedResponse: string) { + const response = JSON.parse(encodedResponse); + if (!('Ok' in response)) + throw new Error("Failed to partition the font!"); + const meshes = response.Ok; + this.bQuads = base64js.toByteArray(meshes.bQuads); + this.bVertices = base64js.toByteArray(meshes.bVertices); } + bQuads: ArrayBuffer; + bVertices: ArrayBuffer; +} + +class AppController { + constructor() {} + start() { this.view = new PathfinderView(document.getElementById('pf-canvas') as HTMLCanvasElement); @@ -15,16 +34,49 @@ class AppController { loadFont() { const file = this.loadFontButton.files[0]; - const fileURL = window.URL.createObjectURL(file); - opentype.load(fileURL, (err, font) => this.fontLoaded(font)); + const reader = new FileReader; + reader.addEventListener('loadend', () => { + this.fontData = reader.result; + this.fontLoaded(); + }, false); + reader.readAsArrayBuffer(file); } - fontLoaded(font) { + fontLoaded() { + this.font = opentype.parse(this.fontData); + if (!this.font.supported) { + window.alert("The font type is unsupported."); + return; + } + + const glyphIDs = this.font.stringToGlyphs(TEXT).map(glyph => glyph.index); + + const request = { + otf: base64js.fromByteArray(new Uint8Array(this.fontData)), + fontIndex: 0, + glyphIDs: glyphIDs, + pointSize: FONT_SIZE, + }; + + const xhr = new XMLHttpRequest(); + xhr.addEventListener('load', () => { + this.meshes = new PathfinderMeshes(xhr.responseText); + this.meshesReceived(); + }, false); + xhr.open('POST', PARTITION_FONT_ENDPOINT_URL, true); + xhr.setRequestHeader('Content-Type', 'application/json'); + xhr.send(JSON.stringify(request)); + } + + meshesReceived() { // TODO(pcwalton) } view: PathfinderView; loadFontButton: HTMLInputElement; + fontData: ArrayBuffer; + font: any; + meshes: PathfinderMeshes; } class PathfinderView { diff --git a/demo/server/src/main.rs b/demo/server/src/main.rs index 4d57c348..8c899bc4 100644 --- a/demo/server/src/main.rs +++ b/demo/server/src/main.rs @@ -52,13 +52,14 @@ impl IndexRange { } } +#[allow(non_snake_case)] #[derive(Clone, Serialize, Deserialize)] struct PartitionFontRequest { // Base64 encoded. otf: String, - font_index: u32, - glyph_ids: Vec, - point_size: f64, + fontIndex: u32, + glyphIDs: Vec, + pointSize: f64, } #[derive(Clone, Copy, Serialize, Deserialize)] @@ -83,13 +84,14 @@ struct PartitionGlyphInfo { b_vertex_indices: IndexRange, } +#[allow(non_snake_case)] #[derive(Clone, Serialize, Deserialize)] struct PartitionFontResponse { - glyph_info: Vec, + glyphInfo: Vec, // Base64-encoded `bincode`-encoded `BQuad`s. - b_quads: String, + bQuads: String, // Base64-encoded `bincode`-encoded `BVertex`es. - b_vertices: String, + bVertices: String, } #[derive(Clone, Copy, Serialize, Deserialize)] @@ -119,16 +121,16 @@ fn partition_font(request: Json) let font_key = FontKey::new(); let font_instance_key = FontInstanceKey { font_key: font_key, - size: Au::from_f64_px(request.point_size), + size: Au::from_f64_px(request.pointSize), }; let mut font_context = FontContext::new(); - if font_context.add_font_from_memory(&font_key, otf_data, request.font_index).is_err() { + if font_context.add_font_from_memory(&font_key, otf_data, request.fontIndex).is_err() { return Json(Err(PartitionFontError::FontLoadingFailed)) } // Read glyph info. let mut outline_buffer = GlyphOutlineBuffer::new(); - let decoded_outline_indices: Vec<_> = request.glyph_ids.iter().map(|&glyph_id| { + let decoded_outline_indices: Vec<_> = request.glyphIDs.iter().map(|&glyph_id| { let glyph_key = GlyphKey::new(glyph_id); let first_endpoint_index = outline_buffer.endpoints.len(); @@ -159,7 +161,7 @@ fn partition_font(request: Json) &outline_buffer.subpaths); let mut glyph_info = vec![]; for (path_index, (&glyph_id, decoded_outline_indices)) in - request.glyph_ids.iter().zip(decoded_outline_indices.iter()).enumerate() { + request.glyphIDs.iter().zip(decoded_outline_indices.iter()).enumerate() { let glyph_key = GlyphKey::new(glyph_id); let dimensions = match font_context.glyph_dimensions(&font_instance_key, &glyph_key) { @@ -212,9 +214,9 @@ fn partition_font(request: Json) // Return the response. Json(Ok(PartitionFontResponse { - glyph_info: glyph_info, - b_quads: base64::encode(&b_quads), - b_vertices: base64::encode(&b_vertices), + glyphInfo: glyph_info, + bQuads: base64::encode(&b_quads), + bVertices: base64::encode(&b_vertices), })) }