mirror of
https://github.com/servo/servo.git
synced 2025-07-08 16:03:40 +01:00
Auto merge of #25782 - kaiakz:master, r=jdm
Add a simple implementation of CanvasRenderingContext2d.fillText <!-- Please describe your changes on the following line: --> I added a simple implementation of CanvasRenderingContext2d.fillText. Some code are merged from @mikrut, and I fixed a bug about text scaling. Also, the bug of text rotation should be fixed after `raqote` merged my other PR. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix (part of) #11681 (GitHub issue number if applicable) <!-- Either: --> - [X] There are tests for these changes <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
commit
ffdb83b644
11 changed files with 111 additions and 32 deletions
|
@ -44,3 +44,4 @@ webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]}
|
|||
surfman = { version = "0.1", features = ["sm-angle", "sm-osmesa"] }
|
||||
surfman-chains = "0.3"
|
||||
surfman-chains-api = "0.2"
|
||||
font-kit = "0.5.0"
|
||||
|
|
|
@ -266,6 +266,15 @@ pub trait GenericDrawTarget {
|
|||
);
|
||||
fn fill(&mut self, path: &Path, pattern: Pattern, draw_options: &DrawOptions);
|
||||
fn fill_rect(&mut self, rect: &Rect<f32>, pattern: Pattern, draw_options: Option<&DrawOptions>);
|
||||
fn fill_text(
|
||||
&mut self,
|
||||
text: String,
|
||||
x: f32,
|
||||
y: f32,
|
||||
max_width: Option<f64>,
|
||||
pattern: Pattern,
|
||||
draw_options: &DrawOptions,
|
||||
);
|
||||
fn get_format(&self) -> SurfaceFormat;
|
||||
fn get_size(&self) -> Size2D<i32>;
|
||||
fn get_transform(&self) -> Transform2D<f32>;
|
||||
|
@ -458,10 +467,19 @@ impl<'a> CanvasData<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fill_text(&self, text: String, x: f64, y: f64, max_width: Option<f64>) {
|
||||
error!(
|
||||
"Unimplemented canvas2d.fillText. Values received: {}, {}, {}, {:?}.",
|
||||
text, x, y, max_width
|
||||
pub fn fill_text(&mut self, text: String, x: f64, y: f64, max_width: Option<f64>) {
|
||||
// If any of the arguments are infinite or NaN, then return.
|
||||
if !x.is_finite() || !y.is_finite() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.drawtarget.fill_text(
|
||||
text,
|
||||
x as f32,
|
||||
y as f32,
|
||||
max_width,
|
||||
self.state.fill_style.clone(),
|
||||
&self.state.draw_options,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,9 @@ use canvas_traits::canvas::*;
|
|||
use cssparser::RGBA;
|
||||
use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D};
|
||||
use euclid::Angle;
|
||||
use font_kit::family_name::FamilyName;
|
||||
use font_kit::properties::Properties;
|
||||
use font_kit::source::SystemSource;
|
||||
use lyon_geom::Arc;
|
||||
use raqote::PathOp;
|
||||
use std::marker::PhantomData;
|
||||
|
@ -539,6 +542,84 @@ impl GenericDrawTarget for raqote::DrawTarget {
|
|||
&DrawOptions::Raqote(draw_options),
|
||||
);
|
||||
}
|
||||
// TODO
|
||||
// This should eventually use the same infrastructure as layout
|
||||
// (i.e. layout should be updated to use font-kit as well).
|
||||
// Need to implement .font .
|
||||
fn fill_text(
|
||||
&mut self,
|
||||
text: String,
|
||||
x: f32,
|
||||
y: f32,
|
||||
max_width: Option<f64>,
|
||||
pattern: canvas_data::Pattern,
|
||||
draw_options: &DrawOptions,
|
||||
) {
|
||||
// Replace all ASCII whitespace in text with U+0020 SPACE characters.
|
||||
fn replace_whitespace(text: String) -> String {
|
||||
text.chars()
|
||||
.map(|c| match c {
|
||||
'\x09'..='\x0D' => '\x20',
|
||||
_ => c,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
// Compute the width of the text
|
||||
fn get_text_width(text: &str, font: &font_kit::font::Font) -> f64 {
|
||||
let point_size = 24.;
|
||||
let mut length = 0.;
|
||||
for c in text.chars() {
|
||||
let id = font.glyph_for_char(c).unwrap();
|
||||
length += (font.advance(id).unwrap() * point_size / 24. / 96.).x;
|
||||
}
|
||||
length as f64
|
||||
}
|
||||
|
||||
let font = SystemSource::new()
|
||||
.select_best_match(&[FamilyName::SansSerif], &Properties::new())
|
||||
.unwrap()
|
||||
.load()
|
||||
.unwrap();
|
||||
|
||||
// text preparation algorithm
|
||||
let (scale_factor, replaced_text) = match max_width {
|
||||
Some(value) => {
|
||||
if value <= 0. || !value.is_finite() {
|
||||
return;
|
||||
} else {
|
||||
let replaced_text = replace_whitespace(text);
|
||||
let text_width = get_text_width(&replaced_text, &font);
|
||||
if value > text_width {
|
||||
(1., replaced_text)
|
||||
} else {
|
||||
(value / text_width, replaced_text)
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => (1., replace_whitespace(text)),
|
||||
};
|
||||
|
||||
// Text scaling
|
||||
let old_transform = self.get_transform().clone();
|
||||
let new_transform = old_transform
|
||||
.pre_translate(Vector2D::new(x as f32, 0.))
|
||||
.pre_scale(scale_factor as f32, 1.)
|
||||
.pre_translate(Vector2D::new(-x as f32, 0.));
|
||||
self.set_transform(&new_transform);
|
||||
|
||||
self.draw_text(
|
||||
&font,
|
||||
24.,
|
||||
&replaced_text,
|
||||
Point2D::new(x, y),
|
||||
&pattern.source(),
|
||||
draw_options.as_raqote(),
|
||||
);
|
||||
|
||||
// Restore the transform
|
||||
self.set_transform(&old_transform);
|
||||
}
|
||||
fn get_format(&self) -> SurfaceFormat {
|
||||
SurfaceFormat::Raqote(())
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue