Skip to content

Commit

Permalink
dev: remove some features
Browse files Browse the repository at this point in the history
  • Loading branch information
Myriad-Dreamin committed Sep 29, 2024
1 parent 190305b commit ec3cf92
Show file tree
Hide file tree
Showing 3 changed files with 6 additions and 223 deletions.
1 change: 0 additions & 1 deletion crates/conversion/vec2canvas/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ web-sys = { workspace = true, features = [
"Path2d",
"Blob",
"HtmlImageElement",
"HtmlDivElement",
"HtmlCanvasElement",
"Url",
"ImageData",
Expand Down
148 changes: 4 additions & 144 deletions crates/conversion/vec2canvas/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ use std::{cell::OnceCell, fmt::Debug, sync::Arc};

use tiny_skia as sk;

use wasm_bindgen::{JsCast, JsValue};
use web_sys::{CanvasRenderingContext2d, HtmlDivElement, HtmlImageElement, Path2d};
use wasm_bindgen::JsCast;
use web_sys::{CanvasRenderingContext2d, HtmlImageElement};

use reflexo::{
hash::Fingerprint,
vector::{
ir::{
self, Abs, Axes, FlatGlyphItem, FontIndice, FontItem, FontRef, Image, ImmutStr, Module,
Point, Ratio, Rect, Scalar, Size,
self, Abs, Axes, FontIndice, FontItem, FontRef, Image, ImmutStr, Module, Point, Ratio,
Rect, Scalar, Size,
},
vm::{GroupContext, RenderVm, TransformContext},
},
Expand Down Expand Up @@ -330,152 +330,12 @@ impl<'a> Drop for CanvasStateGuard<'a> {
}
}

/// Useful snippets for rendering parts of vector items to canvas.
pub struct CanvasRenderSnippets;

impl CanvasRenderSnippets {
fn put_glyph(
canvas: &web_sys::CanvasRenderingContext2d,
fill: &str,
glyph_item: &FlatGlyphItem,
ts: sk::Transform,
) {
let _guard = CanvasStateGuard::new(canvas);
if !set_transform(canvas, ts) {
return;
}
match &glyph_item {
FlatGlyphItem::Outline(path) => {
canvas.set_fill_style(&fill.into());
canvas.fill_with_path_2d(&Path2d::new_with_path_string(&path.d).unwrap());
}
FlatGlyphItem::Image(_glyph) => {
unimplemented!();
}
FlatGlyphItem::None => {}
}
}

/// Rasterize a text element to a image based on canvas.
pub fn rasterize_text<'a>(
fg: &Fingerprint,
glyphs: impl Iterator<Item = (Scalar, &'a FlatGlyphItem)>,
width: f32,
height: f32,
decender: f32,
fill: &str,
) -> String {
let Some(elem) = rasterize_text(*fg) else {
return Default::default();
};
let elem = elem.0;

let image_loaded = elem.get_attribute("data-typst-loaded-image");
if matches!(image_loaded, Some(t) if t == "true") {
return elem.outer_html();
}

let random_token = format!(
"text-{}",
js_sys::Math::random().to_string().replace('.', "")
);

// presentational text
elem.set_class_name(format!("typst-ptext {}", random_token).as_str());
elem.set_attribute("data-typst-loaded-image", "true")
.unwrap();

crate::utils::console_log!(
"rasterize_text {:?} {} {} {} {}",
fg,
fill,
width,
height,
decender
);

elem.set_attribute(
"style",
"width: 100%; height: 100%; background: transparent;",
)
.unwrap();

Self::rasterize_text_slow(
elem.clone(),
random_token,
glyphs,
width,
height,
decender,
fill,
);

elem.outer_html()
}

fn rasterize_text_slow<'a>(
elem: HtmlDivElement,
random_token: String,
glyphs: impl Iterator<Item = (Scalar, &'a FlatGlyphItem)>,
width: f32,
height: f32,
decender: f32,
fill: &str,
) {
const RATIO: f32 = 8f32;
let canvas = web_sys::window()
.unwrap()
.document()
.unwrap()
.create_element("canvas")
.unwrap()
.dyn_into::<web_sys::HtmlCanvasElement>()
.unwrap();
canvas.set_width((width / RATIO).ceil() as u32);
canvas.set_height(((height + decender) / RATIO).ceil() as u32);
let ctx = canvas
.get_context("2d")
.unwrap()
.unwrap()
.dyn_into::<web_sys::CanvasRenderingContext2d>()
.unwrap();

let ts = sk::Transform::from_scale(1. / RATIO, 1. / RATIO).pre_translate(0., decender);
for (pos, glyph) in glyphs {
Self::put_glyph(&ctx, fill, glyph, ts.pre_translate(pos.0, 0.));
}

// window.handleTextRasterized = function (canvas: HTMLCanvasElement, elem:
// Element, randomToken: string) get handle and call
let window = web_sys::window().unwrap();
if let Ok(proc) = js_sys::Reflect::get(&window, &JsValue::from_str("handleTextRasterized"))
{
proc.dyn_ref::<js_sys::Function>()
.unwrap()
.call3(&JsValue::NULL, &canvas, &elem, &random_token.into())
.unwrap();
}
}
}

// pub use backend::canvas::IncrCanvasDocClient;

#[derive(Debug, Clone)]
struct UnsafeMemorize<T>(T);

unsafe impl<T> Send for UnsafeMemorize<T> {}
unsafe impl<T> Sync for UnsafeMemorize<T> {}

#[comemo::memoize]
fn rasterize_text(_fg: Fingerprint) -> Option<UnsafeMemorize<HtmlDivElement>> {
let doc = web_sys::window()?.document()?;
doc.create_element("div")
.ok()?
.dyn_into()
.ok()
.map(UnsafeMemorize)
}

fn create_image() -> Option<HtmlImageElement> {
let doc = web_sys::window()?.document()?;
doc.create_element("img").ok()?.dyn_into().ok()
Expand Down
80 changes: 2 additions & 78 deletions crates/conversion/vec2svg/src/frontend/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,91 +200,15 @@ impl<'m, 't, Feat: ExportFeature> RenderVm<'m> for RenderContext<'m, 't, Feat> {
fn render_text(
&mut self,
group_ctx: Self::Group,
abs_ref: &Fingerprint,
_abs_ref: &Fingerprint,
text: &TextItem,
) -> Self::Group {
if self.should_rasterize_text() {
self.rasterize_and_put_text(group_ctx, abs_ref, text)
} else {
self.render_text_inplace(group_ctx, text)
}
self.render_text_inplace(group_ctx, text)
}
}

impl<'m, 't, Feat: ExportFeature> IncrRenderVm<'m> for RenderContext<'m, 't, Feat> {}

#[cfg(not(feature = "aggresive-browser-rasterization"))]
impl<'m, 't, Feat: ExportFeature> RenderContext<'m, 't, Feat> {
/// Raseterize the text and put it into the group context.
fn rasterize_and_put_text(
&mut self,
_group_ctx: SvgTextBuilder,
_abs_ref: &Fingerprint,
_text: &TextItem,
) -> SvgTextBuilder {
panic!("Rasterization is not enabled.")
}
}

#[cfg(feature = "aggresive-browser-rasterization")]
impl<'m, 't, Feat: ExportFeature> RenderContext<'m, 't, Feat> {
/// Raseterize the text and put it into the group context.
fn rasterize_and_put_text(
&mut self,
mut group_ctx: SvgTextBuilder,
abs_ref: &Fingerprint,
text: &TextItem,
) -> SvgTextBuilder {
use reflexo_vec2canvas::CanvasRenderSnippets;

let font = self.get_font(&text.shape.font).unwrap();

// upem is the unit per em defined in the font.
let upem = font.units_per_em;

group_ctx = text.shape.add_transform(self, group_ctx, upem);

//

let width = text.width();
let mut _width = 0f32;
let iter = text
.render_glyphs(upem, &mut _width)
.flat_map(|(pos, g)| font.get_glyph(g).map(|g| (pos, g.as_ref())));
let scaled_width = width.0 * upem.0 / text.shape.size.0;
let decender_adjust = (font.descender.0 * upem.0).abs();
// .max(0.)
let div_text = CanvasRenderSnippets::rasterize_text(
abs_ref,
iter,
scaled_width,
upem.0,
decender_adjust,
"#000",
);

group_ctx.content.push(SvgText::Plain(format!(
r#"<foreignObject width="{:.1}" height="{:.1}" x="0" y="{:.1}">{div_text}</foreignObject>"#,
scaled_width,
upem.0 + decender_adjust,
-decender_adjust,
)));

if self.should_render_text_element() {
group_ctx.render_text_semantics_inner(
&text.shape,
&text.content.content,
width,
font.ascender,
upem,
self.should_aware_html_entity(),
)
}

group_ctx
}
}

impl<'m, 't, Feat: ExportFeature> RenderContext<'m, 't, Feat> {
/// Render a text into the underlying context.
fn render_text_inplace(
Expand Down

0 comments on commit ec3cf92

Please sign in to comment.