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,439 @@
|
|
|
1
|
+
use markup5ever::{LocalName, local_name};
|
|
2
|
+
use taffy::{
|
|
3
|
+
AvailableSpace, BoxSizing, CoreStyle, LayoutInput, LayoutOutput, MaybeMath, MaybeResolve,
|
|
4
|
+
RequestedAxis, ResolveOrZero as _, RunMode, Size, SizingMode,
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
/// Whether an element is a replaced element laid out as a leaf box with an
|
|
8
|
+
/// intrinsic size. Note: `<object>` is deliberately excluded as its fallback
|
|
9
|
+
/// children should render when no resource is loaded.
|
|
10
|
+
pub(crate) fn is_replaced_element(tag_name: &LocalName) -> bool {
|
|
11
|
+
*tag_name == local_name!("img")
|
|
12
|
+
|| *tag_name == local_name!("svg")
|
|
13
|
+
|| *tag_name == local_name!("canvas")
|
|
14
|
+
|| *tag_name == local_name!("video")
|
|
15
|
+
|| *tag_name == local_name!("embed")
|
|
16
|
+
|| *tag_name == local_name!("iframe")
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/// The intrinsic dimensions of a replaced element per CSS Images 3
|
|
20
|
+
/// (https://drafts.csswg.org/css-images/#intrinsic-dimensions): an intrinsic
|
|
21
|
+
/// width, an intrinsic height, and an intrinsic aspect ratio, each of which
|
|
22
|
+
/// may independently be absent.
|
|
23
|
+
#[derive(Debug, Clone, Copy, Default)]
|
|
24
|
+
pub struct IntrinsicSizes {
|
|
25
|
+
pub width: Option<f32>,
|
|
26
|
+
pub height: Option<f32>,
|
|
27
|
+
pub ratio: Option<f32>,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#[derive(Debug, Clone, Copy)]
|
|
31
|
+
pub struct ReplacedContext {
|
|
32
|
+
/// The element's intrinsic dimensions, each possibly absent.
|
|
33
|
+
pub intrinsic_sizes: IntrinsicSizes,
|
|
34
|
+
/// The default object size (https://drafts.csswg.org/css-images/#default-object-size)
|
|
35
|
+
/// used to fill in dimensions the intrinsic sizes leave unresolved. 300x150
|
|
36
|
+
/// for most replaced elements; zero for an image with no loaded resource.
|
|
37
|
+
pub default_object_size: taffy::Size<f32>,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/// Whether a height/width value is violating it's min- and max- constraints
|
|
41
|
+
/// The min- and max- constraints cannot both be violated because the max
|
|
42
|
+
/// constraint if floored by the min constraint (min constraint takes priority)
|
|
43
|
+
enum Violation {
|
|
44
|
+
/// Constraints are not violated
|
|
45
|
+
None,
|
|
46
|
+
/// Min constraint is violated
|
|
47
|
+
Min,
|
|
48
|
+
/// Max constraint is violated
|
|
49
|
+
Max,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
pub fn compute_replaced_layout(
|
|
53
|
+
inputs: LayoutInput,
|
|
54
|
+
style: &impl CoreStyle,
|
|
55
|
+
resolve_calc_value: impl Fn(*const (), f32) -> f32,
|
|
56
|
+
context: &ReplacedContext,
|
|
57
|
+
) -> LayoutOutput {
|
|
58
|
+
let LayoutInput {
|
|
59
|
+
known_dimensions,
|
|
60
|
+
parent_size,
|
|
61
|
+
available_space,
|
|
62
|
+
sizing_mode,
|
|
63
|
+
run_mode,
|
|
64
|
+
axis: requested_axis,
|
|
65
|
+
..
|
|
66
|
+
} = inputs;
|
|
67
|
+
|
|
68
|
+
let padding = style
|
|
69
|
+
.padding()
|
|
70
|
+
.resolve_or_zero(parent_size.width, &resolve_calc_value);
|
|
71
|
+
let border = style
|
|
72
|
+
.border()
|
|
73
|
+
.resolve_or_zero(parent_size.width, &resolve_calc_value);
|
|
74
|
+
let padding_border = padding + border;
|
|
75
|
+
let pb_sum = Size {
|
|
76
|
+
width: padding_border.left + padding_border.right,
|
|
77
|
+
height: padding_border.top + padding_border.bottom,
|
|
78
|
+
};
|
|
79
|
+
let box_sizing_adjustment = if style.box_sizing() == BoxSizing::BorderBox {
|
|
80
|
+
pb_sum
|
|
81
|
+
} else {
|
|
82
|
+
Size::ZERO
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// The scrollable overflow rect is measured from the scroll origin at the
|
|
86
|
+
// padding-box corner: the content-box size offset by the start padding. A
|
|
87
|
+
// scroll container's own padding at the end of the content is part of its
|
|
88
|
+
// scrollable overflow region, so it is included. Boxes that are not scroll
|
|
89
|
+
// containers do not extend their overflow region by their own padding.
|
|
90
|
+
let is_scroll_container = {
|
|
91
|
+
let overflow = style.overflow();
|
|
92
|
+
overflow.x.is_scroll_container() || overflow.y.is_scroll_container()
|
|
93
|
+
};
|
|
94
|
+
let is_rtl = style.direction() == taffy::Direction::Rtl;
|
|
95
|
+
let overflow_rect_for = |content_box_size: Size<f32>| {
|
|
96
|
+
let start_padding = if is_rtl { padding.right } else { padding.left };
|
|
97
|
+
let end_padding = if is_rtl { padding.left } else { padding.right };
|
|
98
|
+
taffy::Rect {
|
|
99
|
+
left: 0.0,
|
|
100
|
+
right: start_padding
|
|
101
|
+
+ content_box_size.width
|
|
102
|
+
+ if is_scroll_container {
|
|
103
|
+
end_padding
|
|
104
|
+
} else {
|
|
105
|
+
0.0
|
|
106
|
+
},
|
|
107
|
+
top: 0.0,
|
|
108
|
+
bottom: padding.top
|
|
109
|
+
+ content_box_size.height
|
|
110
|
+
+ if is_scroll_container {
|
|
111
|
+
padding.bottom
|
|
112
|
+
} else {
|
|
113
|
+
0.0
|
|
114
|
+
},
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// Return early if both width and height are known
|
|
119
|
+
if run_mode == RunMode::ComputeSize {
|
|
120
|
+
if let Size {
|
|
121
|
+
width: Some(width),
|
|
122
|
+
height: Some(height),
|
|
123
|
+
} = known_dimensions
|
|
124
|
+
{
|
|
125
|
+
return LayoutOutput::from_outer_size(Size {
|
|
126
|
+
width: width.max(pb_sum.width),
|
|
127
|
+
height: height.max(pb_sum.height),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Use aspect_ratio from style, fall back to inherent aspect ratio (if any).
|
|
133
|
+
//
|
|
134
|
+
// A degenerate ratio -- zero, infinite, or NaN -- is discarded. Transferring
|
|
135
|
+
// such a ratio between axes computes `width / ratio` or `height * ratio`,
|
|
136
|
+
// which yields an infinite (ratio == 0) or NaN (ratio is NaN) size in the
|
|
137
|
+
// other axis. CSS Sizing 4 4.1 says a degenerate ratio behaves as `auto`,
|
|
138
|
+
// so each source is filtered *before* the fallback: a degenerate style
|
|
139
|
+
// ratio falls back to the inherent one (that is what `auto` means for a
|
|
140
|
+
// replaced element), and only if both are degenerate or absent does the
|
|
141
|
+
// element get no preferred aspect ratio at all.
|
|
142
|
+
let is_usable_ratio = |ratio: &f32| ratio.is_finite() && *ratio > 0.0;
|
|
143
|
+
let intrinsic = context.intrinsic_sizes;
|
|
144
|
+
let aspect_ratio: Option<f32> = style
|
|
145
|
+
.aspect_ratio()
|
|
146
|
+
.filter(is_usable_ratio)
|
|
147
|
+
.or(intrinsic.ratio.filter(is_usable_ratio));
|
|
148
|
+
|
|
149
|
+
// Concrete object size per the CSS default sizing algorithm with no
|
|
150
|
+
// specified size (https://drafts.csswg.org/css-images/#default-sizing):
|
|
151
|
+
// missing intrinsic dimensions are derived from the aspect ratio when
|
|
152
|
+
// possible, otherwise taken from the default object size. An element with
|
|
153
|
+
// only an intrinsic aspect ratio uses the stretch-fit width in normal flow
|
|
154
|
+
// (CSS2 §10.3.2) when the available width is definite; shrink-to-fit
|
|
155
|
+
// contexts (min/max-content) contain it within the default object size.
|
|
156
|
+
//
|
|
157
|
+
// Only the intrinsic ratio participates here: the `aspect-ratio` property
|
|
158
|
+
// affects the sizing of the box, not the natural dimensions of its content.
|
|
159
|
+
let intrinsic_ratio = intrinsic.ratio.filter(is_usable_ratio);
|
|
160
|
+
let default_size = context.default_object_size;
|
|
161
|
+
let inherent_size = match (intrinsic.width, intrinsic.height) {
|
|
162
|
+
(Some(w), Some(h)) => Size {
|
|
163
|
+
width: w,
|
|
164
|
+
height: h,
|
|
165
|
+
},
|
|
166
|
+
(Some(w), None) => Size {
|
|
167
|
+
width: w,
|
|
168
|
+
height: intrinsic_ratio
|
|
169
|
+
.map(|r| w / r)
|
|
170
|
+
.unwrap_or(default_size.height),
|
|
171
|
+
},
|
|
172
|
+
(None, Some(h)) => Size {
|
|
173
|
+
width: intrinsic_ratio.map(|r| h * r).unwrap_or(default_size.width),
|
|
174
|
+
height: h,
|
|
175
|
+
},
|
|
176
|
+
(None, None) => match intrinsic_ratio {
|
|
177
|
+
Some(ratio) => {
|
|
178
|
+
// A ratio-only replaced element stretches to fit the width it is laid out
|
|
179
|
+
// in: the available width if definite, else (under a max-content constraint)
|
|
180
|
+
// its containing block, per CSS2 §10.3.2.
|
|
181
|
+
let stretch_fit_width = match available_space.width {
|
|
182
|
+
AvailableSpace::Definite(width) => Some(width),
|
|
183
|
+
AvailableSpace::MaxContent => parent_size.width,
|
|
184
|
+
AvailableSpace::MinContent => None,
|
|
185
|
+
};
|
|
186
|
+
if let Some(width) = stretch_fit_width {
|
|
187
|
+
Size {
|
|
188
|
+
width,
|
|
189
|
+
height: width / ratio,
|
|
190
|
+
}
|
|
191
|
+
} else {
|
|
192
|
+
// Contain within the default object size
|
|
193
|
+
let scale = (default_size.width / ratio).min(default_size.height);
|
|
194
|
+
Size {
|
|
195
|
+
width: scale * ratio,
|
|
196
|
+
height: scale,
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
None => default_size,
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// Percentages are only resolved against zero in the inline axis.
|
|
205
|
+
// See https://www.w3.org/TR/css-sizing-3/#replaced-percentage-min-contribution
|
|
206
|
+
let basis_for_max_and_preferred = Size {
|
|
207
|
+
width: if available_space.width == AvailableSpace::MinContent {
|
|
208
|
+
Some(0.0)
|
|
209
|
+
} else {
|
|
210
|
+
parent_size.width
|
|
211
|
+
},
|
|
212
|
+
height: parent_size.height,
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// `stretch` fills the containing block (less margins) when its size is definite, and
|
|
216
|
+
// behaves as `auto` otherwise. The content size can't be negative.
|
|
217
|
+
// See https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing
|
|
218
|
+
let margin = style
|
|
219
|
+
.margin()
|
|
220
|
+
.resolve_or_zero(parent_size.width, &resolve_calc_value);
|
|
221
|
+
let stretch_size = Size {
|
|
222
|
+
width: parent_size
|
|
223
|
+
.width
|
|
224
|
+
.filter(|_| available_space.width.is_definite())
|
|
225
|
+
.map(|width| (width - margin.horizontal_axis_sum() - pb_sum.width).max(0.0)),
|
|
226
|
+
height: parent_size
|
|
227
|
+
.height
|
|
228
|
+
.filter(|_| available_space.height.is_definite())
|
|
229
|
+
.map(|height| (height - margin.vertical_axis_sum() - pb_sum.height).max(0.0)),
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// Resolve sizes
|
|
233
|
+
let size_style = style.size();
|
|
234
|
+
let style_size = size_style
|
|
235
|
+
.maybe_resolve(basis_for_max_and_preferred, &resolve_calc_value)
|
|
236
|
+
.maybe_sub(box_sizing_adjustment);
|
|
237
|
+
let style_size = Size {
|
|
238
|
+
width: if size_style.width.is_stretch() {
|
|
239
|
+
stretch_size.width
|
|
240
|
+
} else {
|
|
241
|
+
style_size.width
|
|
242
|
+
},
|
|
243
|
+
height: if size_style.height.is_stretch() {
|
|
244
|
+
stretch_size.height
|
|
245
|
+
} else {
|
|
246
|
+
style_size.height
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
let mut min_size = style
|
|
250
|
+
.min_size()
|
|
251
|
+
.maybe_resolve(parent_size, &resolve_calc_value)
|
|
252
|
+
.maybe_sub(box_sizing_adjustment);
|
|
253
|
+
let max_size = style
|
|
254
|
+
.max_size()
|
|
255
|
+
.maybe_resolve(basis_for_max_and_preferred, &resolve_calc_value)
|
|
256
|
+
.maybe_max(min_size)
|
|
257
|
+
.maybe_sub(box_sizing_adjustment);
|
|
258
|
+
|
|
259
|
+
// For ContentSize mode, ignore preferred/min size styles in the axis being measured: the
|
|
260
|
+
// parent layout algorithm applies them itself, and content-based measurement should return
|
|
261
|
+
// the content size (the intrinsic size for replaced elements). Constraints in the opposite
|
|
262
|
+
// axis are retained as they transfer through the aspect ratio (transferred size suggestion).
|
|
263
|
+
let mut style_size = style_size;
|
|
264
|
+
if sizing_mode == SizingMode::ContentSize {
|
|
265
|
+
match requested_axis {
|
|
266
|
+
RequestedAxis::Horizontal => {
|
|
267
|
+
style_size.width = None;
|
|
268
|
+
min_size.width = None;
|
|
269
|
+
}
|
|
270
|
+
RequestedAxis::Vertical => {
|
|
271
|
+
style_size.height = None;
|
|
272
|
+
min_size.height = None;
|
|
273
|
+
}
|
|
274
|
+
RequestedAxis::Both => {}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Known dimensions are the parent's current sizing inputs. Clamp them before transferring
|
|
279
|
+
// an aspect ratio so provisional cross-axis sizes do not bypass replaced-element limits.
|
|
280
|
+
if known_dimensions.width.is_some() | known_dimensions.height.is_some() {
|
|
281
|
+
// Style max sizes without the available-space fallback: available space must not
|
|
282
|
+
// constrain the aspect-ratio transfer of parent-resolved dimensions.
|
|
283
|
+
let style_max_size = style
|
|
284
|
+
.max_size()
|
|
285
|
+
.maybe_resolve(basis_for_max_and_preferred, &resolve_calc_value)
|
|
286
|
+
.maybe_sub(box_sizing_adjustment)
|
|
287
|
+
.maybe_max(min_size);
|
|
288
|
+
|
|
289
|
+
let content_box_known_dimensions = known_dimensions.maybe_sub(pb_sum);
|
|
290
|
+
let transferred = content_box_known_dimensions
|
|
291
|
+
.maybe_clamp(min_size, style_max_size)
|
|
292
|
+
.maybe_apply_aspect_ratio(aspect_ratio)
|
|
293
|
+
.unwrap_or(inherent_size);
|
|
294
|
+
|
|
295
|
+
// Known axes are authoritative (already resolved by the parent); only the axis
|
|
296
|
+
// derived via aspect-ratio transfer (or falling back to the intrinsic size) is
|
|
297
|
+
// clamped by this element's min/max sizes.
|
|
298
|
+
let size = content_box_known_dimensions
|
|
299
|
+
.unwrap_or(transferred.maybe_clamp(min_size, style_max_size));
|
|
300
|
+
|
|
301
|
+
let size = size.map(|s| s.max(0.0));
|
|
302
|
+
return LayoutOutput::from_sizes(size + pb_sum, overflow_rect_for(size));
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
let unclamped_size = if style_size.width.is_some() | style_size.height.is_some() {
|
|
306
|
+
style_size
|
|
307
|
+
.maybe_apply_aspect_ratio(aspect_ratio)
|
|
308
|
+
.unwrap_or(inherent_size)
|
|
309
|
+
} else {
|
|
310
|
+
inherent_size
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
// Floor size at zero
|
|
314
|
+
let size = unclamped_size.map(|s| s.max(0.0));
|
|
315
|
+
|
|
316
|
+
// Violations
|
|
317
|
+
let width_violation = if size.width < min_size.width.unwrap_or(0.0) {
|
|
318
|
+
Violation::Min
|
|
319
|
+
} else if size.width > max_size.width.unwrap_or(f32::INFINITY) {
|
|
320
|
+
Violation::Max
|
|
321
|
+
} else {
|
|
322
|
+
Violation::None
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
let height_violation = if size.height < min_size.height.unwrap_or(0.0) {
|
|
326
|
+
Violation::Min
|
|
327
|
+
} else if size.height > max_size.height.unwrap_or(f32::INFINITY) {
|
|
328
|
+
Violation::Max
|
|
329
|
+
} else {
|
|
330
|
+
Violation::None
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
// Without an intrinsic aspect ratio, each axis is clamped independently
|
|
334
|
+
let Some(aspect_ratio) = aspect_ratio else {
|
|
335
|
+
let size = size.maybe_clamp(min_size, max_size);
|
|
336
|
+
return LayoutOutput::from_sizes(size + pb_sum, overflow_rect_for(size));
|
|
337
|
+
};
|
|
338
|
+
let inv_aspect_ratio = 1.0 / aspect_ratio;
|
|
339
|
+
|
|
340
|
+
// Clamp following rules in table at
|
|
341
|
+
// https://www.w3.org/TR/CSS22/visudet.html#min-max-widths
|
|
342
|
+
let size = match (width_violation, height_violation) {
|
|
343
|
+
// No constraint violation
|
|
344
|
+
(Violation::None, Violation::None) => size,
|
|
345
|
+
// w > max-width
|
|
346
|
+
(Violation::Max, Violation::None) => {
|
|
347
|
+
let max_width = max_size.width.unwrap();
|
|
348
|
+
Size {
|
|
349
|
+
width: max_width,
|
|
350
|
+
height: (max_width * inv_aspect_ratio).maybe_max(min_size.height),
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
// w < min-width
|
|
354
|
+
(Violation::Min, Violation::None) => {
|
|
355
|
+
let min_width = min_size.width.unwrap();
|
|
356
|
+
Size {
|
|
357
|
+
width: min_width,
|
|
358
|
+
height: (min_width * inv_aspect_ratio).maybe_min(max_size.height),
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
// h > max-height
|
|
362
|
+
(Violation::None, Violation::Max) => {
|
|
363
|
+
let max_height = max_size.height.unwrap();
|
|
364
|
+
Size {
|
|
365
|
+
width: (max_height * aspect_ratio).maybe_max(min_size.width),
|
|
366
|
+
height: max_height,
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
// h < min-height
|
|
370
|
+
(Violation::None, Violation::Min) => {
|
|
371
|
+
let min_height = min_size.height.unwrap();
|
|
372
|
+
Size {
|
|
373
|
+
width: (min_height * aspect_ratio).maybe_min(max_size.width),
|
|
374
|
+
height: min_height,
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
// (w > max-width) and (h > max-height)
|
|
378
|
+
(Violation::Max, Violation::Max) => {
|
|
379
|
+
let max_width = max_size.width.unwrap();
|
|
380
|
+
let max_height = max_size.height.unwrap();
|
|
381
|
+
if max_width / size.width <= max_height / size.height {
|
|
382
|
+
Size {
|
|
383
|
+
width: max_width,
|
|
384
|
+
height: (max_width * inv_aspect_ratio).maybe_max(min_size.height),
|
|
385
|
+
}
|
|
386
|
+
} else {
|
|
387
|
+
Size {
|
|
388
|
+
width: (max_height * aspect_ratio).maybe_max(min_size.width),
|
|
389
|
+
height: max_height,
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
// (w < min-width) and (h < min-height)
|
|
394
|
+
(Violation::Min, Violation::Min) => {
|
|
395
|
+
let min_width = min_size.width.unwrap();
|
|
396
|
+
let min_height = min_size.height.unwrap();
|
|
397
|
+
if min_width / size.width <= min_height / size.height {
|
|
398
|
+
Size {
|
|
399
|
+
width: (min_height * aspect_ratio).maybe_min(max_size.width),
|
|
400
|
+
height: min_height,
|
|
401
|
+
}
|
|
402
|
+
} else {
|
|
403
|
+
Size {
|
|
404
|
+
width: min_width,
|
|
405
|
+
height: (min_width * inv_aspect_ratio).maybe_min(max_size.height),
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
// (w < min-width) and (h > max-height)
|
|
410
|
+
(Violation::Min, Violation::Max) => {
|
|
411
|
+
let min_width = min_size.width.unwrap();
|
|
412
|
+
let max_height = max_size.height.unwrap();
|
|
413
|
+
Size {
|
|
414
|
+
width: min_width,
|
|
415
|
+
height: max_height,
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
// (w < min-width) and (h > max-height)
|
|
419
|
+
(Violation::Max, Violation::Min) => {
|
|
420
|
+
let max_width = max_size.width.unwrap();
|
|
421
|
+
let min_height = min_size.height.unwrap();
|
|
422
|
+
Size {
|
|
423
|
+
width: max_width,
|
|
424
|
+
height: min_height,
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
LayoutOutput::from_sizes(size + pb_sum, overflow_rect_for(size))
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/// Inline-level elements that are laid out as atomic inline boxes (with their own
|
|
433
|
+
/// layout box) rather than being flattened into the surrounding text layout.
|
|
434
|
+
pub(crate) fn is_inline_box_element(tag_name: &LocalName) -> bool {
|
|
435
|
+
is_replaced_element(tag_name)
|
|
436
|
+
|| *tag_name == local_name!("input")
|
|
437
|
+
|| *tag_name == local_name!("textarea")
|
|
438
|
+
|| *tag_name == local_name!("button")
|
|
439
|
+
}
|