Support cubic Béziers for fonts with CFF outlines
This commit is contained in:
parent
a508322f34
commit
6ac37c5085
|
@ -22,10 +22,13 @@ flat in int vVertexID[];
|
||||||
|
|
||||||
// The starting point of the segment.
|
// The starting point of the segment.
|
||||||
out vec2 vpP0[];
|
out vec2 vpP0[];
|
||||||
// The control point, if this is a curve. If this is a line, this value must be ignored.
|
// The first control point, if this is a curve. If this is a line, this value must be ignored.
|
||||||
out vec2 vpP1[];
|
out vec2 vpP1[];
|
||||||
// The endpoint of this segment.
|
// The second control point, if this is a curve. If this is a line, this value must be ignored.
|
||||||
|
// If this curve is quadratic, this will be the same as `vpP1`.
|
||||||
out vec2 vpP2[];
|
out vec2 vpP2[];
|
||||||
|
// The endpoint of this segment.
|
||||||
|
out vec2 vpP3[];
|
||||||
// The tessellation level.
|
// The tessellation level.
|
||||||
//
|
//
|
||||||
// This is passed along explicitly instead of having the TES read it from `gl_TessLevelInner` in
|
// This is passed along explicitly instead of having the TES read it from `gl_TessLevelInner` in
|
||||||
|
@ -36,15 +39,19 @@ void main() {
|
||||||
vec2 p0 = gl_in[0].gl_Position.xy;
|
vec2 p0 = gl_in[0].gl_Position.xy;
|
||||||
vec2 p1 = gl_in[1].gl_Position.xy;
|
vec2 p1 = gl_in[1].gl_Position.xy;
|
||||||
vec2 p2 = gl_in[2].gl_Position.xy;
|
vec2 p2 = gl_in[2].gl_Position.xy;
|
||||||
|
vec2 p3 = gl_in[3].gl_Position.xy;
|
||||||
|
|
||||||
// Divide into lines.
|
// Divide into lines.
|
||||||
float lineCount = 1.0f;
|
float lineCount = 1.0f;
|
||||||
if (vVertexID[1] > 0) {
|
if (vVertexID[1] > 0) {
|
||||||
// Quadratic curve.
|
// A curve.
|
||||||
vec2 dev = p0 - 2.0f * p1 + p2;
|
//
|
||||||
|
// FIXME(pcwalton): Is this formula good for cubic curves?
|
||||||
|
vec2 dev = p0 - 2.0f * mix(p1, p2, 0.5) + p3;
|
||||||
float devSq = dot(dev, dev);
|
float devSq = dot(dev, dev);
|
||||||
if (devSq >= CURVE_THRESHOLD) {
|
if (devSq >= CURVE_THRESHOLD) {
|
||||||
// Inverse square root is likely no slower and may be faster than regular square root
|
// Inverse square root is likely no slower and may be faster than regular square
|
||||||
|
// root
|
||||||
// (e.g. on x86).
|
// (e.g. on x86).
|
||||||
lineCount += floor(inversesqrt(inversesqrt(CURVE_TOLERANCE * devSq)));
|
lineCount += floor(inversesqrt(inversesqrt(CURVE_TOLERANCE * devSq)));
|
||||||
}
|
}
|
||||||
|
@ -92,7 +99,7 @@ void main() {
|
||||||
// so we're in the clear: the rasterizer will always discard the unshaded areas and render only
|
// so we're in the clear: the rasterizer will always discard the unshaded areas and render only
|
||||||
// the shaded ones.
|
// the shaded ones.
|
||||||
|
|
||||||
float tessLevel = min(p0.x == p2.x ? 0.0f : (lineCount * 2.0f - 1.0f), 31.0f);
|
float tessLevel = min(p0.x == p3.x ? 0.0f : (lineCount * 2.0f - 1.0f), 31.0f);
|
||||||
gl_TessLevelInner[0] = tessLevel;
|
gl_TessLevelInner[0] = tessLevel;
|
||||||
gl_TessLevelInner[1] = 1.0f;
|
gl_TessLevelInner[1] = 1.0f;
|
||||||
gl_TessLevelOuter[0] = 1.0f;
|
gl_TessLevelOuter[0] = 1.0f;
|
||||||
|
@ -105,6 +112,7 @@ void main() {
|
||||||
vpP0[gl_InvocationID] = p0;
|
vpP0[gl_InvocationID] = p0;
|
||||||
vpP1[gl_InvocationID] = p1;
|
vpP1[gl_InvocationID] = p1;
|
||||||
vpP2[gl_InvocationID] = p2;
|
vpP2[gl_InvocationID] = p2;
|
||||||
|
vpP3[gl_InvocationID] = p3;
|
||||||
vpTessLevel[gl_InvocationID] = tessLevel;
|
vpTessLevel[gl_InvocationID] = tessLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,13 @@ uniform uvec2 uAtlasSize;
|
||||||
|
|
||||||
// The starting point of the segment.
|
// The starting point of the segment.
|
||||||
in vec2 vpP0[];
|
in vec2 vpP0[];
|
||||||
// The control point, if this is a curve. If this is a line, this value must be ignored.
|
// The first control point, if this is a curve. If this is a line, this value must be ignored.
|
||||||
in vec2 vpP1[];
|
in vec2 vpP1[];
|
||||||
// The endpoint of this segment.
|
// The second control point, if this is a cubic curve. If this is a quadratic curve or a line, this
|
||||||
|
// is equal to `vpP1`.
|
||||||
in vec2 vpP2[];
|
in vec2 vpP2[];
|
||||||
|
// The endpoint of this segment.
|
||||||
|
in vec2 vpP3[];
|
||||||
// The tessellation level.
|
// The tessellation level.
|
||||||
//
|
//
|
||||||
// This is passed along explicitly instead of having the TES read it from `gl_TessLevelInner` in
|
// This is passed along explicitly instead of having the TES read it from `gl_TessLevelInner` in
|
||||||
|
@ -40,7 +43,7 @@ flat out vec2 vYMinMax;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// Read in curve points.
|
// Read in curve points.
|
||||||
vec2 cP0 = vpP0[0], cP1 = vpP1[0], cP2 = vpP2[0];
|
vec2 cP0 = vpP0[0], cP1 = vpP1[0], cP2 = vpP2[0], cP3 = vpP3[0];
|
||||||
|
|
||||||
// Work out how many lines made up this segment, which line we're working on, and which
|
// Work out how many lines made up this segment, which line we're working on, and which
|
||||||
// endpoint of that line we're looking at.
|
// endpoint of that line we're looking at.
|
||||||
|
@ -53,12 +56,25 @@ void main() {
|
||||||
vec2 p0, p1;
|
vec2 p0, p1;
|
||||||
if (lineCount == 1) {
|
if (lineCount == 1) {
|
||||||
p0 = cP0;
|
p0 = cP0;
|
||||||
p1 = cP2;
|
p1 = cP3;
|
||||||
} else {
|
} else {
|
||||||
float t0 = float(lineIndex + 0) / float(lineCount);
|
float t0 = float(lineIndex + 0) / float(lineCount);
|
||||||
float t1 = float(lineIndex + 1) / float(lineCount);
|
float t1 = float(lineIndex + 1) / float(lineCount);
|
||||||
p0 = mix(mix(cP0, cP1, t0), mix(cP1, cP2, t0), t0);
|
|
||||||
p1 = mix(mix(cP0, cP1, t1), mix(cP1, cP2, t1), t1);
|
// These lerps are needed both for quadratic and cubic Béziers.
|
||||||
|
vec2 pP0P1T0 = mix(cP0, cP1, t0), pP0P1T1 = mix(cP0, cP1, t1);
|
||||||
|
vec2 pP2P3T0 = mix(cP2, cP3, t0), pP2P3T1 = mix(cP2, cP3, t1);
|
||||||
|
|
||||||
|
if (cP1 == cP2) {
|
||||||
|
// Quadratic Bézier.
|
||||||
|
p0 = mix(pP0P1T0, pP2P3T0, t0);
|
||||||
|
p1 = mix(pP0P1T1, pP2P3T1, t1);
|
||||||
|
} else {
|
||||||
|
// Cubic Bézier.
|
||||||
|
vec2 pP1P2T0 = mix(cP1, cP2, t0), pP1P2T1 = mix(cP1, cP2, t1);
|
||||||
|
p0 = mix(mix(pP0P1T0, pP1P2T0, t0), mix(pP1P2T0, pP2P3T0, t0), t0);
|
||||||
|
p1 = mix(mix(pP0P1T1, pP1P2T1, t1), mix(pP1P2T1, pP2P3T1, t1), t1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute direction. Flip the two points around so that p0 is on the left and p1 is on the
|
// Compute direction. Flip the two points around so that p0 is on the left and p1 is on the
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
use byteorder::{BigEndian, LittleEndian, ReadBytesExt};
|
use byteorder::{BigEndian, LittleEndian, ReadBytesExt};
|
||||||
use euclid::Point2D;
|
use euclid::Point2D;
|
||||||
use otf::glyf::Point;
|
use otf::glyf::{Point, PointKind};
|
||||||
use otf::head::HeadTable;
|
use otf::head::HeadTable;
|
||||||
use otf::{Error, FontTable};
|
use otf::{Error, FontTable};
|
||||||
use outline::GlyphBounds;
|
use outline::GlyphBounds;
|
||||||
|
@ -112,7 +112,7 @@ impl<'a> CffTable<'a> {
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: pos,
|
position: pos,
|
||||||
index_in_contour: 0,
|
index_in_contour: 0,
|
||||||
on_curve: true,
|
kind: PointKind::OnCurve,
|
||||||
});
|
});
|
||||||
start = pos;
|
start = pos;
|
||||||
index_in_contour = 1;
|
index_in_contour = 1;
|
||||||
|
@ -125,7 +125,7 @@ impl<'a> CffTable<'a> {
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: pos,
|
position: pos,
|
||||||
index_in_contour: index_in_contour,
|
index_in_contour: index_in_contour,
|
||||||
on_curve: true,
|
kind: PointKind::OnCurve,
|
||||||
});
|
});
|
||||||
index_in_contour += 1
|
index_in_contour += 1
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ impl<'a> CffTable<'a> {
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: pos,
|
position: pos,
|
||||||
index_in_contour: index_in_contour,
|
index_in_contour: index_in_contour,
|
||||||
on_curve: true,
|
kind: PointKind::OnCurve,
|
||||||
});
|
});
|
||||||
index_in_contour += 1
|
index_in_contour += 1
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ impl<'a> CffTable<'a> {
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: pos,
|
position: pos,
|
||||||
index_in_contour: index_in_contour,
|
index_in_contour: index_in_contour,
|
||||||
on_curve: true,
|
kind: PointKind::OnCurve,
|
||||||
});
|
});
|
||||||
index_in_contour += 1
|
index_in_contour += 1
|
||||||
}
|
}
|
||||||
|
@ -174,21 +174,21 @@ impl<'a> CffTable<'a> {
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: pos,
|
position: pos,
|
||||||
index_in_contour: index_in_contour + 0,
|
index_in_contour: index_in_contour + 0,
|
||||||
on_curve: true,
|
kind: PointKind::FirstCubicControl,
|
||||||
});
|
});
|
||||||
|
|
||||||
pos = pos + Point2D::new(chunk[2] as i16, chunk[3] as i16);
|
pos = pos + Point2D::new(chunk[2] as i16, chunk[3] as i16);
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: pos,
|
position: pos,
|
||||||
index_in_contour: index_in_contour + 1,
|
index_in_contour: index_in_contour + 1,
|
||||||
on_curve: true,
|
kind: PointKind::SecondCubicControl,
|
||||||
});
|
});
|
||||||
|
|
||||||
pos = pos + Point2D::new(chunk[4] as i16, chunk[5] as i16);
|
pos = pos + Point2D::new(chunk[4] as i16, chunk[5] as i16);
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: pos,
|
position: pos,
|
||||||
index_in_contour: index_in_contour + 2,
|
index_in_contour: index_in_contour + 2,
|
||||||
on_curve: true,
|
kind: PointKind::OnCurve,
|
||||||
});
|
});
|
||||||
|
|
||||||
index_in_contour += 3
|
index_in_contour += 3
|
||||||
|
@ -272,7 +272,7 @@ impl<'a> CffTable<'a> {
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: pos,
|
position: pos,
|
||||||
index_in_contour: index_in_contour,
|
index_in_contour: index_in_contour,
|
||||||
on_curve: true,
|
kind: PointKind::FirstCubicControl,
|
||||||
});
|
});
|
||||||
|
|
||||||
pos.x += chunk[1] as i16;
|
pos.x += chunk[1] as i16;
|
||||||
|
@ -280,14 +280,14 @@ impl<'a> CffTable<'a> {
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: pos,
|
position: pos,
|
||||||
index_in_contour: index_in_contour + 1,
|
index_in_contour: index_in_contour + 1,
|
||||||
on_curve: true,
|
kind: PointKind::SecondCubicControl,
|
||||||
});
|
});
|
||||||
|
|
||||||
pos.y += chunk[3] as i16;
|
pos.y += chunk[3] as i16;
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: pos,
|
position: pos,
|
||||||
index_in_contour: index_in_contour + 2,
|
index_in_contour: index_in_contour + 2,
|
||||||
on_curve: true,
|
kind: PointKind::OnCurve,
|
||||||
});
|
});
|
||||||
|
|
||||||
index_in_contour += 3
|
index_in_contour += 3
|
||||||
|
@ -311,7 +311,7 @@ impl<'a> CffTable<'a> {
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: pos,
|
position: pos,
|
||||||
index_in_contour: index_in_contour,
|
index_in_contour: index_in_contour,
|
||||||
on_curve: true,
|
kind: PointKind::FirstCubicControl,
|
||||||
});
|
});
|
||||||
|
|
||||||
pos.x += chunk[1] as i16;
|
pos.x += chunk[1] as i16;
|
||||||
|
@ -319,14 +319,14 @@ impl<'a> CffTable<'a> {
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: pos,
|
position: pos,
|
||||||
index_in_contour: index_in_contour + 1,
|
index_in_contour: index_in_contour + 1,
|
||||||
on_curve: true,
|
kind: PointKind::SecondCubicControl,
|
||||||
});
|
});
|
||||||
|
|
||||||
pos.x += chunk[3] as i16;
|
pos.x += chunk[3] as i16;
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: pos,
|
position: pos,
|
||||||
index_in_contour: index_in_contour + 2,
|
index_in_contour: index_in_contour + 2,
|
||||||
on_curve: true,
|
kind: PointKind::OnCurve,
|
||||||
});
|
});
|
||||||
|
|
||||||
index_in_contour += 3
|
index_in_contour += 3
|
||||||
|
@ -367,7 +367,7 @@ impl<'a> CffTable<'a> {
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: pos,
|
position: pos,
|
||||||
index_in_contour: 0,
|
index_in_contour: 0,
|
||||||
on_curve: true,
|
kind: PointKind::OnCurve,
|
||||||
});
|
});
|
||||||
start = pos;
|
start = pos;
|
||||||
index_in_contour = 1;
|
index_in_contour = 1;
|
||||||
|
@ -380,7 +380,7 @@ impl<'a> CffTable<'a> {
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: pos,
|
position: pos,
|
||||||
index_in_contour: 0,
|
index_in_contour: 0,
|
||||||
on_curve: true,
|
kind: PointKind::OnCurve,
|
||||||
});
|
});
|
||||||
start = pos;
|
start = pos;
|
||||||
index_in_contour = 1;
|
index_in_contour = 1;
|
||||||
|
@ -558,7 +558,7 @@ fn close_path_if_necessary<F>(pos: &mut Point2D<i16>,
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: *start,
|
position: *start,
|
||||||
index_in_contour: index_in_contour,
|
index_in_contour: index_in_contour,
|
||||||
on_curve: true,
|
kind: PointKind::OnCurve,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,7 +572,7 @@ fn process_hvcurveto_h<F>(chunk: &[i32],
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: *pos,
|
position: *pos,
|
||||||
index_in_contour: *index_in_contour + 0,
|
index_in_contour: *index_in_contour + 0,
|
||||||
on_curve: true,
|
kind: PointKind::FirstCubicControl,
|
||||||
});
|
});
|
||||||
|
|
||||||
pos.x += chunk[1] as i16;
|
pos.x += chunk[1] as i16;
|
||||||
|
@ -580,7 +580,7 @@ fn process_hvcurveto_h<F>(chunk: &[i32],
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: *pos,
|
position: *pos,
|
||||||
index_in_contour: *index_in_contour + 1,
|
index_in_contour: *index_in_contour + 1,
|
||||||
on_curve: true,
|
kind: PointKind::SecondCubicControl,
|
||||||
});
|
});
|
||||||
|
|
||||||
pos.x += dxf as i16;
|
pos.x += dxf as i16;
|
||||||
|
@ -588,7 +588,7 @@ fn process_hvcurveto_h<F>(chunk: &[i32],
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: *pos,
|
position: *pos,
|
||||||
index_in_contour: *index_in_contour + 2,
|
index_in_contour: *index_in_contour + 2,
|
||||||
on_curve: true,
|
kind: PointKind::OnCurve,
|
||||||
});
|
});
|
||||||
|
|
||||||
*index_in_contour += 3
|
*index_in_contour += 3
|
||||||
|
@ -604,7 +604,7 @@ fn process_hvcurveto_v<F>(chunk: &[i32],
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: *pos,
|
position: *pos,
|
||||||
index_in_contour: *index_in_contour + 0,
|
index_in_contour: *index_in_contour + 0,
|
||||||
on_curve: true,
|
kind: PointKind::FirstCubicControl,
|
||||||
});
|
});
|
||||||
|
|
||||||
pos.x += chunk[1] as i16;
|
pos.x += chunk[1] as i16;
|
||||||
|
@ -612,7 +612,7 @@ fn process_hvcurveto_v<F>(chunk: &[i32],
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: *pos,
|
position: *pos,
|
||||||
index_in_contour: *index_in_contour + 1,
|
index_in_contour: *index_in_contour + 1,
|
||||||
on_curve: true,
|
kind: PointKind::SecondCubicControl,
|
||||||
});
|
});
|
||||||
|
|
||||||
pos.x += chunk[3] as i16;
|
pos.x += chunk[3] as i16;
|
||||||
|
@ -620,7 +620,7 @@ fn process_hvcurveto_v<F>(chunk: &[i32],
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: *pos,
|
position: *pos,
|
||||||
index_in_contour: *index_in_contour + 2,
|
index_in_contour: *index_in_contour + 2,
|
||||||
on_curve: true,
|
kind: PointKind::OnCurve,
|
||||||
});
|
});
|
||||||
|
|
||||||
*index_in_contour += 3
|
*index_in_contour += 3
|
||||||
|
|
|
@ -46,9 +46,30 @@ bitflags! {
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
pub struct Point {
|
pub struct Point {
|
||||||
|
/// Where the point is located in glyph space.
|
||||||
pub position: Point2D<i16>,
|
pub position: Point2D<i16>,
|
||||||
|
|
||||||
|
/// The index of the point in this contour.
|
||||||
|
///
|
||||||
|
/// When iterating over points via `for_each_point`, a value of 0 here indicates that a new
|
||||||
|
/// contour begins.
|
||||||
pub index_in_contour: u16,
|
pub index_in_contour: u16,
|
||||||
pub on_curve: bool,
|
|
||||||
|
/// The kind of point this is.
|
||||||
|
pub kind: PointKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The type of point.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
pub enum PointKind {
|
||||||
|
/// The point is on the curve.
|
||||||
|
OnCurve,
|
||||||
|
/// The point is a quadratic control point.
|
||||||
|
QuadControl,
|
||||||
|
/// The point is the first cubic control point.
|
||||||
|
FirstCubicControl,
|
||||||
|
/// The point is the second cubic control point.
|
||||||
|
SecondCubicControl,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO(pcwalton): Add some caching so we don't keep going to the `loca` table all the time.
|
/// TODO(pcwalton): Add some caching so we don't keep going to the `loca` table all the time.
|
||||||
|
@ -166,7 +187,7 @@ impl<'a> GlyfTable<'a> {
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: position,
|
position: position,
|
||||||
index_in_contour: point_index_in_contour,
|
index_in_contour: point_index_in_contour,
|
||||||
on_curve: true,
|
kind: PointKind::OnCurve,
|
||||||
});
|
});
|
||||||
point_index_in_contour += 1
|
point_index_in_contour += 1
|
||||||
}
|
}
|
||||||
|
@ -185,7 +206,11 @@ impl<'a> GlyfTable<'a> {
|
||||||
} else {
|
} else {
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: position,
|
position: position,
|
||||||
on_curve: flags.contains(ON_CURVE),
|
kind: if flags.contains(ON_CURVE) {
|
||||||
|
PointKind::OnCurve
|
||||||
|
} else {
|
||||||
|
PointKind::QuadControl
|
||||||
|
},
|
||||||
index_in_contour: point_index_in_contour,
|
index_in_contour: point_index_in_contour,
|
||||||
});
|
});
|
||||||
point_index_in_contour += 1
|
point_index_in_contour += 1
|
||||||
|
@ -203,14 +228,14 @@ impl<'a> GlyfTable<'a> {
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: position,
|
position: position,
|
||||||
index_in_contour: point_index_in_contour,
|
index_in_contour: point_index_in_contour,
|
||||||
on_curve: true,
|
kind: PointKind::OnCurve,
|
||||||
});
|
});
|
||||||
point_index_in_contour += 1
|
point_index_in_contour += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: initial_off_curve_point,
|
position: initial_off_curve_point,
|
||||||
on_curve: false,
|
kind: PointKind::QuadControl,
|
||||||
index_in_contour: point_index_in_contour,
|
index_in_contour: point_index_in_contour,
|
||||||
});
|
});
|
||||||
point_index_in_contour += 1
|
point_index_in_contour += 1
|
||||||
|
@ -220,7 +245,7 @@ impl<'a> GlyfTable<'a> {
|
||||||
if let Some(first_on_curve_point) = first_on_curve_point {
|
if let Some(first_on_curve_point) = first_on_curve_point {
|
||||||
callback(&Point {
|
callback(&Point {
|
||||||
position: first_on_curve_point,
|
position: first_on_curve_point,
|
||||||
on_curve: true,
|
kind: PointKind::OnCurve,
|
||||||
index_in_contour: point_index_in_contour,
|
index_in_contour: point_index_in_contour,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,13 @@
|
||||||
|
|
||||||
//! OpenType fonts.
|
//! OpenType fonts.
|
||||||
|
|
||||||
|
pub use otf::glyf::{Point, PointKind};
|
||||||
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt};
|
||||||
use charmap::{CodepointRange, GlyphMapping};
|
use charmap::{CodepointRange, GlyphMapping};
|
||||||
use otf::cff::CffTable;
|
use otf::cff::CffTable;
|
||||||
use otf::cmap::CmapTable;
|
use otf::cmap::CmapTable;
|
||||||
use otf::glyf::{GlyfTable, Point};
|
use otf::glyf::GlyfTable;
|
||||||
use otf::head::HeadTable;
|
use otf::head::HeadTable;
|
||||||
use otf::hhea::HheaTable;
|
use otf::hhea::HheaTable;
|
||||||
use otf::hmtx::{HmtxTable, HorizontalMetrics};
|
use otf::hmtx::{HmtxTable, HorizontalMetrics};
|
||||||
|
|
|
@ -14,7 +14,7 @@ use error::GlError;
|
||||||
use euclid::Size2D;
|
use euclid::Size2D;
|
||||||
use gl::types::{GLsizeiptr, GLuint};
|
use gl::types::{GLsizeiptr, GLuint};
|
||||||
use gl;
|
use gl;
|
||||||
use otf::{self, Font};
|
use otf::{self, Font, PointKind};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ impl OutlineBuilder {
|
||||||
let mut point_index = self.vertices.len() as u32;
|
let mut point_index = self.vertices.len() as u32;
|
||||||
let start_index = self.indices.len() as u32;
|
let start_index = self.indices.len() as u32;
|
||||||
let start_point = point_index;
|
let start_point = point_index;
|
||||||
let mut last_point_on_curve = true;
|
let mut last_point_kind = PointKind::OnCurve;
|
||||||
|
|
||||||
try!(font.for_each_point(glyph_id, |point| {
|
try!(font.for_each_point(glyph_id, |point| {
|
||||||
self.vertices.push(Vertex {
|
self.vertices.push(Vertex {
|
||||||
|
@ -59,17 +59,22 @@ impl OutlineBuilder {
|
||||||
glyph_index: glyph_index,
|
glyph_index: glyph_index,
|
||||||
});
|
});
|
||||||
|
|
||||||
if point.index_in_contour > 0 && point.on_curve {
|
if point.index_in_contour > 0 && point.kind == PointKind::OnCurve {
|
||||||
let indices = if !last_point_on_curve {
|
let indices = match last_point_kind {
|
||||||
[point_index - 2, point_index - 1, point_index]
|
PointKind::FirstCubicControl => [0, 0, 0, 0],
|
||||||
} else {
|
PointKind::SecondCubicControl => {
|
||||||
[point_index - 1, 0, point_index]
|
[point_index - 3, point_index - 2, point_index - 1, point_index]
|
||||||
|
}
|
||||||
|
PointKind::QuadControl => {
|
||||||
|
[point_index - 2, point_index - 1, point_index - 1, point_index]
|
||||||
|
}
|
||||||
|
PointKind::OnCurve => [point_index - 1, 0, 0, point_index],
|
||||||
};
|
};
|
||||||
self.indices.extend(indices.iter().cloned());
|
self.indices.extend(indices.iter().cloned());
|
||||||
}
|
}
|
||||||
|
|
||||||
point_index += 1;
|
point_index += 1;
|
||||||
last_point_on_curve = point.on_curve
|
last_point_kind = point.kind
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Add a glyph descriptor.
|
// Add a glyph descriptor.
|
||||||
|
|
|
@ -273,7 +273,7 @@ impl Rasterizer {
|
||||||
|
|
||||||
gl::Uniform2ui(self.draw_atlas_size_uniform, rect.size.width, rect.size.height);
|
gl::Uniform2ui(self.draw_atlas_size_uniform, rect.size.width, rect.size.height);
|
||||||
|
|
||||||
gl::PatchParameteri(gl::PATCH_VERTICES, 3);
|
gl::PatchParameteri(gl::PATCH_VERTICES, 4);
|
||||||
|
|
||||||
// Use blending on our floating point framebuffer to accumulate coverage.
|
// Use blending on our floating point framebuffer to accumulate coverage.
|
||||||
gl::Enable(gl::BLEND);
|
gl::Enable(gl::BLEND);
|
||||||
|
|
Loading…
Reference in New Issue