Allow multiple glyphs to be rendered simultaneously
This commit is contained in:
parent
9b3f9d029c
commit
93277c7c11
|
@ -9,10 +9,15 @@
|
||||||
"author": "Patrick Walton <pcwalton@mimiga.net>",
|
"author": "Patrick Walton <pcwalton@mimiga.net>",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/base64-js": "^1.2.5",
|
||||||
|
"@types/gl-matrix": "^2.2.34",
|
||||||
|
"@types/lodash": "^4.14.73",
|
||||||
"@types/node": "^8.0.19",
|
"@types/node": "^8.0.19",
|
||||||
|
"@types/opentype.js": "0.0.0",
|
||||||
"base64-js": "^1.2.1",
|
"base64-js": "^1.2.1",
|
||||||
"bootstrap": "^4.0.0-alpha.6",
|
"bootstrap": "^4.0.0-alpha.6",
|
||||||
"gl-matrix": "^2.4.0",
|
"gl-matrix": "^2.4.0",
|
||||||
|
"lodash": "^4.17.4",
|
||||||
"opentype.js": "^0.7.3",
|
"opentype.js": "^0.7.3",
|
||||||
"ts-loader": "^2.3.2",
|
"ts-loader": "^2.3.2",
|
||||||
"typescript": "^2.4.2",
|
"typescript": "^2.4.2",
|
||||||
|
|
|
@ -2,11 +2,12 @@
|
||||||
//
|
//
|
||||||
// Copyright © 2017 Mozilla Foundation
|
// Copyright © 2017 Mozilla Foundation
|
||||||
|
|
||||||
const base64js = require('base64-js');
|
import * as _ from 'lodash';
|
||||||
const glmatrix = require('gl-matrix');
|
import * as base64js from 'base64-js';
|
||||||
const opentype = require('opentype.js');
|
import * as glmatrix from 'gl-matrix';
|
||||||
|
import * as opentype from 'opentype.js';
|
||||||
|
|
||||||
const TEXT: string = "G";
|
const TEXT: string = "Lorem ipsum dolor sit amet";
|
||||||
const FONT_SIZE: number = 16.0;
|
const FONT_SIZE: number = 16.0;
|
||||||
|
|
||||||
const SCALE_FACTOR: number = 1.0 / 100.0;
|
const SCALE_FACTOR: number = 1.0 / 100.0;
|
||||||
|
@ -73,6 +74,8 @@ interface UnlinkedShaderProgram {
|
||||||
|
|
||||||
type Matrix4D = Float32Array;
|
type Matrix4D = Float32Array;
|
||||||
|
|
||||||
|
type Rect = Float32Array;
|
||||||
|
|
||||||
interface Point2D {
|
interface Point2D {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
|
@ -316,7 +319,7 @@ class PathfinderMeshData implements Meshes<ArrayBuffer> {
|
||||||
throw new PathfinderError("Failed to partition the font!");
|
throw new PathfinderError("Failed to partition the font!");
|
||||||
const meshes = response.Ok;
|
const meshes = response.Ok;
|
||||||
for (const bufferName of Object.keys(BUFFER_TYPES) as Array<keyof Meshes<void>>)
|
for (const bufferName of Object.keys(BUFFER_TYPES) as Array<keyof Meshes<void>>)
|
||||||
this[bufferName] = base64js.toByteArray(meshes[bufferName]).buffer;
|
this[bufferName] = base64js.toByteArray(meshes[bufferName]).buffer as ArrayBuffer;
|
||||||
|
|
||||||
this.bQuadCount = this.bQuads.byteLength / B_QUAD_SIZE;
|
this.bQuadCount = this.bQuads.byteLength / B_QUAD_SIZE;
|
||||||
this.edgeUpperLineIndexCount = this.edgeUpperLineIndices.byteLength / 8;
|
this.edgeUpperLineIndexCount = this.edgeUpperLineIndices.byteLength / 8;
|
||||||
|
@ -407,16 +410,40 @@ class AppController {
|
||||||
|
|
||||||
fontLoaded() {
|
fontLoaded() {
|
||||||
this.font = opentype.parse(this.fontData);
|
this.font = opentype.parse(this.fontData);
|
||||||
if (!this.font.supported)
|
if (!(this.font as any).supported)
|
||||||
throw new PathfinderError("The font type is unsupported.");
|
throw new PathfinderError("The font type is unsupported.");
|
||||||
|
|
||||||
const glyphIDs = this.font.stringToGlyphs(TEXT).map((glyph: any) => glyph.index);
|
this.glyphs = this.font.stringToGlyphs(TEXT).map(glyph => new PathfinderGlyph(glyph));
|
||||||
|
this.glyphs.sort((a, b) => a.index() - b.index());
|
||||||
|
this.glyphs = _.sortedUniqBy(this.glyphs, glyph => glyph.index());
|
||||||
|
|
||||||
|
// Lay out in the atlas.
|
||||||
|
let atlasWidth = 0, atlasHeight = 0;
|
||||||
|
for (const glyph of this.glyphs) {
|
||||||
|
const metrics = glyph.metrics();
|
||||||
|
const width = metrics.xMax - metrics.xMin;
|
||||||
|
const height = metrics.yMax - metrics.yMin;
|
||||||
|
atlasHeight = Math.max(atlasHeight, height);
|
||||||
|
const newAtlasWidth = atlasWidth + width;
|
||||||
|
glyph.setAtlasLocation(new Float32Array([atlasWidth, 0, newAtlasWidth, height]));
|
||||||
|
atlasWidth = newAtlasWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the partitioning request to the server.
|
||||||
const request = {
|
const request = {
|
||||||
otf: base64js.fromByteArray(new Uint8Array(this.fontData)),
|
otf: base64js.fromByteArray(new Uint8Array(this.fontData)),
|
||||||
fontIndex: 0,
|
fontIndex: 0,
|
||||||
glyphIDs: glyphIDs,
|
glyphs: this.glyphs.map(glyph => {
|
||||||
pointSize: FONT_SIZE,
|
const atlasLocation = glyph.getAtlasLocation();
|
||||||
|
const metrics = glyph.metrics();
|
||||||
|
const tX = atlasLocation[0] - metrics.xMin;
|
||||||
|
const tY = atlasLocation[1] - metrics.yMin;
|
||||||
|
return {
|
||||||
|
id: glyph.index(),
|
||||||
|
transform: [1, 0, 0, 1, tX, tY],
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
pointSize: this.font.unitsPerEm,
|
||||||
};
|
};
|
||||||
|
|
||||||
window.fetch(PARTITION_FONT_ENDPOINT_URL, {
|
window.fetch(PARTITION_FONT_ENDPOINT_URL, {
|
||||||
|
@ -445,7 +472,8 @@ class AppController {
|
||||||
aaLevelSelect: HTMLSelectElement;
|
aaLevelSelect: HTMLSelectElement;
|
||||||
fpsLabel: HTMLElement;
|
fpsLabel: HTMLElement;
|
||||||
fontData: ArrayBuffer;
|
fontData: ArrayBuffer;
|
||||||
font: any;
|
font: opentype.Font;
|
||||||
|
glyphs: Array<PathfinderGlyph>;
|
||||||
meshes: PathfinderMeshData;
|
meshes: PathfinderMeshData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,14 +642,14 @@ class PathfinderView {
|
||||||
if (event.ctrlKey) {
|
if (event.ctrlKey) {
|
||||||
// Zoom event: see https://developer.mozilla.org/en-US/docs/Web/Events/wheel
|
// Zoom event: see https://developer.mozilla.org/en-US/docs/Web/Events/wheel
|
||||||
const scaleFactor = 1.0 - event.deltaY * window.devicePixelRatio * SCALE_FACTOR;
|
const scaleFactor = 1.0 - event.deltaY * window.devicePixelRatio * SCALE_FACTOR;
|
||||||
const scaleFactors = new Float32Array([scaleFactor, scaleFactor, 1.0]);
|
const scaleFactors = new Float32Array([scaleFactor, scaleFactor, 1.0]) as glmatrix.vec3;
|
||||||
glmatrix.mat4.scale(this.transform, this.transform, scaleFactors);
|
glmatrix.mat4.scale(this.transform, this.transform, scaleFactors);
|
||||||
} else {
|
} else {
|
||||||
const delta = new Float32Array([
|
const delta = new Float32Array([
|
||||||
-event.deltaX * window.devicePixelRatio,
|
-event.deltaX * window.devicePixelRatio,
|
||||||
event.deltaY * window.devicePixelRatio,
|
event.deltaY * window.devicePixelRatio,
|
||||||
0.0
|
0.0,
|
||||||
]);
|
]) as glmatrix.vec3;
|
||||||
glmatrix.mat4.translate(this.transform, this.transform, delta);
|
glmatrix.mat4.translate(this.transform, this.transform, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -821,7 +849,7 @@ class PathfinderView {
|
||||||
quadTexCoordsBuffer: WebGLBuffer;
|
quadTexCoordsBuffer: WebGLBuffer;
|
||||||
quadElementsBuffer: WebGLBuffer;
|
quadElementsBuffer: WebGLBuffer;
|
||||||
|
|
||||||
transform: Matrix4D;
|
transform: glmatrix.mat4;
|
||||||
|
|
||||||
appController: AppController;
|
appController: AppController;
|
||||||
|
|
||||||
|
@ -1457,6 +1485,31 @@ interface AntialiasingStrategyTable {
|
||||||
ecaa: typeof ECAAStrategy;
|
ecaa: typeof ECAAStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PathfinderGlyph {
|
||||||
|
constructor(glyph: opentype.Glyph) {
|
||||||
|
this.glyph = glyph;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAtlasLocation() {
|
||||||
|
return this.atlasLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
setAtlasLocation(rect: Rect) {
|
||||||
|
this.atlasLocation = rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
index(): number {
|
||||||
|
return (this.glyph as any).index;
|
||||||
|
}
|
||||||
|
|
||||||
|
metrics(): opentype.Metrics {
|
||||||
|
return this.glyph.getMetrics();
|
||||||
|
}
|
||||||
|
|
||||||
|
glyph: opentype.Glyph;
|
||||||
|
private atlasLocation: Rect;
|
||||||
|
}
|
||||||
|
|
||||||
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
|
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
|
||||||
none: NoAAStrategy,
|
none: NoAAStrategy,
|
||||||
ssaa: SSAAStrategy,
|
ssaa: SSAAStrategy,
|
||||||
|
|
|
@ -3,7 +3,11 @@
|
||||||
"target": "ES2017",
|
"target": "ES2017",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"types": [
|
"types": [
|
||||||
"node"
|
"base64-js",
|
||||||
|
"gl-matrix",
|
||||||
|
"lodash",
|
||||||
|
"node",
|
||||||
|
"opentype.js"
|
||||||
],
|
],
|
||||||
"typeRoots": [
|
"typeRoots": [
|
||||||
"node_modules/@types"
|
"node_modules/@types"
|
||||||
|
|
|
@ -22,7 +22,7 @@ extern crate serde_derive;
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use bincode::Infinite;
|
use bincode::Infinite;
|
||||||
use euclid::{Point2D, Size2D};
|
use euclid::{Point2D, Size2D, Transform2D};
|
||||||
use pathfinder_font_renderer::{FontContext, FontInstanceKey, FontKey};
|
use pathfinder_font_renderer::{FontContext, FontInstanceKey, FontKey};
|
||||||
use pathfinder_font_renderer::{GlyphKey, GlyphOutlineBuffer};
|
use pathfinder_font_renderer::{GlyphKey, GlyphOutlineBuffer};
|
||||||
use pathfinder_partitioner::partitioner::Partitioner;
|
use pathfinder_partitioner::partitioner::Partitioner;
|
||||||
|
@ -43,7 +43,7 @@ static STATIC_JS_JQUERY_PATH: &'static str = "../client/node_modules/jquery/dist
|
||||||
static STATIC_JS_PATHFINDER_JS_PATH: &'static str = "../client/pathfinder.js";
|
static STATIC_JS_PATHFINDER_JS_PATH: &'static str = "../client/pathfinder.js";
|
||||||
static STATIC_GLSL_PATH: &'static str = "../../shaders";
|
static STATIC_GLSL_PATH: &'static str = "../../shaders";
|
||||||
|
|
||||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
struct IndexRange {
|
struct IndexRange {
|
||||||
start: usize,
|
start: usize,
|
||||||
end: usize,
|
end: usize,
|
||||||
|
@ -57,9 +57,7 @@ impl IndexRange {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_vector_append_and_serialization<T>(dest: &mut Vec<u8>, src: &[T])
|
fn from_data<T>(dest: &mut Vec<u8>, src: &[T]) -> Result<IndexRange, ()> where T: Serialize {
|
||||||
-> Result<IndexRange, ()>
|
|
||||||
where T: Serialize {
|
|
||||||
let byte_len_before = dest.len();
|
let byte_len_before = dest.len();
|
||||||
for src_value in src {
|
for src_value in src {
|
||||||
try!(bincode::serialize_into(dest, src_value, Infinite).map_err(drop))
|
try!(bincode::serialize_into(dest, src_value, Infinite).map_err(drop))
|
||||||
|
@ -78,10 +76,16 @@ struct PartitionFontRequest {
|
||||||
// Base64 encoded.
|
// Base64 encoded.
|
||||||
otf: String,
|
otf: String,
|
||||||
fontIndex: u32,
|
fontIndex: u32,
|
||||||
glyphIDs: Vec<u32>,
|
glyphs: Vec<PartitionGlyph>,
|
||||||
pointSize: f64,
|
pointSize: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||||
|
struct PartitionGlyph {
|
||||||
|
id: u32,
|
||||||
|
transform: Transform2D<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||||
struct PartitionGlyphDimensions {
|
struct PartitionGlyphDimensions {
|
||||||
origin: Point2D<i32>,
|
origin: Point2D<i32>,
|
||||||
|
@ -89,7 +93,7 @@ struct PartitionGlyphDimensions {
|
||||||
advance: f32,
|
advance: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
struct DecodedOutlineIndices {
|
struct DecodedOutlineIndices {
|
||||||
endpoint_indices: IndexRange,
|
endpoint_indices: IndexRange,
|
||||||
control_point_indices: IndexRange,
|
control_point_indices: IndexRange,
|
||||||
|
@ -173,15 +177,18 @@ fn partition_font(request: Json<PartitionFontRequest>)
|
||||||
|
|
||||||
// Read glyph info.
|
// Read glyph info.
|
||||||
let mut outline_buffer = GlyphOutlineBuffer::new();
|
let mut outline_buffer = GlyphOutlineBuffer::new();
|
||||||
let decoded_outline_indices: Vec<_> = request.glyphIDs.iter().map(|&glyph_id| {
|
let decoded_outline_indices: Vec<_> = request.glyphs.iter().map(|glyph| {
|
||||||
let glyph_key = GlyphKey::new(glyph_id);
|
let glyph_key = GlyphKey::new(glyph.id);
|
||||||
|
|
||||||
let first_endpoint_index = outline_buffer.endpoints.len();
|
let first_endpoint_index = outline_buffer.endpoints.len();
|
||||||
let first_control_point_index = outline_buffer.control_points.len();
|
let first_control_point_index = outline_buffer.control_points.len();
|
||||||
let first_subpath_index = outline_buffer.subpaths.len();
|
let first_subpath_index = outline_buffer.subpaths.len();
|
||||||
|
|
||||||
// This might fail; if so, just leave it blank.
|
// This might fail; if so, just leave it blank.
|
||||||
drop(font_context.push_glyph_outline(&font_instance_key, &glyph_key, &mut outline_buffer));
|
drop(font_context.push_glyph_outline(&font_instance_key,
|
||||||
|
&glyph_key,
|
||||||
|
&mut outline_buffer,
|
||||||
|
&glyph.transform));
|
||||||
|
|
||||||
let last_endpoint_index = outline_buffer.endpoints.len();
|
let last_endpoint_index = outline_buffer.endpoints.len();
|
||||||
let last_control_point_index = outline_buffer.control_points.len();
|
let last_control_point_index = outline_buffer.control_points.len();
|
||||||
|
@ -202,13 +209,15 @@ fn partition_font(request: Json<PartitionFontRequest>)
|
||||||
let (mut cover_interior_indices, mut cover_curve_indices) = (vec![], vec![]);
|
let (mut cover_interior_indices, mut cover_curve_indices) = (vec![], vec![]);
|
||||||
let (mut edge_upper_line_indices, mut edge_upper_curve_indices) = (vec![], vec![]);
|
let (mut edge_upper_line_indices, mut edge_upper_curve_indices) = (vec![], vec![]);
|
||||||
let (mut edge_lower_line_indices, mut edge_lower_curve_indices) = (vec![], vec![]);
|
let (mut edge_lower_line_indices, mut edge_lower_curve_indices) = (vec![], vec![]);
|
||||||
|
|
||||||
partitioner.init(&outline_buffer.endpoints,
|
partitioner.init(&outline_buffer.endpoints,
|
||||||
&outline_buffer.control_points,
|
&outline_buffer.control_points,
|
||||||
&outline_buffer.subpaths);
|
&outline_buffer.subpaths);
|
||||||
|
|
||||||
let mut glyph_info = vec![];
|
let mut glyph_info = vec![];
|
||||||
for (path_index, (&glyph_id, decoded_outline_indices)) in
|
for (path_index, (&glyph, decoded_outline_indices)) in
|
||||||
request.glyphIDs.iter().zip(decoded_outline_indices.iter()).enumerate() {
|
request.glyphs.iter().zip(decoded_outline_indices.iter()).enumerate() {
|
||||||
let glyph_key = GlyphKey::new(glyph_id);
|
let glyph_key = GlyphKey::new(glyph.id);
|
||||||
|
|
||||||
let dimensions = match font_context.glyph_dimensions(&font_instance_key, &glyph_key) {
|
let dimensions = match font_context.glyph_dimensions(&font_instance_key, &glyph_key) {
|
||||||
Some(dimensions) => {
|
Some(dimensions) => {
|
||||||
|
@ -231,44 +240,64 @@ fn partition_font(request: Json<PartitionFontRequest>)
|
||||||
decoded_outline_indices.subpath_indices.start as u32,
|
decoded_outline_indices.subpath_indices.start as u32,
|
||||||
decoded_outline_indices.subpath_indices.end as u32);
|
decoded_outline_indices.subpath_indices.end as u32);
|
||||||
|
|
||||||
let path_b_quads = partitioner.b_quads();
|
|
||||||
let path_b_vertex_positions = partitioner.b_vertex_positions();
|
let path_b_vertex_positions = partitioner.b_vertex_positions();
|
||||||
let path_b_vertex_path_ids = partitioner.b_vertex_path_ids();
|
let path_b_vertex_path_ids = partitioner.b_vertex_path_ids();
|
||||||
let path_b_vertex_loop_blinn_data = partitioner.b_vertex_loop_blinn_data();
|
let path_b_vertex_loop_blinn_data = partitioner.b_vertex_loop_blinn_data();
|
||||||
let cover_indices = partitioner.cover_indices();
|
let cover_indices = partitioner.cover_indices();
|
||||||
let edge_indices = partitioner.edge_indices();
|
let edge_indices = partitioner.edge_indices();
|
||||||
|
|
||||||
IndexRange::from_vector_append_and_serialization(&mut b_vertex_positions,
|
let positions_start = IndexRange::from_data(&mut b_vertex_positions,
|
||||||
path_b_vertex_positions).unwrap();
|
path_b_vertex_positions).unwrap().start as u32;
|
||||||
IndexRange::from_vector_append_and_serialization(&mut b_vertex_path_ids,
|
IndexRange::from_data(&mut b_vertex_path_ids, path_b_vertex_path_ids).unwrap();
|
||||||
path_b_vertex_path_ids).unwrap();
|
|
||||||
|
let mut path_b_quads = partitioner.b_quads().to_vec();
|
||||||
|
let mut path_cover_interior_indices = cover_indices.interior_indices.to_vec();
|
||||||
|
let mut path_cover_curve_indices = cover_indices.curve_indices.to_vec();
|
||||||
|
let mut path_edge_upper_line_indices = edge_indices.upper_line_indices.to_vec();
|
||||||
|
let mut path_edge_upper_curve_indices = edge_indices.upper_curve_indices.to_vec();
|
||||||
|
let mut path_edge_lower_line_indices = edge_indices.lower_line_indices.to_vec();
|
||||||
|
let mut path_edge_lower_curve_indices = edge_indices.lower_curve_indices.to_vec();
|
||||||
|
|
||||||
|
for path_b_quad in &mut path_b_quads {
|
||||||
|
path_b_quad.offset(positions_start);
|
||||||
|
}
|
||||||
|
for path_cover_interior_index in &mut path_cover_interior_indices {
|
||||||
|
*path_cover_interior_index += positions_start
|
||||||
|
}
|
||||||
|
for path_cover_curve_index in &mut path_cover_curve_indices {
|
||||||
|
*path_cover_curve_index += positions_start
|
||||||
|
}
|
||||||
|
for path_edge_upper_line_indices in &mut path_edge_upper_line_indices {
|
||||||
|
path_edge_upper_line_indices.offset(positions_start);
|
||||||
|
}
|
||||||
|
for path_edge_upper_curve_indices in &mut path_edge_upper_curve_indices {
|
||||||
|
path_edge_upper_curve_indices.offset(positions_start);
|
||||||
|
}
|
||||||
|
for path_edge_lower_line_indices in &mut path_edge_lower_line_indices {
|
||||||
|
path_edge_lower_line_indices.offset(positions_start);
|
||||||
|
}
|
||||||
|
for path_edge_lower_curve_indices in &mut path_edge_lower_curve_indices {
|
||||||
|
path_edge_lower_curve_indices.offset(positions_start);
|
||||||
|
}
|
||||||
|
|
||||||
glyph_info.push(PartitionGlyphInfo {
|
glyph_info.push(PartitionGlyphInfo {
|
||||||
id: glyph_id,
|
id: glyph.id,
|
||||||
dimensions: dimensions,
|
dimensions: dimensions,
|
||||||
bQuadIndices: IndexRange::from_vector_append_and_serialization(&mut b_quads,
|
bQuadIndices: IndexRange::from_data(&mut b_quads, &path_b_quads).unwrap(),
|
||||||
path_b_quads).unwrap(),
|
bVertexIndices: IndexRange::from_data(&mut b_vertex_loop_blinn_data,
|
||||||
bVertexIndices: IndexRange::from_vector_append_and_serialization(
|
path_b_vertex_loop_blinn_data).unwrap(),
|
||||||
&mut b_vertex_loop_blinn_data,
|
coverInteriorIndices: IndexRange::from_data(&mut cover_interior_indices,
|
||||||
path_b_vertex_loop_blinn_data).unwrap(),
|
&path_cover_interior_indices).unwrap(),
|
||||||
coverInteriorIndices: IndexRange::from_vector_append_and_serialization(
|
coverCurveIndices: IndexRange::from_data(&mut cover_curve_indices,
|
||||||
&mut cover_interior_indices,
|
&path_cover_curve_indices).unwrap(),
|
||||||
cover_indices.interior_indices).unwrap(),
|
edgeUpperLineIndices: IndexRange::from_data(&mut edge_upper_line_indices,
|
||||||
coverCurveIndices: IndexRange::from_vector_append_and_serialization(
|
&path_edge_upper_line_indices).unwrap(),
|
||||||
&mut cover_curve_indices,
|
edgeUpperCurveIndices: IndexRange::from_data(&mut edge_upper_curve_indices,
|
||||||
cover_indices.curve_indices).unwrap(),
|
&path_edge_upper_curve_indices).unwrap(),
|
||||||
edgeUpperLineIndices: IndexRange::from_vector_append_and_serialization(
|
edgeLowerLineIndices: IndexRange::from_data(&mut edge_lower_line_indices,
|
||||||
&mut edge_upper_line_indices,
|
&path_edge_lower_line_indices).unwrap(),
|
||||||
edge_indices.upper_line_indices).unwrap(),
|
edgeLowerCurveIndices: IndexRange::from_data(&mut edge_lower_curve_indices,
|
||||||
edgeUpperCurveIndices: IndexRange::from_vector_append_and_serialization(
|
&path_edge_lower_curve_indices).unwrap(),
|
||||||
&mut edge_upper_curve_indices,
|
|
||||||
edge_indices.upper_curve_indices).unwrap(),
|
|
||||||
edgeLowerLineIndices: IndexRange::from_vector_append_and_serialization(
|
|
||||||
&mut edge_lower_line_indices,
|
|
||||||
edge_indices.lower_line_indices).unwrap(),
|
|
||||||
edgeLowerCurveIndices: IndexRange::from_vector_append_and_serialization(
|
|
||||||
&mut edge_lower_curve_indices,
|
|
||||||
edge_indices.lower_curve_indices).unwrap(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ extern crate log;
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use euclid::{Point2D, Size2D};
|
use euclid::{Point2D, Size2D, Transform2D};
|
||||||
use freetype_sys::{FT_BBox, FT_Done_Face, FT_F26Dot6, FT_Face, FT_GLYPH_FORMAT_OUTLINE};
|
use freetype_sys::{FT_BBox, FT_Done_Face, FT_F26Dot6, FT_Face, FT_GLYPH_FORMAT_OUTLINE};
|
||||||
use freetype_sys::{FT_GlyphSlot, FT_Init_FreeType, FT_Int32, FT_LOAD_TARGET_LIGHT, FT_Library};
|
use freetype_sys::{FT_GlyphSlot, FT_Init_FreeType, FT_Int32, FT_LOAD_TARGET_LIGHT, FT_Library};
|
||||||
use freetype_sys::{FT_Load_Glyph, FT_Long, FT_New_Memory_Face, FT_Outline_Get_CBox};
|
use freetype_sys::{FT_Load_Glyph, FT_Long, FT_New_Memory_Face, FT_Outline_Get_CBox};
|
||||||
|
@ -93,13 +93,15 @@ impl FontContext {
|
||||||
pub fn push_glyph_outline(&self,
|
pub fn push_glyph_outline(&self,
|
||||||
font_instance: &FontInstanceKey,
|
font_instance: &FontInstanceKey,
|
||||||
glyph_key: &GlyphKey,
|
glyph_key: &GlyphKey,
|
||||||
glyph_outline_buffer: &mut GlyphOutlineBuffer)
|
glyph_outline_buffer: &mut GlyphOutlineBuffer,
|
||||||
|
transform: &Transform2D<f32>)
|
||||||
-> Result<(), ()> {
|
-> Result<(), ()> {
|
||||||
self.load_glyph(font_instance, glyph_key).ok_or(()).map(|glyph_slot| {
|
self.load_glyph(font_instance, glyph_key).ok_or(()).map(|glyph_slot| {
|
||||||
self.push_glyph_outline_from_glyph_slot(font_instance,
|
self.push_glyph_outline_from_glyph_slot(font_instance,
|
||||||
glyph_key,
|
glyph_key,
|
||||||
glyph_slot,
|
glyph_slot,
|
||||||
glyph_outline_buffer)
|
glyph_outline_buffer,
|
||||||
|
transform)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +113,8 @@ impl FontContext {
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
FT_Set_Char_Size(face.face, font_instance.size.to_ft_f26dot6(), 0, 0, 0);
|
let point_size = (font_instance.size.to_f64_px() / 72.0).to_ft_f26dot6();
|
||||||
|
FT_Set_Char_Size(face.face, point_size, 0, 72, 0);
|
||||||
|
|
||||||
if FT_Load_Glyph(face.face, glyph_key.glyph_index as FT_UInt, GLYPH_LOAD_FLAGS) != 0 {
|
if FT_Load_Glyph(face.face, glyph_key.glyph_index as FT_UInt, GLYPH_LOAD_FLAGS) != 0 {
|
||||||
return None
|
return None
|
||||||
|
@ -174,7 +177,8 @@ impl FontContext {
|
||||||
_: &FontInstanceKey,
|
_: &FontInstanceKey,
|
||||||
_: &GlyphKey,
|
_: &GlyphKey,
|
||||||
glyph_slot: FT_GlyphSlot,
|
glyph_slot: FT_GlyphSlot,
|
||||||
glyph_outline_buffer: &mut GlyphOutlineBuffer) {
|
glyph_outline_buffer: &mut GlyphOutlineBuffer,
|
||||||
|
transform: &Transform2D<f32>) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let outline = &(*glyph_slot).outline;
|
let outline = &(*glyph_slot).outline;
|
||||||
let mut first_point_index = 0 as u32;
|
let mut first_point_index = 0 as u32;
|
||||||
|
@ -189,7 +193,8 @@ impl FontContext {
|
||||||
// FIXME(pcwalton): Does FreeType produce multiple consecutive off-curve points
|
// FIXME(pcwalton): Does FreeType produce multiple consecutive off-curve points
|
||||||
// in a row like raw TrueType does?
|
// in a row like raw TrueType does?
|
||||||
let point = *outline.points.offset(point_index as isize);
|
let point = *outline.points.offset(point_index as isize);
|
||||||
let point_position = Point2D::new(point.x as f32, point.y as f32);
|
let point_position = transform.transform_point(&Point2D::new(point.x as f32,
|
||||||
|
point.y as f32));
|
||||||
if (*outline.tags.offset(point_index as isize) & FREETYPE_POINT_ON_CURVE) != 0 {
|
if (*outline.tags.offset(point_index as isize) & FREETYPE_POINT_ON_CURVE) != 0 {
|
||||||
glyph_outline_buffer.endpoints.push(Endpoint {
|
glyph_outline_buffer.endpoints.push(Endpoint {
|
||||||
position: point_position,
|
position: point_position,
|
||||||
|
@ -303,8 +308,14 @@ trait ToFtF26Dot6 {
|
||||||
fn to_ft_f26dot6(&self) -> FT_F26Dot6;
|
fn to_ft_f26dot6(&self) -> FT_F26Dot6;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToFtF26Dot6 for Au {
|
impl ToFtF26Dot6 for f64 {
|
||||||
fn to_ft_f26dot6(&self) -> FT_F26Dot6 {
|
fn to_ft_f26dot6(&self) -> FT_F26Dot6 {
|
||||||
(self.to_f64_px() * 64.0 + 0.5) as FT_F26Dot6
|
(*self * 64.0 + 0.5) as FT_F26Dot6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToFtF26Dot6 for Au {
|
||||||
|
fn to_ft_f26dot6(&self) -> FT_F26Dot6 {
|
||||||
|
self.to_f64_px().to_ft_f26dot6()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,20 @@ impl BQuad {
|
||||||
pad1: 0,
|
pad1: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn offset(&mut self, delta: u32) {
|
||||||
|
self.upper_left_vertex_index += delta;
|
||||||
|
self.upper_right_vertex_index += delta;
|
||||||
|
self.lower_left_vertex_index += delta;
|
||||||
|
self.lower_right_vertex_index += delta;
|
||||||
|
if self.upper_control_point_vertex_index < u32::MAX {
|
||||||
|
self.upper_control_point_vertex_index += delta;
|
||||||
|
}
|
||||||
|
if self.lower_control_point_vertex_index < u32::MAX {
|
||||||
|
self.lower_control_point_vertex_index += delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -145,6 +159,12 @@ impl LineIndices {
|
||||||
right_vertex_index: right_vertex_index,
|
right_vertex_index: right_vertex_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn offset(&mut self, delta: u32) {
|
||||||
|
self.left_vertex_index += delta;
|
||||||
|
self.right_vertex_index += delta;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||||
|
@ -167,4 +187,13 @@ impl CurveIndices {
|
||||||
pad: 0,
|
pad: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn offset(&mut self, delta: u32) {
|
||||||
|
self.left_vertex_index += delta;
|
||||||
|
self.right_vertex_index += delta;
|
||||||
|
if self.control_point_vertex_index < u32::MAX {
|
||||||
|
self.control_point_vertex_index += delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue