1
//! Layout crate for the Azul GUI framework.
2
//!
3
//! Provides the layout solver (`solver3`), text shaping (`text3`), font
4
//! management (`font`), hit testing, page fragmentation, and widget support.
5
//! Integrates with `azul-core` for DOM types and `azul-css` for style
6
//! properties.
7

            
8
#![doc(
9
    html_logo_url = "https://raw.githubusercontent.com/maps4print/azul/master/assets/images/azul_logo_full_min.svg.png",
10
    html_favicon_url = "https://raw.githubusercontent.com/maps4print/azul/master/assets/images/favicon.ico"
11
)]
12
// Lint policy: deny correctness/safety issues, warn on style
13
#![deny(unused_must_use)]
14
#![warn(clippy::all)]
15
#![allow(
16
    clippy::non_canonical_partial_ord_impl,
17
    clippy::legacy_numeric_constants,
18
    clippy::should_implement_trait,
19
    clippy::result_unit_err,
20
    clippy::ptr_as_ptr,
21
    clippy::too_many_arguments,
22
    clippy::type_complexity,
23
    unused_imports,
24
    unused_variables,
25
    unused_mut,
26
    dead_code,
27
    unused_parens,
28
    unused_doc_comments,                   // doc comments before macro invocations
29
    unused_assignments,                    // layout solver incremental updates
30
    unused_labels,
31
    dropping_references,                   // intentional scope markers in layout solver
32
    private_interfaces,                    // internal solver types exposed for testing
33
    function_casts_as_integer,             // widget callback pointer identity
34
    improper_ctypes_definitions,           // node_graph extern fn returns ()
35
    mismatched_lifetime_syntaxes,
36
    unreachable_patterns,                  // exhaustive match in generated property code
37
    unexpected_cfgs,
38
    deprecated,                            // image crate tiff encoder
39
)]
40

            
41
#[macro_use]
42
extern crate alloc;
43
extern crate core;
44

            
45
/// Web-lift diagnostic marker: a volatile store of `val` to the absolute wasm
46
/// linear-memory address `addr` (the 0x40000–0xF0000 free band the e2e harness
47
/// peeks via `AzStartup_peekU32`). Compiles to NOTHING without the `web_lift`
48
/// feature — absolute-address stores would segfault native builds (macOS
49
/// `__PAGEZERO` covers the low 4 GiB). All in-tree diagnostic markers MUST go
50
/// through this helper rather than calling `core::ptr::write_volatile` on a
51
/// literal address directly.
52
#[inline(always)]
53
809116
pub unsafe fn az_mark(_addr: u32, _val: u32) {
54
    #[cfg(feature = "web_lift")]
55
    core::ptr::write_volatile(_addr as usize as *mut u32, _val);
56
809116
}
57

            
58
/// Read counterpart of [`az_mark`] (marker counters like `0x60758`).
59
/// Returns 0 without the `web_lift` feature.
60
#[inline(always)]
61
76164
pub unsafe fn az_mark_read(_addr: u32) -> u32 {
62
    #[cfg(feature = "web_lift")]
63
    return core::ptr::read_volatile(_addr as usize as *const u32);
64
    #[cfg(not(feature = "web_lift"))]
65
76164
    0
66
76164
}
67

            
68
/// Font traits available regardless of text layout feature.
69
pub mod font_traits;
70
/// Optional probe instrumentation. With the `probe` feature off this
71
/// is a tiny module of no-op stubs and pays zero cost.
72
pub mod probe;
73
/// Image decoding and encoding (wraps the `image` crate).
74
#[cfg(feature = "image_decoding")]
75
pub mod image;
76
/// Scroll, hover, clipboard, cursor, and focus managers.
77
#[cfg(feature = "text_layout")]
78
pub mod managers;
79
/// CSS layout solver: block, inline, flex, grid, and table formatting.
80
#[cfg(feature = "text_layout")]
81
pub mod solver3;
82

            
83
/// C-compatible string formatting via `strfmt`.
84
#[cfg(feature = "strfmt")]
85
pub mod fmt;
86
#[cfg(feature = "strfmt")]
87
pub use fmt::{FmtArg, FmtArgVec, FmtArgVecDestructor, FmtValue, fmt_string};
88

            
89
/// Built-in widgets: button, text input, tabs, tree view, node graph, etc.
90
#[cfg(feature = "widgets")]
91
pub mod widgets;
92

            
93
/// Desktop platform helpers (file dialogs, notifications).
94
#[cfg(feature = "extra")]
95
pub mod desktop;
96
/// Color parsing, XML DOM construction, and misc utilities.
97
#[cfg(feature = "extra")]
98
pub mod extra;
99

            
100
/// ICU internationalization: date/time formatting, plurals, list formatting.
101
#[cfg(any(
102
    feature = "icu",
