Implement canvas text align
This commit is contained in:
parent
5974aeba7b
commit
607a518544
|
@ -20,10 +20,10 @@ use pathfinder_geometry::basic::transform2d::Transform2DF;
|
||||||
use pathfinder_geometry::color::ColorU;
|
use pathfinder_geometry::color::ColorU;
|
||||||
use pathfinder_geometry::outline::{Contour, Outline};
|
use pathfinder_geometry::outline::{Contour, Outline};
|
||||||
use pathfinder_geometry::stroke::{LineCap, LineJoin, OutlineStrokeToFill, StrokeStyle};
|
use pathfinder_geometry::stroke::{LineCap, LineJoin, OutlineStrokeToFill, StrokeStyle};
|
||||||
use pathfinder_renderer::paint::Paint;
|
use pathfinder_renderer::paint::{Paint, PaintId};
|
||||||
use pathfinder_renderer::scene::{PathObject, Scene};
|
use pathfinder_renderer::scene::{PathObject, Scene};
|
||||||
use pathfinder_text::{SceneExt, TextRenderMode};
|
use pathfinder_text::{SceneExt, TextRenderMode};
|
||||||
use skribo::{FontCollection, FontFamily, TextStyle};
|
use skribo::{FontCollection, FontFamily, Layout, TextStyle};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -80,48 +80,49 @@ impl CanvasRenderingContext2D {
|
||||||
// Drawing text
|
// Drawing text
|
||||||
|
|
||||||
pub fn fill_text(&mut self, string: &str, position: Point2DF) {
|
pub fn fill_text(&mut self, string: &str, position: Point2DF) {
|
||||||
// TODO(pcwalton): Report errors.
|
|
||||||
let paint_id = self.scene.push_paint(&self.current_state.fill_paint);
|
let paint_id = self.scene.push_paint(&self.current_state.fill_paint);
|
||||||
let transform = Transform2DF::from_translation(position).post_mul(&self.current_state
|
self.fill_or_stroke_text(string, position, paint_id, TextRenderMode::Fill);
|
||||||
.transform);
|
|
||||||
drop(self.scene.push_text(string,
|
|
||||||
&TextStyle { size: self.current_state.font_size },
|
|
||||||
&self.current_state.font_collection,
|
|
||||||
&transform,
|
|
||||||
TextRenderMode::Fill,
|
|
||||||
HintingOptions::None,
|
|
||||||
paint_id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stroke_text(&mut self, string: &str, position: Point2DF) {
|
pub fn stroke_text(&mut self, string: &str, position: Point2DF) {
|
||||||
// TODO(pcwalton): Report errors.
|
|
||||||
let paint_id = self.scene.push_paint(&self.current_state.stroke_paint);
|
let paint_id = self.scene.push_paint(&self.current_state.stroke_paint);
|
||||||
let transform = Transform2DF::from_translation(position).post_mul(&self.current_state
|
let render_mode = TextRenderMode::Stroke(self.current_state.stroke_style);
|
||||||
.transform);
|
self.fill_or_stroke_text(string, position, paint_id, render_mode);
|
||||||
drop(self.scene.push_text(string,
|
|
||||||
&TextStyle { size: self.current_state.font_size },
|
|
||||||
&self.current_state.font_collection,
|
|
||||||
&transform,
|
|
||||||
TextRenderMode::Stroke(self.current_state.stroke_style),
|
|
||||||
HintingOptions::None,
|
|
||||||
paint_id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn measure_text(&self, string: &str) -> TextMetrics {
|
pub fn measure_text(&self, string: &str) -> TextMetrics {
|
||||||
let layout = skribo::layout(&TextStyle { size: self.current_state.font_size },
|
TextMetrics { width: self.layout_text(string).width() }
|
||||||
&self.current_state.font_collection,
|
}
|
||||||
string);
|
|
||||||
let width = match layout.glyphs.last() {
|
fn fill_or_stroke_text(&mut self,
|
||||||
None => 0.0,
|
string: &str,
|
||||||
Some(last_glyph) => {
|
mut position: Point2DF,
|
||||||
let glyph_id = last_glyph.glyph_id;
|
paint_id: PaintId,
|
||||||
let font_metrics = last_glyph.font.font.metrics();
|
render_mode: TextRenderMode) {
|
||||||
let glyph_rect = last_glyph.font.font.typographic_bounds(glyph_id).unwrap();
|
let layout = self.layout_text(string);
|
||||||
let scale_factor = layout.size / font_metrics.units_per_em as f32;
|
|
||||||
last_glyph.offset.x + glyph_rect.max_x() * scale_factor
|
match self.current_state.text_align {
|
||||||
}
|
TextAlign::Left => {},
|
||||||
};
|
TextAlign::Right => position.set_x(position.x() - layout.width()),
|
||||||
TextMetrics { width }
|
TextAlign::Center => position.set_x(position.x() - layout.width() * 0.5),
|
||||||
|
}
|
||||||
|
|
||||||
|
let transform = Transform2DF::from_translation(position).post_mul(&self.current_state
|
||||||
|
.transform);
|
||||||
|
|
||||||
|
// TODO(pcwalton): Report errors.
|
||||||
|
drop(self.scene.push_layout(&layout,
|
||||||
|
&TextStyle { size: self.current_state.font_size },
|
||||||
|
&transform,
|
||||||
|
render_mode,
|
||||||
|
HintingOptions::None,
|
||||||
|
paint_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layout_text(&self, string: &str) -> Layout {
|
||||||
|
skribo::layout(&TextStyle { size: self.current_state.font_size },
|
||||||
|
&self.current_state.font_collection,
|
||||||
|
string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Line styles
|
// Line styles
|
||||||
|
@ -158,6 +159,11 @@ impl CanvasRenderingContext2D {
|
||||||
self.current_state.font_size = new_font_size;
|
self.current_state.font_size = new_font_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_text_align(&mut self, new_text_align: TextAlign) {
|
||||||
|
self.current_state.text_align = new_text_align;
|
||||||
|
}
|
||||||
|
|
||||||
// Drawing paths
|
// Drawing paths
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -236,6 +242,7 @@ pub struct State {
|
||||||
transform: Transform2DF,
|
transform: Transform2DF,
|
||||||
font_collection: Arc<FontCollection>,
|
font_collection: Arc<FontCollection>,
|
||||||
font_size: f32,
|
font_size: f32,
|
||||||
|
text_align: TextAlign,
|
||||||
fill_paint: Paint,
|
fill_paint: Paint,
|
||||||
stroke_paint: Paint,
|
stroke_paint: Paint,
|
||||||
stroke_style: StrokeStyle,
|
stroke_style: StrokeStyle,
|
||||||
|
@ -248,6 +255,7 @@ impl State {
|
||||||
transform: Transform2DF::default(),
|
transform: Transform2DF::default(),
|
||||||
font_collection: default_font_collection,
|
font_collection: default_font_collection,
|
||||||
font_size: DEFAULT_FONT_SIZE,
|
font_size: DEFAULT_FONT_SIZE,
|
||||||
|
text_align: TextAlign::Left,
|
||||||
fill_paint: Paint { color: ColorU::black() },
|
fill_paint: Paint { color: ColorU::black() },
|
||||||
stroke_paint: Paint { color: ColorU::black() },
|
stroke_paint: Paint { color: ColorU::black() },
|
||||||
stroke_style: StrokeStyle::default(),
|
stroke_style: StrokeStyle::default(),
|
||||||
|
@ -340,6 +348,13 @@ impl FillStyle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum TextAlign {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Center,
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): Support other fields.
|
// TODO(pcwalton): Support other fields.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct TextMetrics {
|
pub struct TextMetrics {
|
||||||
|
@ -373,3 +388,24 @@ impl CanvasFontContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Text layout utilities
|
||||||
|
|
||||||
|
trait LayoutExt {
|
||||||
|
fn width(&self) -> f32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LayoutExt for Layout {
|
||||||
|
fn width(&self) -> f32 {
|
||||||
|
let last_glyph = match self.glyphs.last() {
|
||||||
|
None => return 0.0,
|
||||||
|
Some(last_glyph) => last_glyph,
|
||||||
|
};
|
||||||
|
|
||||||
|
let glyph_id = last_glyph.glyph_id;
|
||||||
|
let font_metrics = last_glyph.font.font.metrics();
|
||||||
|
let glyph_rect = last_glyph.font.font.typographic_bounds(glyph_id).unwrap();
|
||||||
|
let scale_factor = self.size / font_metrics.units_per_em as f32;
|
||||||
|
last_glyph.offset.x + glyph_rect.max_x() * scale_factor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D};
|
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, TextAlign};
|
||||||
use pathfinder_geometry::basic::point::{Point2DF, Point2DI};
|
use pathfinder_geometry::basic::point::{Point2DF, Point2DI};
|
||||||
use pathfinder_geometry::color::ColorF;
|
use pathfinder_geometry::color::ColorF;
|
||||||
use pathfinder_gl::{GLDevice, GLVersion};
|
use pathfinder_gl::{GLDevice, GLVersion};
|
||||||
|
@ -58,7 +58,8 @@ fn main() {
|
||||||
// Draw the text.
|
// Draw the text.
|
||||||
canvas.set_font_size(32.0);
|
canvas.set_font_size(32.0);
|
||||||
canvas.fill_text("Hello Pathfinder!", Point2DF::new(32.0, 48.0));
|
canvas.fill_text("Hello Pathfinder!", Point2DF::new(32.0, 48.0));
|
||||||
canvas.stroke_text("Goodbye Pathfinder!", Point2DF::new(32.0, 96.0));
|
canvas.set_text_align(TextAlign::Right);
|
||||||
|
canvas.stroke_text("Goodbye Pathfinder!", Point2DF::new(608.0, 464.0));
|
||||||
|
|
||||||
// Render the canvas to screen.
|
// Render the canvas to screen.
|
||||||
let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor);
|
let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor);
|
||||||
|
|
Loading…
Reference in New Issue