Commit d0c5dd41 authored by Alex Butler's avatar Alex Butler
Browse files

Merge branch 'get_glyph_shape-separate-flags' into 'master'

Safe rework of get_glyph_shape

Closes #15 and #16

See merge request !24
parents 3e5c2799 2d3a5a85
Pipeline #1219 passed with stages
in 4 minutes and 15 seconds
## master
* Remove all unsafe usage.
## 0.2.3
* Add `is_collection(&[u8]) -> bool`.
......
#![allow(unknown_lints)]
#![warn(clippy)]
#![allow(
too_many_arguments,
cast_lossless,
many_single_char_names,
)]
#![allow(too_many_arguments, cast_lossless, many_single_char_names,)]
extern crate byteorder;
......@@ -645,64 +641,10 @@ impl<Data: Deref<Target = [u8]>> FontInfo<Data> {
None => true,
}
}
/// Like `get_codepoint_shape`, but takes a glyph index instead. Use this
/// if you have cached the glyph index for a codepoint.
#[allow(cyclomatic_complexity)] // FIXME rework
pub fn get_glyph_shape(&self, glyph_index: u32) -> Option<Vec<Vertex>> {
use VertexType::*;
fn close_shape(
vertices: &mut [Vertex],
num_vertices: &mut usize,
was_off: bool,
start_off: bool,
sx: i32,
sy: i32,
scx: i32,
scy: i32,
cx: i32,
cy: i32,
) {
use VertexType::*;
if start_off {
if was_off {
vertices[*num_vertices] = Vertex {
type_: CurveTo as u8,
x: ((cx + scx) >> 1) as i16,
y: ((cy + scy) >> 1) as i16,
cx: cx as i16,
cy: cy as i16,
};
*num_vertices += 1;
}
vertices[*num_vertices] = Vertex {
type_: CurveTo as u8,
x: sx as i16,
y: sy as i16,
cx: scx as i16,
cy: scy as i16,
};
} else {
vertices[*num_vertices] = if was_off {
Vertex {
type_: CurveTo as u8,
x: sx as i16,
y: sy as i16,
cx: cx as i16,
cy: cy as i16,
}
} else {
Vertex {
type_: LineTo as u8,
x: sx as i16,
y: sy as i16,
cx: 0,
cy: 0,
}
};
}
*num_vertices += 1;
}
let g = match self.get_glyf_offset(glyph_index) {
Some(g) => &self.data[g as usize..],
None => return None,
......@@ -710,209 +652,7 @@ impl<Data: Deref<Target = [u8]>> FontInfo<Data> {
let number_of_contours = BE::read_i16(g);
let vertices: Vec<Vertex> = if number_of_contours > 0 {
let number_of_contours = number_of_contours as usize;
let mut start_off = false;
let mut was_off = false;
let end_points_of_contours = &g[10..];
let ins = BE::read_u16(&g[10 + number_of_contours * 2..]) as usize;
let mut points = &g[10 + number_of_contours * 2 + 2 + ins..];
let n =
1 + BE::read_u16(&end_points_of_contours[number_of_contours * 2 - 2..]) as usize;
let m = n + 2 * number_of_contours; // a loose bound on how many vertices we might need
let mut vertices: Vec<Vertex> = Vec::with_capacity(m);
unsafe { vertices.set_len(m) };
let mut next_move = 0;
let mut flagcount = 0;
// in first pass, we load uninterpreted data into the allocated array
// above, shifted to the end of the array so we won't overwrite it when
// we create our final data starting from the front
// starting offset for uninterpreted data, regardless of how m ends up being
// calculated
let off = m - n;
// first load flags
let mut flags = 0;
for i in 0..n {
if flagcount == 0 {
flags = points[0];
points = &points[1..];
if flags & 8 != 0 {
flagcount = points[0];
points = &points[1..];
}
} else {
flagcount -= 1;
}
vertices[off + i].type_ = flags;
}
// now load x coordinates
let mut x = 0i32;
for i in 0..n {
let flags = vertices[off + i].type_;
if flags == 255 {
println!("{:?}", flags);
}
if flags & 2 != 0 {
let dx = points[0] as i32;
points = &points[1..];
if flags & 16 != 0 {
// ???
x += dx;
} else {
x -= dx;
}
} else if flags & 16 == 0 {
x += points[0] as i32 * 256 + points[1] as i32;
points = &points[2..];
}
vertices[off + i].x = x as i16;
}
// now load y coordinates
let mut y = 0i32;
for i in 0..n {
let flags = vertices[off + i].type_;
if flags & 4 != 0 {
let dy = points[0] as i32;
points = &points[1..];
if flags & 32 != 0 {
y += dy;
} else {
y -= dy;
}
} else if flags & 32 == 0 {
y += points[0] as i32 * 256 + points[1] as i32;
points = &points[2..];
}
vertices[off + i].y = y as i16;
}
// now convert them to our format
let mut num_vertices = 0;
let mut sx = 0;
let mut sy = 0;
let mut cx = 0;
let mut cy = 0;
let mut scx = 0;
let mut scy = 0;
let mut i = 0;
let mut j = 0;
while i < n {
let flags = vertices[off + i].type_;
x = vertices[off + i].x as i32;
y = vertices[off + i].y as i32;
if next_move == i {
if i != 0 {
close_shape(
&mut vertices[..],
&mut num_vertices,
was_off,
start_off,
sx,
sy,
scx,
scy,
cx,
cy,
);
}
// now start the new one
start_off = flags & 1 == 0;
if start_off {
// if we start off with an off-curve point, then when we need to find a
// point on the curve where we can start, and we
// need to save some state for
// when we wraparound.
scx = x;
scy = y;
if vertices[off + i + 1].type_ as u8 & 1 == 0 {
// next point is also a curve point, so interpolate an on-point curve
sx = (x + vertices[off + i + 1].x as i32) >> 1;
sy = (y + vertices[off + i + 1].y as i32) >> 1;
} else {
// otherwise just use the next point as our start point
sx = vertices[off + i + 1].x as i32;
sy = vertices[off + i + 1].y as i32;
i += 1; // we're using point i+1 as the starting point, so skip it
}
} else {
sx = x;
sy = y;
}
vertices[num_vertices] = Vertex {
type_: MoveTo as u8,
x: sx as i16,
y: sy as i16,
cx: 0,
cy: 0,
};
num_vertices += 1;
was_off = false;
next_move = 1 + BE::read_u16(&end_points_of_contours[j * 2..]) as usize;
j += 1;
} else if flags & 1 == 0 {
// if it's a curve
if was_off {
// two off-curve control points in a row means interpolate an on-curve
// midpoint
vertices[num_vertices] = Vertex {
type_: CurveTo as u8,
x: ((cx + x) >> 1) as i16,
y: ((cy + y) >> 1) as i16,
cx: cx as i16,
cy: cy as i16,
};
num_vertices += 1;
}
cx = x;
cy = y;
was_off = true;
} else {
if was_off {
vertices[num_vertices] = Vertex {
type_: CurveTo as u8,
x: x as i16,
y: y as i16,
cx: cx as i16,
cy: cy as i16,
}
} else {
vertices[num_vertices] = Vertex {
type_: LineTo as u8,
x: x as i16,
y: y as i16,
cx: 0 as i16,
cy: 0 as i16,
}
}
num_vertices += 1;
was_off = false;
}
i += 1;
}
close_shape(
&mut vertices[..],
&mut num_vertices,
was_off,
start_off,
sx,
sy,
scx,
scy,
cx,
cy,
);
assert!(num_vertices <= vertices.len());
vertices.truncate(num_vertices);
vertices
self.glyph_shape_positive_contours(g, number_of_contours as usize)
} else if number_of_contours == -1 {
// Compound shapes
let mut more = true;
......@@ -1003,6 +743,258 @@ impl<Data: Deref<Target = [u8]>> FontInfo<Data> {
Some(vertices)
}
#[inline]
fn glyph_shape_positive_contours(
&self,
glyph_data: &[u8],
number_of_contours: usize,
) -> Vec<Vertex> {
use VertexType::*;
struct FlagData {
flags: u8,
x: i16,
y: i16,
}
#[inline]
fn close_shape(
vertices: &mut Vec<Vertex>,
was_off: bool,
start_off: bool,
sx: i16,
sy: i16,
scx: i16,
scy: i16,
cx: i16,
cy: i16,
) {
if start_off {
if was_off {
vertices.push(Vertex {
type_: CurveTo as u8,
x: (cx + scx) >> 1,
y: (cy + scy) >> 1,
cx,
cy,
});
}
vertices.push(Vertex {
type_: CurveTo as u8,
x: sx,
y: sy,
cx: scx,
cy: scy,
});
} else {
vertices.push(if was_off {
Vertex {
type_: CurveTo as u8,
x: sx,
y: sy,
cx,
cy,
}
} else {
Vertex {
type_: LineTo as u8,
x: sx,
y: sy,
cx: 0,
cy: 0,
}
});
}
}
let number_of_contours = number_of_contours as usize;
let mut start_off = false;
let mut was_off = false;
let end_points_of_contours = &glyph_data[10..];
let ins = BE::read_u16(&glyph_data[10 + number_of_contours * 2..]) as usize;
let mut points = &glyph_data[10 + number_of_contours * 2 + 2 + ins..];
let n = 1 + BE::read_u16(&end_points_of_contours[number_of_contours * 2 - 2..]) as usize;
let m = n + 2 * number_of_contours; // a loose bound on how many vertices we might need
let mut vertices: Vec<Vertex> = Vec::with_capacity(m);
let mut flag_data = Vec::with_capacity(n);
let mut next_move = 0;
// in first pass, we load uninterpreted data into the allocated array above
// first load flags
{
let mut flagcount = 0;
let mut flags = 0;
for _ in 0..n {
if flagcount == 0 {
flags = points[0];
if flags & 8 != 0 {
flagcount = points[1];
points = &points[2..];
} else {
points = &points[1..];
}
} else {
flagcount -= 1;
}
flag_data.push(FlagData { flags, x: 0, y: 0 });
}
}
// now load x coordinates
let mut x_coord = 0_i16;
for flag_data in &mut flag_data {
let flags = flag_data.flags;
if flags & 2 != 0 {
let dx = i16::from(points[0]);
points = &points[1..];
if flags & 16 != 0 {
// ???
x_coord += dx;
} else {
x_coord -= dx;
}
} else if flags & 16 == 0 {
x_coord += BE::read_i16(points);
points = &points[2..];
}
flag_data.x = x_coord;
}
// now load y coordinates
let mut y_coord = 0_i16;
for flag_data in &mut flag_data {
let flags = flag_data.flags;
if flags & 4 != 0 {
let dy = i16::from(points[0]);
points = &points[1..];
if flags & 32 != 0 {
y_coord += dy;
} else {
y_coord -= dy;
}
} else if flags & 32 == 0 {
y_coord += BE::read_i16(points);
points = &points[2..];
}
flag_data.y = y_coord;
}
// now convert them to our format
let mut sx = 0;
let mut sy = 0;
let mut cx = 0;
let mut cy = 0;
let mut scx = 0;
let mut scy = 0;
let mut j = 0;
let mut iter = flag_data.into_iter().enumerate().peekable();
while let Some((index, FlagData { flags, x, y })) = iter.next() {
if next_move == index {
if index != 0 {
close_shape(&mut vertices, was_off, start_off, sx, sy, scx, scy, cx, cy);
}
// now start the new one
start_off = flags & 1 == 0;
if start_off {
// if we start off with an off-curve point, then when we need to find a
// point on the curve where we can start, and we
// need to save some state for
// when we wraparound.
scx = x;
scy = y;
let (next_flags, next_x, next_y) = {
let peek = &iter.peek().unwrap().1;
(peek.flags, peek.x, peek.y)
};
if next_flags & 1 == 0 {
// next point is also a curve point, so interpolate an on-point curve
sx = (x + next_x) >> 1;
sy = (y + next_y) >> 1;
} else {
// otherwise just use the next point as our start point
sx = next_x;
sy = next_y;
// we're using point i+1 as the starting point, so skip it
let _ = iter.next();
}
} else {
sx = x;
sy = y;
}
vertices.push(Vertex {
type_: MoveTo as u8,
x: sx,
y: sy,
cx: 0,
cy: 0,
});
was_off = false;
next_move = 1 + BE::read_u16(&end_points_of_contours[j * 2..]) as usize;
j += 1;
} else if flags & 1 == 0 {
// if it's a curve
if was_off {
// two off-curve control points in a row means interpolate an on-curve
// midpoint
vertices.push(Vertex {
type_: CurveTo as u8,
x: ((cx + x) >> 1),
y: ((cy + y) >> 1),
cx,
cy,
});
}
cx = x;
cy = y;
was_off = true;
} else {
vertices.push(if was_off {
Vertex {
type_: CurveTo as u8,
x,
y,
cx,
cy,
}
} else {
Vertex {
type_: LineTo as u8,
x,
y,
cx: 0,
cy: 0,
}
});
was_off = false;
}
}
close_shape(
&mut vertices,
// &mut num_vertices,
was_off,
start_off,
sx,
sy,
scx,
scy,
cx,
cy,
);
vertices
}
/// like `get_codepoint_h_metrics`, but takes a glyph index instead. Use
/// this if you have cached the glyph index for a codepoint.
pub fn get_glyph_h_metrics(&self, glyph_index: u32) -> HMetrics {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment