1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use *;
/// Decides whether this host is one where `env(safe-area-inset-*)` describes a
/// real screen feature worth reserving space for.
///
/// The inset only means something where the OS draws a notch, a rounded corner
/// or a home indicator over the page. iOS is the platform that always has one
/// (and reports it in every browser, Safari or not). Desktop Safari has one on
/// notched Macs, and is the only desktop engine that reports the variable at
/// all. Every other platform — Android, Windows, Linux desktop — either has no
/// inset to report or lies about it, which is precisely the blank band the
/// contract variables were introduced to avoid.
///
/// Detection reads `navigator.userAgent` rather than `navigator.platform`,
/// because `platform` reports `MacIntel` for iPadOS and cannot separate it
/// from a real Mac, and because the value is available synchronously where a
/// `userAgentData` query would not be.
///
/// # Arguments
///
/// - `&str` - The `navigator.userAgent` string of the current host.
///
/// # Returns
///
/// - `bool` - `true` when the host is iOS-family or desktop Safari.
/// Returns whether any of the comma-separated tokens in `tokens` appears in
/// `haystack`, which the caller has already lowercased.
///
/// The tokens are a comma-separated list rather than one regex-style string
/// because `str::contains` matches substrings: a `"chrome|firefox"` literal
/// would never be found in a user agent.
///
/// # Arguments
///
/// - `&str` - The lowercased user agent to search.
/// - `&str` - The comma-separated lowercase tokens to look for.
///
/// # Returns
///
/// - `bool` - `true` when at least one token occurs in the haystack.
/// Decides whether a viewport is laid out edge-to-edge on its physical screen.
///
/// `env(safe-area-inset-*)` is only meaningful when the page really does reach
/// under the system status bar and gesture bar. An Android browser that
/// letterboxes the page below the status bar still reports a non-zero bottom
/// inset, so consuming `env()` unconditionally renders that inset as a blank
/// band. A large `screen.height - innerHeight` gap is the runtime signature of
/// such a letterbox; an immersive WebView keeps the viewport flush with the
/// screen and reports a small gap.
///
/// An explicit immersive declaration always wins, because a host that knows it
/// is edge-to-edge stays trustworthy even when the measurement is unavailable.
///
/// # Arguments
///
/// - `bool` - Whether the host declares edge-to-edge (immersive) mode.
/// - `Option<f64>` - `screen.height - window.innerHeight` in CSS pixels,
/// or `None` when the measurement is unavailable.
///
/// # Returns
///
/// - `bool` - `true` when `env()` insets may be trusted for this viewport.
/// Picks the pixel value one side's contract variable carries for a given host.
///
/// Every side falls back to `0px`, so an untrusted or unmeasured inset can
/// never widen a shell edge: only a measured inset from a genuinely
/// edge-to-edge viewport is written back.
///
/// # Arguments
///
/// - `bool` - Whether the host is a genuinely edge-to-edge (immersive) viewport.
/// - `&str` - The measured `env(safe-area-inset-*)` pixel value, which may be
/// empty or malformed.
///
/// # Returns
///
/// - `String` - The measured pixel value when it is a usable length, and `0px`
/// otherwise.
/// Measures `screen.height - window.innerHeight` for the current window.
///
/// # Returns
///
/// - `Option<f64>` - The vertical gap between the physical screen and the layout
/// viewport in CSS pixels, or `None` when either side cannot be read.
pub