blitz-pdf 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -3
- package/THIRD_PARTY_NOTICES.md +2 -0
- package/dist/api.d.ts +9 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +25 -27
- package/dist/api.js.map +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +13 -1
- package/dist/browser.js.map +1 -1
- package/dist/node-worker.d.ts +2 -0
- package/dist/node-worker.d.ts.map +1 -0
- package/dist/node-worker.js +10 -0
- package/dist/node-worker.js.map +1 -0
- package/dist/node.d.ts +1 -1
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +18 -6
- package/dist/node.js.map +1 -1
- package/dist/render.d.ts +8 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +28 -0
- package/dist/render.js.map +1 -0
- package/dist/wasm.d.ts +3 -0
- package/dist/wasm.d.ts.map +1 -0
- package/dist/wasm.js +18 -0
- package/dist/wasm.js.map +1 -0
- package/dist/worker-host.d.ts +16 -0
- package/dist/worker-host.d.ts.map +1 -0
- package/dist/worker-host.js +31 -0
- package/dist/worker-host.js.map +1 -0
- package/dist/worker-protocol.d.ts +22 -0
- package/dist/worker-protocol.d.ts.map +1 -0
- package/dist/worker-protocol.js +2 -0
- package/dist/worker-protocol.js.map +1 -0
- package/dist/worker-runtime.d.ts +8 -0
- package/dist/worker-runtime.d.ts.map +1 -0
- package/dist/worker-runtime.js +34 -0
- package/dist/worker-runtime.js.map +1 -0
- package/dist/worker.d.ts +2 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +7 -0
- package/dist/worker.js.map +1 -0
- package/package.json +5 -2
- package/src/api.ts +33 -22
- package/src/browser.ts +13 -3
- package/src/node-worker.ts +9 -0
- package/src/node.ts +13 -4
- package/src/render.ts +28 -0
- package/src/wasm.ts +17 -0
- package/src/worker-host.ts +45 -0
- package/src/worker-protocol.ts +10 -0
- package/src/worker-runtime.ts +35 -0
- package/src/worker.ts +12 -0
- package/vendor/README.md +24 -0
- package/vendor/blitz-paint/Cargo.toml +50 -0
- package/vendor/blitz-paint/LICENSE-APACHE +176 -0
- package/vendor/blitz-paint/LICENSE-MIT +23 -0
- package/vendor/blitz-paint/src/color.rs +66 -0
- package/vendor/blitz-paint/src/debug_overlay.rs +168 -0
- package/vendor/blitz-paint/src/filters.rs +40 -0
- package/vendor/blitz-paint/src/gradient.rs +536 -0
- package/vendor/blitz-paint/src/kurbo_css/css_box.rs +847 -0
- package/vendor/blitz-paint/src/kurbo_css/mod.rs +77 -0
- package/vendor/blitz-paint/src/kurbo_css/non_uniform_radii.rs +60 -0
- package/vendor/blitz-paint/src/layers.rs +95 -0
- package/vendor/blitz-paint/src/lib.rs +190 -0
- package/vendor/blitz-paint/src/render/background.rs +968 -0
- package/vendor/blitz-paint/src/render/border.rs +631 -0
- package/vendor/blitz-paint/src/render/box_shadow.rs +157 -0
- package/vendor/blitz-paint/src/render/clip_path.rs +492 -0
- package/vendor/blitz-paint/src/render/form_controls.rs +103 -0
- package/vendor/blitz-paint/src/render/mask.rs +144 -0
- package/vendor/blitz-paint/src/render.rs +1351 -0
- package/vendor/blitz-paint/src/sizing.rs +63 -0
- package/vendor/blitz-paint/src/text.rs +747 -0
- package/wasm/blitz_pdf_bg.wasm +0 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
//! A rounded rect closer to the browser
|
|
2
|
+
//! Implemented in such a way that splits the border into 4 parts at the midway of each radius
|
|
3
|
+
//!
|
|
4
|
+
//! This object is meant to be updated only when the data changes - BezPaths are expensive!
|
|
5
|
+
//!
|
|
6
|
+
//! Can I just say, this is a lot of work for a border
|
|
7
|
+
//! HTML/css is annoyingly wild
|
|
8
|
+
|
|
9
|
+
use kurbo::{Insets, Vec2};
|
|
10
|
+
|
|
11
|
+
mod css_box;
|
|
12
|
+
mod non_uniform_radii;
|
|
13
|
+
|
|
14
|
+
pub use css_box::CssBox;
|
|
15
|
+
pub use non_uniform_radii::NonUniformRoundedRectRadii;
|
|
16
|
+
|
|
17
|
+
#[derive(Debug, Clone, Copy)]
|
|
18
|
+
pub enum Edge {
|
|
19
|
+
Top,
|
|
20
|
+
Right,
|
|
21
|
+
Bottom,
|
|
22
|
+
Left,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#[derive(Debug, Clone, Copy)]
|
|
26
|
+
pub(crate) enum Corner {
|
|
27
|
+
TopLeft,
|
|
28
|
+
TopRight,
|
|
29
|
+
BottomLeft,
|
|
30
|
+
BottomRight,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
34
|
+
#[allow(clippy::enum_variant_names, reason = "Use CSS standard terminology")]
|
|
35
|
+
pub(crate) enum CssBoxKind {
|
|
36
|
+
OutlineBox,
|
|
37
|
+
BorderBox,
|
|
38
|
+
PaddingBox,
|
|
39
|
+
ContentBox,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#[derive(Debug, Clone, Copy)]
|
|
43
|
+
pub(crate) enum Direction {
|
|
44
|
+
Clockwise,
|
|
45
|
+
Anticlockwise,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fn add_insets(a: Insets, b: Insets) -> Insets {
|
|
49
|
+
Insets {
|
|
50
|
+
x0: a.x0 + b.x0,
|
|
51
|
+
y0: a.y0 + b.y0,
|
|
52
|
+
x1: a.x1 + b.x1,
|
|
53
|
+
y1: a.y1 + b.y1,
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
#[inline(always)]
|
|
58
|
+
fn get_corner_insets(insets: Insets, corner: Corner) -> Vec2 {
|
|
59
|
+
match corner {
|
|
60
|
+
Corner::TopLeft => Vec2 {
|
|
61
|
+
x: insets.x0,
|
|
62
|
+
y: insets.y0,
|
|
63
|
+
},
|
|
64
|
+
Corner::TopRight => Vec2 {
|
|
65
|
+
x: insets.x1,
|
|
66
|
+
y: insets.y0,
|
|
67
|
+
},
|
|
68
|
+
Corner::BottomLeft => Vec2 {
|
|
69
|
+
x: insets.x0,
|
|
70
|
+
y: insets.y1,
|
|
71
|
+
},
|
|
72
|
+
Corner::BottomRight => Vec2 {
|
|
73
|
+
x: insets.x1,
|
|
74
|
+
y: insets.y1,
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
use kurbo::Vec2;
|
|
2
|
+
use std::ops::{Mul, MulAssign};
|
|
3
|
+
|
|
4
|
+
/// Radii for each corner of a non-uniform rounded rectangle.
|
|
5
|
+
///
|
|
6
|
+
/// The use of `top` as in `top_left` assumes a y-down coordinate space. Piet
|
|
7
|
+
/// (and Druid by extension) uses a y-down coordinate space, but Kurbo also
|
|
8
|
+
/// supports a y-up coordinate space, in which case `top_left` would actually
|
|
9
|
+
/// refer to the bottom-left corner, and vice versa. Top may not always
|
|
10
|
+
/// actually be the top, but `top` corners will always have a smaller y-value
|
|
11
|
+
/// than `bottom` corners.
|
|
12
|
+
#[derive(Clone, Copy, Default, Debug, PartialEq)]
|
|
13
|
+
// #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
|
14
|
+
// #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
15
|
+
pub struct NonUniformRoundedRectRadii {
|
|
16
|
+
/// The radii of the top-left corner.
|
|
17
|
+
pub top_left: Vec2,
|
|
18
|
+
/// The radii of the top-right corner.
|
|
19
|
+
pub top_right: Vec2,
|
|
20
|
+
/// The radii of the bottom-right corner.
|
|
21
|
+
pub bottom_right: Vec2,
|
|
22
|
+
/// The radii of the bottom-left corner.
|
|
23
|
+
pub bottom_left: Vec2,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
impl NonUniformRoundedRectRadii {
|
|
27
|
+
pub fn average(&self) -> f64 {
|
|
28
|
+
(self.top_left.x
|
|
29
|
+
+ self.top_left.y
|
|
30
|
+
+ self.top_right.x
|
|
31
|
+
+ self.top_right.y
|
|
32
|
+
+ self.bottom_left.x
|
|
33
|
+
+ self.bottom_left.y
|
|
34
|
+
+ self.bottom_right.x
|
|
35
|
+
+ self.bottom_right.y)
|
|
36
|
+
/ 8.0
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
impl Mul<f64> for NonUniformRoundedRectRadii {
|
|
41
|
+
type Output = Self;
|
|
42
|
+
|
|
43
|
+
fn mul(self, rhs: f64) -> Self::Output {
|
|
44
|
+
Self {
|
|
45
|
+
top_left: self.top_left * rhs,
|
|
46
|
+
top_right: self.top_right * rhs,
|
|
47
|
+
bottom_right: self.bottom_right * rhs,
|
|
48
|
+
bottom_left: self.bottom_left * rhs,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
impl MulAssign<f64> for NonUniformRoundedRectRadii {
|
|
54
|
+
fn mul_assign(&mut self, rhs: f64) {
|
|
55
|
+
self.top_left *= rhs;
|
|
56
|
+
self.top_right *= rhs;
|
|
57
|
+
self.bottom_left *= rhs;
|
|
58
|
+
self.bottom_right *= rhs;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
use anyrender::{Filter, PaintScene};
|
|
2
|
+
use kurbo::{Affine, Shape};
|
|
3
|
+
use peniko::{Fill, Mix};
|
|
4
|
+
use std::{cell::Cell, sync::Arc};
|
|
5
|
+
|
|
6
|
+
const LAYER_LIMIT: u32 = 1024;
|
|
7
|
+
|
|
8
|
+
#[derive(Default)]
|
|
9
|
+
pub(crate) struct LayerManager {
|
|
10
|
+
layers_used: Cell<u32>,
|
|
11
|
+
layer_depth: Cell<u32>,
|
|
12
|
+
layers_wanted: Cell<u32>,
|
|
13
|
+
|
|
14
|
+
#[allow(unused)] // Only used for debugging. Enabled as required.
|
|
15
|
+
layer_depth_used: Cell<u32>,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
impl LayerManager {
|
|
19
|
+
#[allow(clippy::too_many_arguments)]
|
|
20
|
+
pub(crate) fn maybe_with_layer<S: PaintScene, F: FnOnce(&mut S)>(
|
|
21
|
+
&self,
|
|
22
|
+
scene: &mut S,
|
|
23
|
+
condition: bool,
|
|
24
|
+
opacity: f32,
|
|
25
|
+
transform: Affine,
|
|
26
|
+
shape: &impl Shape,
|
|
27
|
+
filter: Option<Arc<Filter>>,
|
|
28
|
+
backdrop_filter: Option<Arc<Filter>>,
|
|
29
|
+
paint_layer: F,
|
|
30
|
+
) {
|
|
31
|
+
let layer_used = self.maybe_push_layer(
|
|
32
|
+
scene,
|
|
33
|
+
condition,
|
|
34
|
+
opacity,
|
|
35
|
+
transform,
|
|
36
|
+
shape,
|
|
37
|
+
filter,
|
|
38
|
+
backdrop_filter,
|
|
39
|
+
);
|
|
40
|
+
paint_layer(scene);
|
|
41
|
+
self.maybe_pop_layer(scene, layer_used);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#[allow(clippy::too_many_arguments)]
|
|
45
|
+
pub(crate) fn maybe_push_layer(
|
|
46
|
+
&self,
|
|
47
|
+
scene: &mut impl PaintScene,
|
|
48
|
+
condition: bool,
|
|
49
|
+
opacity: f32,
|
|
50
|
+
transform: Affine,
|
|
51
|
+
shape: &impl Shape,
|
|
52
|
+
filter: Option<Arc<Filter>>,
|
|
53
|
+
backdrop_filter: Option<Arc<Filter>>,
|
|
54
|
+
) -> bool {
|
|
55
|
+
if !condition {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
self.layers_wanted.update(|x| x + 1);
|
|
59
|
+
|
|
60
|
+
// Check if clips are above limit
|
|
61
|
+
let layers_available = self.layers_used.get() <= LAYER_LIMIT;
|
|
62
|
+
if !layers_available {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Actually push the layer
|
|
67
|
+
if opacity == 1.0 && filter.is_none() && backdrop_filter.is_none() {
|
|
68
|
+
scene.push_clip_layer(Fill::NonZero, transform, shape);
|
|
69
|
+
} else {
|
|
70
|
+
scene.push_layer(
|
|
71
|
+
Fill::NonZero,
|
|
72
|
+
Mix::Normal,
|
|
73
|
+
opacity,
|
|
74
|
+
transform,
|
|
75
|
+
shape,
|
|
76
|
+
filter,
|
|
77
|
+
backdrop_filter,
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Update accounting
|
|
82
|
+
self.layers_used.update(|x| x + 1);
|
|
83
|
+
self.layer_depth.update(|x| x + 1);
|
|
84
|
+
self.layer_depth.update(|x| x.max(self.layer_depth.get()));
|
|
85
|
+
|
|
86
|
+
true
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
pub(crate) fn maybe_pop_layer(&self, scene: &mut impl PaintScene, condition: bool) {
|
|
90
|
+
if condition {
|
|
91
|
+
scene.pop_layer();
|
|
92
|
+
self.layer_depth.update(|x| x - 1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
//! Paint a [`blitz_dom::BaseDocument`] by pushing [`anyrender`] drawing commands into
|
|
2
|
+
//! an impl [`anyrender::PaintScene`].
|
|
3
|
+
|
|
4
|
+
#![allow(clippy::collapsible_if)]
|
|
5
|
+
|
|
6
|
+
mod color;
|
|
7
|
+
mod debug_overlay;
|
|
8
|
+
mod filters;
|
|
9
|
+
mod gradient;
|
|
10
|
+
mod kurbo_css;
|
|
11
|
+
mod layers;
|
|
12
|
+
mod render;
|
|
13
|
+
mod sizing;
|
|
14
|
+
mod text;
|
|
15
|
+
|
|
16
|
+
use std::{cell::RefCell, collections::HashMap};
|
|
17
|
+
|
|
18
|
+
use anyrender::{PaintScene, Scene};
|
|
19
|
+
use blitz_dom::{BaseDocument, NodeId, util::Color};
|
|
20
|
+
use render::BlitzDomPainter;
|
|
21
|
+
|
|
22
|
+
const FONT_EMBOLDEN_ENABLED: bool = cfg!(any(
|
|
23
|
+
feature = "font-embolden",
|
|
24
|
+
all(feature = "apple-font-embolden", target_os = "macos"),
|
|
25
|
+
all(feature = "apple-font-embolden", target_os = "ios"),
|
|
26
|
+
));
|
|
27
|
+
|
|
28
|
+
/// The default color for text selection highlights
|
|
29
|
+
const SELECTION_COLOR: Color = Color::from_rgb8(180, 213, 255);
|
|
30
|
+
|
|
31
|
+
/// Pre-computed `Scene`s for each CustomWidget, keyed by `(document id, node id)`
|
|
32
|
+
type CustomWidgetSceneMap = HashMap<(usize, NodeId), Scene>;
|
|
33
|
+
|
|
34
|
+
/// Receives each text layout immediately before its glyphs are painted, in paint
|
|
35
|
+
/// order. Vector exporters can retain Unicode and cluster mappings without
|
|
36
|
+
/// attempting to identify source text from glyph shapes or DOM traversal order.
|
|
37
|
+
pub trait TextObserver {
|
|
38
|
+
fn observe(&mut self, layout: &parley::Layout<blitz_dom::node::TextBrush>, text: &str);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// Paint a [`blitz_dom::BaseDocument`] by pushing drawing commands into
|
|
42
|
+
/// an impl [`anyrender::PaintScene`].
|
|
43
|
+
///
|
|
44
|
+
/// This function assumes that the styles and layout in the [`BaseDocument`] are already
|
|
45
|
+
/// resolved. Please ensure that this is the case before trying to paint.
|
|
46
|
+
///
|
|
47
|
+
/// The implementation of [`PaintScene`] is responsible for handling the commands that are pushed into it.
|
|
48
|
+
/// Generally this will involve executing them to draw a rasterized image/texture. But in some cases it may choose to
|
|
49
|
+
/// transform them to a vector format (e.g. SVG/PDF) or serialize them in raw form for later use.
|
|
50
|
+
pub fn paint_scene(
|
|
51
|
+
scene: &mut impl PaintScene,
|
|
52
|
+
doc: &mut BaseDocument,
|
|
53
|
+
scale: f64,
|
|
54
|
+
width: u32,
|
|
55
|
+
height: u32,
|
|
56
|
+
x_offset: u32,
|
|
57
|
+
y_offset: u32,
|
|
58
|
+
) {
|
|
59
|
+
paint_scene_impl(scene, doc, scale, width, height, x_offset, y_offset, None);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/// Paint with source text notifications. The observer is also forwarded to
|
|
63
|
+
/// subdocuments. Existing raster backends can continue using [`paint_scene`].
|
|
64
|
+
#[allow(clippy::too_many_arguments)]
|
|
65
|
+
pub fn paint_scene_with_text(
|
|
66
|
+
scene: &mut impl PaintScene,
|
|
67
|
+
doc: &mut BaseDocument,
|
|
68
|
+
scale: f64,
|
|
69
|
+
width: u32,
|
|
70
|
+
height: u32,
|
|
71
|
+
x_offset: u32,
|
|
72
|
+
y_offset: u32,
|
|
73
|
+
observer: &RefCell<dyn TextObserver>,
|
|
74
|
+
) {
|
|
75
|
+
paint_scene_impl(
|
|
76
|
+
scene,
|
|
77
|
+
doc,
|
|
78
|
+
scale,
|
|
79
|
+
width,
|
|
80
|
+
height,
|
|
81
|
+
x_offset,
|
|
82
|
+
y_offset,
|
|
83
|
+
Some(observer),
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
#[allow(clippy::too_many_arguments)]
|
|
88
|
+
fn paint_scene_impl(
|
|
89
|
+
scene: &mut impl PaintScene,
|
|
90
|
+
doc: &mut BaseDocument,
|
|
91
|
+
scale: f64,
|
|
92
|
+
width: u32,
|
|
93
|
+
height: u32,
|
|
94
|
+
x_offset: u32,
|
|
95
|
+
y_offset: u32,
|
|
96
|
+
observer: Option<&RefCell<dyn TextObserver>>,
|
|
97
|
+
) {
|
|
98
|
+
// Run `.paint()` on every custom widget in the document (and all subdocuments) ahead of time.
|
|
99
|
+
// This helps us avoid borrow-checker issues as we recurse down the tree (`.paint()` require `&mut self`).
|
|
100
|
+
//
|
|
101
|
+
// TODO: Take widget and sub-document visibility into account
|
|
102
|
+
#[allow(unused_mut)]
|
|
103
|
+
let mut custom_widget_scenes: CustomWidgetSceneMap = HashMap::new();
|
|
104
|
+
#[cfg(feature = "custom-widget")]
|
|
105
|
+
build_custom_widget_scenes(&mut custom_widget_scenes, doc, scene, scale);
|
|
106
|
+
|
|
107
|
+
let generator = BlitzDomPainter::new(
|
|
108
|
+
doc,
|
|
109
|
+
scale,
|
|
110
|
+
width,
|
|
111
|
+
height,
|
|
112
|
+
x_offset as f64,
|
|
113
|
+
y_offset as f64,
|
|
114
|
+
&custom_widget_scenes,
|
|
115
|
+
observer,
|
|
116
|
+
);
|
|
117
|
+
generator.paint_scene(scene);
|
|
118
|
+
|
|
119
|
+
// println!(
|
|
120
|
+
// "Rendered using {} clips (depth: {}) (wanted: {})",
|
|
121
|
+
// CLIPS_USED.load(atomic::Ordering::SeqCst),
|
|
122
|
+
// CLIP_DEPTH_USED.load(atomic::Ordering::SeqCst),
|
|
123
|
+
// CLIPS_WANTED.load(atomic::Ordering::SeqCst)
|
|
124
|
+
// );
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
#[cfg(feature = "custom-widget")]
|
|
128
|
+
fn build_custom_widget_scenes(
|
|
129
|
+
custom_widget_scenes: &mut CustomWidgetSceneMap,
|
|
130
|
+
doc: &mut BaseDocument,
|
|
131
|
+
render_ctx: &mut impl anyrender::RenderContext,
|
|
132
|
+
scale: f64,
|
|
133
|
+
) {
|
|
134
|
+
let doc_id = doc.id();
|
|
135
|
+
|
|
136
|
+
// Process scenes for every custom widget in the document
|
|
137
|
+
let custom_widget_node_ids = doc.custom_widget_node_ids();
|
|
138
|
+
for node_id in custom_widget_node_ids.into_iter() {
|
|
139
|
+
if let Some(scene) = process_custom_widget_node(doc, render_ctx, node_id, scale) {
|
|
140
|
+
custom_widget_scenes.insert((doc_id, node_id), scene);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Recurse into sub documents
|
|
145
|
+
let sub_document_node_ids = doc.sub_document_node_ids();
|
|
146
|
+
for node_id in sub_document_node_ids.into_iter() {
|
|
147
|
+
if let Some(sub_doc) = doc.get_node_mut(node_id).and_then(|node| node.subdoc_mut()) {
|
|
148
|
+
let mut inner = sub_doc.inner_mut();
|
|
149
|
+
build_custom_widget_scenes(custom_widget_scenes, &mut inner, render_ctx, scale);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
#[cfg(feature = "custom-widget")]
|
|
155
|
+
fn process_custom_widget_node(
|
|
156
|
+
doc: &mut BaseDocument,
|
|
157
|
+
render_ctx: &mut impl anyrender::RenderContext,
|
|
158
|
+
node_id: NodeId,
|
|
159
|
+
scale: f64,
|
|
160
|
+
) -> Option<Scene> {
|
|
161
|
+
use blitz_dom::node::{CustomWidgetStatus, ProxyRenderContext};
|
|
162
|
+
|
|
163
|
+
let node = doc.get_node_mut(node_id)?;
|
|
164
|
+
let width = (node.final_layout().size.width as f64 * scale) as u32;
|
|
165
|
+
let height = (node.final_layout().size.height as f64 * scale) as u32;
|
|
166
|
+
|
|
167
|
+
if width == 0 || height == 0 {
|
|
168
|
+
return None;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
let style = (*node.stylo_element_data().primary_styles()?).clone();
|
|
172
|
+
let element = node.data.downcast_element_mut()?;
|
|
173
|
+
let widget_data = element.custom_widget_data_mut()?;
|
|
174
|
+
|
|
175
|
+
let mut render_ctx = ProxyRenderContext {
|
|
176
|
+
inner: render_ctx,
|
|
177
|
+
resource_ids: &mut widget_data.active_resource_ids,
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
if widget_data.status == CustomWidgetStatus::Suspended {
|
|
181
|
+
widget_data.widget.can_create_surfaces(&mut render_ctx);
|
|
182
|
+
widget_data.status = CustomWidgetStatus::Active;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
let widget_scene = widget_data
|
|
186
|
+
.widget
|
|
187
|
+
.paint(&mut render_ctx, &style, width, height, scale);
|
|
188
|
+
|
|
189
|
+
Some(widget_scene)
|
|
190
|
+
}
|