Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a simple implementation of CanvasRenderingContext2d.fillText #25782

Merged
merged 2 commits into from Mar 19, 2020
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Some generated files are not rendered by default. Learn more.

@@ -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()

This comment has been minimized.

Copy link
@pcwalton

pcwalton Feb 21, 2020

Contributor

Needs a TODO because this should eventually use the same infrastructure as layout (i.e. layout should be updated to use font-kit as well).

This comment has been minimized.

Copy link
@pcwalton

pcwalton Feb 21, 2020

Contributor

Also, this is in the chrome process, right? It needs to not be in the content process because the content process shouldn't have access to the SystemSource. (It's too dangerous; on macOS for example it needs a connection to the font server, which has had a lot of security vulnerabilities.)

This comment has been minimized.

Copy link
@jdm

jdm Feb 21, 2020

Member

Yes, the canvas code runs in the chrome process.

This comment has been minimized.

Copy link
@kaiakz

kaiakz Feb 22, 2020

Author Contributor

So, I need to do:

  1. add a TODO to raqote_backend.rs
  2. move font_kit code from raqote_backend.rs to canvas_data.rs and pass the SystemSource things through` the parameter?(Well, my code made some compromised, since I am not familiar with all components.)

Also, this is in the chrome process, right? It needs to not be in the content process because the content process shouldn't have access to the SystemSource.

I noticed there is a FontCacheThread, maybe I can use it?

This comment has been minimized.

Copy link
@jdm

jdm Feb 24, 2020

Member

Let's keep the font_kit code in raqote_backend.rs for now until it's more clear how the proper font integration will work. The FontCacheThread is integrated with many other parts of the system, so converting that code to use font_kit will be part of resolving that TODO.

This comment has been minimized.

Copy link
@kaiakz

kaiakz Feb 25, 2020

Author Contributor

@jdm
If I understood well, I moved all font_kit code to raqote_backend.rs, including some functions:
replace_whitespace & get_text_width( They are parts of text preparation algorithm, in fact, I just moved the algorithm to raqote_backend.rs).

I would like to do the converting if have any spare time. 😄

.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(())
}

This file was deleted.

This file was deleted.

@@ -0,0 +1,2 @@
[canvas_text_font_001.htm]
expected: FAIL

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.