103
    all(target_os = "macos", feature = "icu_macos"),
104
    all(target_os = "windows", feature = "icu_windows"),
105
))]
106
pub mod icu;
107
#[cfg(any(
108
    feature = "icu",
109
    all(target_os = "macos", feature = "icu_macos"),
110
    all(target_os = "windows", feature = "icu_windows"),
111
))]
112
pub use icu::{
113
    DateTimeFieldSet, FormatLength, IcuDate, IcuDateTime, IcuError,
114
    IcuLocalizer, IcuLocalizerHandle, IcuResult, IcuStringVec, IcuTime,
115
    LayoutCallbackInfoIcuExt, ListType, PluralCategory,
116
};
117

            
118
/// Project Fluent localization: message bundles, argument formatting, ZIP I/O.
119
#[cfg(feature = "fluent")]
120
pub mod fluent;
121
#[cfg(feature = "fluent")]
122
pub use fluent::{
123
    check_fluent_syntax, check_fluent_syntax_bytes, create_fluent_zip,
124
    create_fluent_zip_from_strings, export_to_zip, FluentError,
125
    FluentLanguageInfo, FluentLanguageInfoVec,
126
    FluentLocalizerHandle, FluentResult, FluentSyntaxCheckResult,
127
    FluentSyntaxError, FluentZipLoadResult, LayoutCallbackInfoFluentExt,
128
};
129

            
130
/// URL parsing (RFC 3986 compliant). Pure-Rust, always present (no TLS deps).
131
pub mod url;
132
pub use url::{Url, UrlParseError, ResultUrlUrlParseError};
133

            
134
/// File system operations (C-compatible wrappers for `std::fs`).
135
pub mod file;
136
pub use file::{
137
    dir_create, dir_create_all, dir_list, dir_delete, dir_delete_all,
138
    file_copy, path_exists, file_metadata, file_read, file_delete, file_rename, file_write,
139
    path_is_dir, path_is_file, path_join, temp_dir,
140
    DirEntry, DirEntryVec, DirEntryVecDestructor, DirEntryVecDestructorType,
141
    FileError, FileErrorKind, FileMetadata, FilePath, OptionFilePath,
142
};
143

            
144
/// HTTP client: GET/POST requests with pure-Rust TLS.
145
/// API surface always present (stub when off); ureq/rustls only pulled in with `http`.
146
pub mod http;
147
pub use http::{
148
    download_bytes, download_bytes_with_config, http_get,
149
    http_get_with_config, is_url_reachable, HttpError, HttpHeader,
150
    HttpRequestConfig, HttpResponse, HttpResponseTooLargeError, HttpResult,
151
    HttpStatusError,
152
};
153

            
154
/// JSON parsing and serialization for the C API.
155
#[cfg(feature = "json")]
156
pub mod json;
157
#[cfg(feature = "json")]
158
pub use json::{
159
    json_parse, json_parse_bytes, json_stringify, json_stringify_pretty,
160
    Json, JsonInternal, JsonKeyValue, JsonKeyValueVec, JsonKeyValueVecDestructor, JsonKeyValueVecDestructorType,
161
    JsonParseError, JsonType, JsonVec,
162
    ResultJsonJsonParseError, OptionJson, OptionJsonVec, OptionJsonKeyValueVec,
163
};
164

            
165
/// ZIP file creation, extraction, and listing.
166
#[cfg(feature = "zip_support")]
167
pub mod zip;
168
#[cfg(feature = "zip_support")]
169
pub use zip::{
170
    zip_create, zip_create_from_files, zip_extract_all, zip_list_contents,
171
    ZipFile, ZipFileEntry, ZipFileEntryVec, ZipPathEntry, ZipPathEntryVec,
172
    ZipReadConfig, ZipWriteConfig, ZipReadError, ZipWriteError,
173
};
174

            
175
/// Icon provider: resolves icons from Material Icons font, images, or ZIP packs.
176
pub mod icon;
177
pub use icon::{
178
    // Resolver
179
    default_icon_resolver,
180
    // Data types for RefAny
181
    ImageIconData, FontIconData,
182
    // Helpers
183
    create_default_icon_provider,
184
    register_material_icons,
185
    register_embedded_material_icons,
186
};
187
// Re-export core icon types
188
pub use azul_core::icon::{
189
    IconProviderHandle, IconResolverCallbackType,
190
    resolve_icons_in_styled_dom, OptionIconProviderHandle,
191
};
192

            
193
/// Callback handling for layout events (invocation, result processing).
194
#[cfg(feature = "text_layout")]
195
pub mod callbacks;
196
/// CPU-based software rendering (no GPU required).
197
#[cfg(feature = "cpurender")]
198
pub mod cpurender;
199
/// Glyph path and cell cache for CPU text rendering.
200
#[cfg(feature = "cpurender")]
201
pub mod glyph_cache;
202
/// Default keyboard actions (copy, paste, select-all, undo, etc.).
203
#[cfg(feature = "text_layout")]
204
pub mod default_actions;
205
/// Event determination: maps raw input to DOM node callbacks.
206
#[cfg(feature = "text_layout")]
207
pub mod event_determination;
208
/// Font parsing, metrics extraction, and subsetting.
209
#[cfg(feature = "text_layout")]
210
pub mod font;
211

            
212
/// Headless backend for CPU-only rendering without a display server.
213
/// Used with `AZUL_HEADLESS=1` for E2E testing, CI, and screenshot capture.
214
#[cfg(feature = "text_layout")]
215
pub mod headless;
216
// Re-export allsorts types needed by printpdf
217
#[cfg(feature = "text_layout")]
218
pub use allsorts::subset::CmapTarget;
219
#[cfg(feature = "text_layout")]
220
pub use font::parsed::{
221
    FontParseWarning, FontParseWarningSeverity, FontType, OwnedGlyph, ParsedFont, PdfFontMetrics,
222
    SubsetFont,
223
};
224
// Re-export hyphenation for external crates (like printpdf)
225
#[cfg(feature = "text_layout_hyphenation")]
226
pub use hyphenation;
227
/// CSS fragmentation engine for paged media (page/column breaks).
228
pub mod fragmentation;
229
/// Hit-testing: maps screen coordinates to DOM nodes.
230
#[cfg(feature = "text_layout")]
231
pub mod hit_test;
232
/// Paged media layout engine (infinite canvas with physical spacers).
233
pub mod paged;
234
/// Text shaping, line breaking (Knuth-Plass), and inline formatting.
235
#[cfg(feature = "text_layout")]
236
pub mod text3;
237
/// Thread callback wrappers for the C API.
238
#[cfg(feature = "text_layout")]
239
pub mod thread;
240
/// Timer callback wrappers for the C API.
241
#[cfg(feature = "text_layout")]
242
pub mod timer;
243
/// Scroll physics timer for momentum-based smooth scrolling.
244
#[cfg(feature = "text_layout")]
245
pub mod scroll_timer;
246
/// Window layout management: relayout, event processing, state sync.
247
#[cfg(feature = "text_layout")]
248
pub mod window;
249
/// Window state types (keyboard, mouse, DPI, focus).
250
#[cfg(feature = "text_layout")]
251
pub mod window_state;
252
/// XML and XHTML parsing for declarative UI definitions.
253
#[cfg(feature = "xml")]
254
pub mod xml;
255

            
256
// Export the main layout function and window management
257
pub use fragmentation::{
258
    BoxBreakBehavior, BreakDecision, FragmentationDefaults, FragmentationLayoutContext,
259
    KeepTogetherPriority, PageCounter, PageFragment, PageMargins, PageNumberStyle, PageSlot,
260
    PageSlotContent, PageSlotPosition, PageTemplate,
261
};
262
#[cfg(feature = "text_layout")]
263
pub use hit_test::{CursorTypeHitTest, FullHitTest};
264
pub use paged::FragmentationState;
265
#[cfg(feature = "text_layout")]
266
pub use solver3::cache::LayoutCache as Solver3LayoutCache;
267
#[cfg(feature = "text_layout")]
268
pub use solver3::display_list::DisplayList as DisplayList3;
269
#[cfg(feature = "text_layout")]
270
pub use solver3::layout_document;
271
#[cfg(feature = "text_layout")]
272
pub use solver3::paged_layout::layout_document_paged;
273
#[cfg(feature = "text_layout")]
274
pub use solver3::{LayoutContext, LayoutError, Result as LayoutResult3};
275
#[cfg(feature = "text_layout")]
276
pub use text3::cache::{FontContext, FontManager, TextShapingCache};
277
/// Backwards-compat alias for the old `TextLayoutCache` name.
278
/// Will be dropped at the next API revision; new code should use
279
/// [`TextShapingCache`] directly.
280
#[cfg(feature = "text_layout")]
281
pub use text3::cache::TextShapingCache as TextLayoutCache;
282
#[cfg(feature = "font_async_registry")]
283
pub use rust_fontconfig::registry::FcFontRegistry;
284
#[cfg(feature = "text_layout")]
285
pub use window::{CursorBlinkTimerAction, LayoutWindow, ScrollbarDragState, TooltipTimerAction};
286
#[cfg(feature = "text_layout")]
287
pub use managers::text_input::{PendingTextEdit, OptionPendingTextEdit};
288

            
289
#[cfg(feature = "text_layout")]
290
/// Parses raw font bytes into a [`FontRef`](azul_css::props::basic::FontRef)
291
/// suitable for use in the layout system.
292
pub fn parse_font_fn(
293
    source: azul_core::resources::LoadedFontSource,
294
) -> Option<azul_css::props::basic::FontRef> {
295
    use crate::font::parsed::ParsedFont;
296

            
297
    ParsedFont::from_bytes(
298
        source.data.as_ref(),
299
        source.index as usize,
300
        &mut Vec::new(), // Ignore warnings for now
301
    )
302
    .map(parsed_font_to_font_ref)
303
}
304

            
305
#[cfg(feature = "text_layout")]
306
/// Wraps a [`ParsedFont`] in a [`FontRef`](azul_css::props::basic::FontRef),
307
/// transferring ownership to the returned handle.
308
12012
pub fn parsed_font_to_font_ref(
309
12012
    parsed_font: crate::font::parsed::ParsedFont,
310
12012
) -> azul_css::props::basic::FontRef {
311
    use core::ffi::c_void;
312

            
313
12012
    extern "C" fn parsed_font_destructor(ptr: *mut c_void) {
314
12012
        unsafe {
315
12012
            let _ = Box::from_raw(ptr as *mut crate::font::parsed::ParsedFont);
316
12012
        }
317
12012
    }
318

            
319
12012
    let boxed = Box::new(parsed_font);
320
12012
    let raw_ptr = Box::into_raw(boxed) as *const c_void;
321
12012
    azul_css::props::basic::FontRef::new(raw_ptr, parsed_font_destructor)
322
12012
}
323

            
324
#[cfg(feature = "text_layout")]
325
/// Recovers a reference to the [`ParsedFont`] stored inside a [`FontRef`](azul_css::props::basic::FontRef).
326
///
327
/// # Safety contract
328
/// The `font_ref` must have been created by [`parsed_font_to_font_ref`],
329
/// so that `font_ref.parsed` points to a valid `ParsedFont`.
330
132
pub fn font_ref_to_parsed_font(
331
132
    font_ref: &azul_css::props::basic::FontRef,
332
132
) -> &crate::font::parsed::ParsedFont {
333
    // SAFETY: `font_ref.parsed` was created by `parsed_font_to_font_ref`
334
    // via `Box::into_raw`, so it points to a valid, aligned `ParsedFont`.
335
132
    unsafe { &*(font_ref.parsed as *const crate::font::parsed::ParsedFont) }
336
132
}