blitz-pdf 0.1.2 → 0.1.4
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 +26 -0
- package/THIRD_PARTY_NOTICES.md +5 -2
- package/docs/layout-regressions.md +65 -0
- package/docs/pagination-regressions.md +89 -0
- package/package.json +2 -1
- package/vendor/README.md +35 -0
- package/vendor/blitz-dom/Cargo.toml +113 -0
- package/vendor/blitz-dom/LICENSE-APACHE +176 -0
- package/vendor/blitz-dom/LICENSE-MIT +23 -0
- package/vendor/blitz-dom/assets/default.css +1142 -0
- package/vendor/blitz-dom/assets/moz-bullet-font.otf +0 -0
- package/vendor/blitz-dom/src/accessibility.rs +255 -0
- package/vendor/blitz-dom/src/config.rs +97 -0
- package/vendor/blitz-dom/src/cssom.rs +971 -0
- package/vendor/blitz-dom/src/debug.rs +206 -0
- package/vendor/blitz-dom/src/document.rs +3395 -0
- package/vendor/blitz-dom/src/events/driver.rs +427 -0
- package/vendor/blitz-dom/src/events/focus.rs +40 -0
- package/vendor/blitz-dom/src/events/ime.rs +31 -0
- package/vendor/blitz-dom/src/events/keyboard.rs +174 -0
- package/vendor/blitz-dom/src/events/mod.rs +315 -0
- package/vendor/blitz-dom/src/events/pointer.rs +849 -0
- package/vendor/blitz-dom/src/font_metrics.rs +177 -0
- package/vendor/blitz-dom/src/form.rs +463 -0
- package/vendor/blitz-dom/src/html.rs +38 -0
- package/vendor/blitz-dom/src/iframe.rs +186 -0
- package/vendor/blitz-dom/src/layout/construct.rs +1328 -0
- package/vendor/blitz-dom/src/layout/damage.rs +642 -0
- package/vendor/blitz-dom/src/layout/inline.rs +1160 -0
- package/vendor/blitz-dom/src/layout/list.rs +237 -0
- package/vendor/blitz-dom/src/layout/mod.rs +969 -0
- package/vendor/blitz-dom/src/layout/paint_tree.rs +462 -0
- package/vendor/blitz-dom/src/layout/replaced.rs +439 -0
- package/vendor/blitz-dom/src/layout/table.rs +967 -0
- package/vendor/blitz-dom/src/layout/text_transform.rs +979 -0
- package/vendor/blitz-dom/src/layout/writing_mode.rs +437 -0
- package/vendor/blitz-dom/src/lib.rs +160 -0
- package/vendor/blitz-dom/src/mutator.rs +1818 -0
- package/vendor/blitz-dom/src/net.rs +649 -0
- package/vendor/blitz-dom/src/node/attributes.rs +60 -0
- package/vendor/blitz-dom/src/node/custom_widget.rs +178 -0
- package/vendor/blitz-dom/src/node/element.rs +1106 -0
- package/vendor/blitz-dom/src/node/mod.rs +30 -0
- package/vendor/blitz-dom/src/node/node.rs +2036 -0
- package/vendor/blitz-dom/src/node/scrollbar.rs +237 -0
- package/vendor/blitz-dom/src/node/serialize.rs +225 -0
- package/vendor/blitz-dom/src/node/stylo_data.rs +142 -0
- package/vendor/blitz-dom/src/node/svg.rs +265 -0
- package/vendor/blitz-dom/src/node/text.rs +804 -0
- package/vendor/blitz-dom/src/query_selector.rs +275 -0
- package/vendor/blitz-dom/src/resolve.rs +474 -0
- package/vendor/blitz-dom/src/resolved_style.rs +797 -0
- package/vendor/blitz-dom/src/scrolling.rs +780 -0
- package/vendor/blitz-dom/src/selection.rs +122 -0
- package/vendor/blitz-dom/src/stylo.rs +1518 -0
- package/vendor/blitz-dom/src/stylo_device.rs +88 -0
- package/vendor/blitz-dom/src/stylo_to_cursor_icon.rs +49 -0
- package/vendor/blitz-dom/src/stylo_to_kurbo.rs +129 -0
- package/vendor/blitz-dom/src/stylo_to_parley.rs +655 -0
- package/vendor/blitz-dom/src/traversal.rs +600 -0
- package/vendor/blitz-dom/src/tree.rs +136 -0
- package/vendor/blitz-dom/src/url.rs +63 -0
- package/vendor/blitz-dom/src/util.rs +256 -0
- package/wasm/blitz_pdf_bg.wasm +0 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
//! Management of the Stylo [`Device`]: constructing it from shell state and
|
|
2
|
+
//! coalescing changes to it (viewport resizes, zoom, color-scheme and media
|
|
3
|
+
//! type changes) so that the stylist device is rebuilt at most once per
|
|
4
|
+
//! [`resolve`](crate::BaseDocument::resolve), no matter how many changes
|
|
5
|
+
//! occurred since the last resolve.
|
|
6
|
+
|
|
7
|
+
use std::sync::{Arc, Mutex};
|
|
8
|
+
|
|
9
|
+
use bitflags::bitflags;
|
|
10
|
+
use blitz_traits::shell::{ColorScheme, Viewport};
|
|
11
|
+
use parley::FontContext;
|
|
12
|
+
use selectors::matching::QuirksMode;
|
|
13
|
+
use style::device::Device;
|
|
14
|
+
use style::media_queries::MediaType;
|
|
15
|
+
use style::properties::ComputedValues;
|
|
16
|
+
use style::properties::style_structs::Font;
|
|
17
|
+
use style::queries::values::PrefersColorScheme;
|
|
18
|
+
use style::servo::media_features::PointerCapabilities;
|
|
19
|
+
|
|
20
|
+
use crate::font_metrics::BlitzFontMetricsProvider;
|
|
21
|
+
|
|
22
|
+
bitflags! {
|
|
23
|
+
/// The set of changes to the [`Device`] that have accumulated since the
|
|
24
|
+
/// stylist device was last rebuilt. Only the *latest* values matter (they
|
|
25
|
+
/// live on [`BaseDocument`](crate::BaseDocument)); these flags record
|
|
26
|
+
/// which kinds of change occurred so that the flush can do the right
|
|
27
|
+
/// amount of invalidation work.
|
|
28
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
|
29
|
+
pub(crate) struct DeviceChanges: u8 {
|
|
30
|
+
/// The CSS pixel viewport size changed (window resize, zoom, or hidpi
|
|
31
|
+
/// scale change).
|
|
32
|
+
const VIEWPORT_SIZE = 0b0000_0001;
|
|
33
|
+
/// The total scale factor (hidpi scale * zoom) changed. Requires
|
|
34
|
+
/// invalidating cached inline layouts (text is shaped at a specific
|
|
35
|
+
/// scale) and a redraw.
|
|
36
|
+
const SCALE = 0b0000_0010;
|
|
37
|
+
/// The preferred color scheme changed.
|
|
38
|
+
const COLOR_SCHEME = 0b0000_0100;
|
|
39
|
+
/// The media type (e.g. screen/print) changed.
|
|
40
|
+
const MEDIA_TYPE = 0b0000_1000;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
impl DeviceChanges {
|
|
45
|
+
/// Compute the [`DeviceChanges`] implied by moving from viewport `old` to
|
|
46
|
+
/// viewport `new`.
|
|
47
|
+
pub(crate) fn from_viewports(old: &Viewport, new: &Viewport) -> Self {
|
|
48
|
+
let mut changes = Self::empty();
|
|
49
|
+
if old.logical_size() != new.logical_size() {
|
|
50
|
+
changes |= Self::VIEWPORT_SIZE;
|
|
51
|
+
}
|
|
52
|
+
if old.scale_f64() != new.scale_f64() {
|
|
53
|
+
changes |= Self::SCALE;
|
|
54
|
+
}
|
|
55
|
+
if old.color_scheme != new.color_scheme {
|
|
56
|
+
changes |= Self::COLOR_SCHEME;
|
|
57
|
+
}
|
|
58
|
+
changes
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
pub(crate) fn make_device(
|
|
63
|
+
viewport: &Viewport,
|
|
64
|
+
layout_viewport: Option<(f32, f32)>,
|
|
65
|
+
media_type: MediaType,
|
|
66
|
+
font_ctx: Arc<Mutex<FontContext>>,
|
|
67
|
+
) -> Device {
|
|
68
|
+
let (width, height) = layout_viewport.unwrap_or_else(|| viewport.logical_size());
|
|
69
|
+
let viewport_size = euclid::Size2D::new(width, height);
|
|
70
|
+
let device_size = euclid::Size2D::new(width, height) * viewport.scale();
|
|
71
|
+
let device_pixel_ratio = euclid::Scale::new(viewport.scale());
|
|
72
|
+
|
|
73
|
+
Device::new(
|
|
74
|
+
media_type,
|
|
75
|
+
QuirksMode::NoQuirks,
|
|
76
|
+
viewport_size,
|
|
77
|
+
device_size,
|
|
78
|
+
device_pixel_ratio,
|
|
79
|
+
Box::new(BlitzFontMetricsProvider { font_ctx }),
|
|
80
|
+
ComputedValues::initial_values_with_font_override(Font::initial_values()),
|
|
81
|
+
match viewport.color_scheme {
|
|
82
|
+
ColorScheme::Light => PrefersColorScheme::Light,
|
|
83
|
+
ColorScheme::Dark => PrefersColorScheme::Dark,
|
|
84
|
+
},
|
|
85
|
+
PointerCapabilities::default(),
|
|
86
|
+
PointerCapabilities::default(),
|
|
87
|
+
)
|
|
88
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
use cursor_icon::CursorIcon;
|
|
2
|
+
use style::values::computed::ui::CursorKind as StyloCursorKind;
|
|
3
|
+
|
|
4
|
+
pub(crate) fn stylo_to_cursor_icon(cursor: StyloCursorKind) -> Option<CursorIcon> {
|
|
5
|
+
match cursor {
|
|
6
|
+
// Auto needs special handling so this function should only really be called with
|
|
7
|
+
// non-Auto values. But better to return a default than panic if it is.
|
|
8
|
+
StyloCursorKind::Auto => {
|
|
9
|
+
#[cfg(feature = "tracing")]
|
|
10
|
+
tracing::warn!("stylo_to_cursor_icon was called with CursorKind::Auto");
|
|
11
|
+
Some(CursorIcon::Default)
|
|
12
|
+
}
|
|
13
|
+
StyloCursorKind::None => None,
|
|
14
|
+
StyloCursorKind::Default => Some(CursorIcon::Default),
|
|
15
|
+
StyloCursorKind::Pointer => Some(CursorIcon::Pointer),
|
|
16
|
+
StyloCursorKind::ContextMenu => Some(CursorIcon::ContextMenu),
|
|
17
|
+
StyloCursorKind::Help => Some(CursorIcon::Help),
|
|
18
|
+
StyloCursorKind::Progress => Some(CursorIcon::Progress),
|
|
19
|
+
StyloCursorKind::Wait => Some(CursorIcon::Wait),
|
|
20
|
+
StyloCursorKind::Cell => Some(CursorIcon::Cell),
|
|
21
|
+
StyloCursorKind::Crosshair => Some(CursorIcon::Crosshair),
|
|
22
|
+
StyloCursorKind::Text => Some(CursorIcon::Text),
|
|
23
|
+
StyloCursorKind::VerticalText => Some(CursorIcon::VerticalText),
|
|
24
|
+
StyloCursorKind::Alias => Some(CursorIcon::Alias),
|
|
25
|
+
StyloCursorKind::Copy => Some(CursorIcon::Copy),
|
|
26
|
+
StyloCursorKind::Move => Some(CursorIcon::Move),
|
|
27
|
+
StyloCursorKind::NoDrop => Some(CursorIcon::NoDrop),
|
|
28
|
+
StyloCursorKind::NotAllowed => Some(CursorIcon::NotAllowed),
|
|
29
|
+
StyloCursorKind::Grab => Some(CursorIcon::Grab),
|
|
30
|
+
StyloCursorKind::Grabbing => Some(CursorIcon::Grabbing),
|
|
31
|
+
StyloCursorKind::EResize => Some(CursorIcon::EResize),
|
|
32
|
+
StyloCursorKind::NResize => Some(CursorIcon::NResize),
|
|
33
|
+
StyloCursorKind::NeResize => Some(CursorIcon::NeResize),
|
|
34
|
+
StyloCursorKind::NwResize => Some(CursorIcon::NwResize),
|
|
35
|
+
StyloCursorKind::SResize => Some(CursorIcon::SResize),
|
|
36
|
+
StyloCursorKind::SeResize => Some(CursorIcon::SeResize),
|
|
37
|
+
StyloCursorKind::SwResize => Some(CursorIcon::SwResize),
|
|
38
|
+
StyloCursorKind::WResize => Some(CursorIcon::WResize),
|
|
39
|
+
StyloCursorKind::EwResize => Some(CursorIcon::EwResize),
|
|
40
|
+
StyloCursorKind::NsResize => Some(CursorIcon::NsResize),
|
|
41
|
+
StyloCursorKind::NeswResize => Some(CursorIcon::NeswResize),
|
|
42
|
+
StyloCursorKind::NwseResize => Some(CursorIcon::NwseResize),
|
|
43
|
+
StyloCursorKind::ColResize => Some(CursorIcon::ColResize),
|
|
44
|
+
StyloCursorKind::RowResize => Some(CursorIcon::RowResize),
|
|
45
|
+
StyloCursorKind::AllScroll => Some(CursorIcon::AllScroll),
|
|
46
|
+
StyloCursorKind::ZoomIn => Some(CursorIcon::ZoomIn),
|
|
47
|
+
StyloCursorKind::ZoomOut => Some(CursorIcon::ZoomOut),
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
use euclid::default::Rect;
|
|
2
|
+
use kurbo::{Affine, Vec2};
|
|
3
|
+
use style::{
|
|
4
|
+
properties::generated::style_structs::Box as BoxStyleStruct,
|
|
5
|
+
values::{
|
|
6
|
+
computed::{CSSPixelLength, Rotate},
|
|
7
|
+
generics::transform::{Scale, Translate},
|
|
8
|
+
},
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// 6. Current Transformation Matrix
|
|
12
|
+
//
|
|
13
|
+
// The transformation matrix is computed from the transform, transform-origin, translate, rotate, scale, and offset properties as follows:
|
|
14
|
+
//
|
|
15
|
+
// - Start with the identity matrix.
|
|
16
|
+
// - Translate by the computed X, Y, and Z values of transform-origin.
|
|
17
|
+
// - Translate by the computed X, Y, and Z values of translate.
|
|
18
|
+
// - Rotate by the computed <angle> about the specified axis of rotate.
|
|
19
|
+
// - Scale by the computed X, Y, and Z values of scale.
|
|
20
|
+
// - Translate and rotate by the transform specified by offset.
|
|
21
|
+
// - Multiply by each of the transform functions in transform from left to right.
|
|
22
|
+
// - Translate by the negated computed X, Y and Z values of transform-origin.
|
|
23
|
+
//
|
|
24
|
+
// <https://drafts.csswg.org/css-transforms-2/#ctm>
|
|
25
|
+
pub fn resolve_2d_transform(
|
|
26
|
+
box_styles: &BoxStyleStruct,
|
|
27
|
+
reference_box: Rect<CSSPixelLength>,
|
|
28
|
+
) -> Option<Affine> {
|
|
29
|
+
let translate = match &box_styles.translate {
|
|
30
|
+
Translate::None => None,
|
|
31
|
+
Translate::Translate(x, y, _z) => Some(Vec2 {
|
|
32
|
+
x: x.resolve(reference_box.width()).px() as f64,
|
|
33
|
+
y: y.resolve(reference_box.height()).px() as f64,
|
|
34
|
+
}),
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
let rotate = match &box_styles.rotate {
|
|
38
|
+
Rotate::None => None,
|
|
39
|
+
Rotate::Rotate(angle) => Some(angle.radians64()),
|
|
40
|
+
// A rotation about the z axis stays in the plane; the sign of the
|
|
41
|
+
// axis component decides the direction, its magnitude cancels out.
|
|
42
|
+
Rotate::Rotate3D(x, y, z, angle) if *x == 0.0 && *y == 0.0 && *z != 0.0 => {
|
|
43
|
+
Some(angle.radians64() * z.signum() as f64)
|
|
44
|
+
}
|
|
45
|
+
// TODO: support 3D transforms
|
|
46
|
+
Rotate::Rotate3D(_, _, _, _) => None,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
let scale_transform = match &box_styles.scale {
|
|
50
|
+
Scale::None => None,
|
|
51
|
+
Scale::Scale(x, y, _z) => Some(Vec2 {
|
|
52
|
+
x: *x as f64,
|
|
53
|
+
y: *y as f64,
|
|
54
|
+
}),
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
let transform = if box_styles.transform.0.is_empty() {
|
|
58
|
+
None
|
|
59
|
+
} else {
|
|
60
|
+
box_styles
|
|
61
|
+
.transform
|
|
62
|
+
.to_transform_3d_matrix(Some(&reference_box))
|
|
63
|
+
.ok()
|
|
64
|
+
// The `has_3d` flag means a 3d function appeared in the list, not that the
|
|
65
|
+
// matrix needs 3d: `translate3d(x, y, 0)` sets it while resolving to a
|
|
66
|
+
// plain 2d translation.
|
|
67
|
+
//
|
|
68
|
+
// TODO: support 3D transforms. Outside a 3d rendering context the spec
|
|
69
|
+
// still applies the transform as a painting effect -- its own example
|
|
70
|
+
// paints `rotateY(50deg)` narrower -- so dropping one is wrong. `is_2d()`
|
|
71
|
+
// is closer than the flag, not the rule.
|
|
72
|
+
// See: https://drafts.csswg.org/css-transforms-2/#3d-transform-rendering
|
|
73
|
+
.filter(|(t, _has_3d)| t.is_2d())
|
|
74
|
+
.map(|(t, _)| {
|
|
75
|
+
// See: https://drafts.csswg.org/css-transforms-2/#two-dimensional-subset
|
|
76
|
+
// And https://docs.rs/kurbo/latest/kurbo/struct.Affine.html#method.new
|
|
77
|
+
Affine::new([t.m11, t.m12, t.m21, t.m22, t.m41, t.m42].map(|v| v as f64))
|
|
78
|
+
})
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// TODO: support the "offset" property
|
|
82
|
+
// <https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/offset>
|
|
83
|
+
|
|
84
|
+
if translate.is_none() && rotate.is_none() && scale_transform.is_none() && transform.is_none() {
|
|
85
|
+
return None;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Apply the transform origin by:
|
|
89
|
+
// - Translating by the origin offset
|
|
90
|
+
// - Applying our transform
|
|
91
|
+
// - Translating by the inverse of the origin offset
|
|
92
|
+
let transform_origin = &box_styles.transform_origin;
|
|
93
|
+
let origin_translation = Affine::translate(Vec2 {
|
|
94
|
+
x: transform_origin
|
|
95
|
+
.horizontal
|
|
96
|
+
.resolve(reference_box.width())
|
|
97
|
+
.px() as f64,
|
|
98
|
+
y: transform_origin
|
|
99
|
+
.vertical
|
|
100
|
+
.resolve(reference_box.height())
|
|
101
|
+
.px() as f64,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
let mut resolved = Affine::IDENTITY;
|
|
105
|
+
|
|
106
|
+
if let Some(translation) = translate {
|
|
107
|
+
resolved *= Affine::translate(translation)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if let Some(rotation) = rotate {
|
|
111
|
+
resolved *= Affine::rotate(rotation)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if let Some(scale_transform) = scale_transform {
|
|
115
|
+
resolved *= Affine::scale_non_uniform(scale_transform.x, scale_transform.y)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if let Some(transform) = transform {
|
|
119
|
+
resolved *= transform;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
resolved = origin_translation * resolved * origin_translation.inverse();
|
|
123
|
+
|
|
124
|
+
if resolved != Affine::IDENTITY {
|
|
125
|
+
Some(resolved)
|
|
126
|
+
} else {
|
|
127
|
+
None
|
|
128
|
+
}
|
|
129
|
+
}
|