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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
//! The configuration of the [`Renderer`](crate::renderer::Renderer) struct.
use std::sync::Arc;
use crate::Library;
/// The winding order for front-facing triangles. (Only used when the GPU renderer is used)
pub enum FaceWinding {
/// Clockwise Winding (Direct3D, etc.)
Clockwise = ul_sys::ULFaceWinding_kFaceWinding_Clockwise as isize,
/// Counter-Clockwise Winding (OpenGL, etc.)
CounterClockwise = ul_sys::ULFaceWinding_kFaceWinding_CounterClockwise as isize,
}
/// The font hinting algorithm.
pub enum FontHinting {
/// Lighter hinting algorithm-- glyphs are slightly fuzzier but better resemble their original
/// shape. This is achieved by snapping glyphs to the pixel grid only vertically which better
/// preserves inter-glyph spacing.
Smooth = ul_sys::ULFontHinting_kFontHinting_Smooth as isize,
/// Default hinting algorithm-- offers a good balance between sharpness and shape at smaller font
/// sizes.
Normal = ul_sys::ULFontHinting_kFontHinting_Normal as isize,
/// Strongest hinting algorithm-- outputs only black/white glyphs. The result is usually
/// unpleasant if the underlying TTF does not contain hints for this type of rendering.
Monochrome = ul_sys::ULFontHinting_kFontHinting_Monochrome as isize,
}
/// Configuration settings for Ultralight renderer
///
/// This is intended to be implemented by users when creating the Renderer in
/// [`Renderer::create`](crate::renderer::Renderer::create).
pub struct Config {
lib: Arc<Library>,
internal: ul_sys::ULConfig,
}
impl Config {
/// Starts the building process for the [`Config`] struct. returns a builder
/// which can be used to configure the settings.
pub fn start() -> ConfigBuilder {
ConfigBuilder::default()
}
/// Returns the underlying [`ul_sys::ULConfig`] struct, to be used locally for
/// calling the underlying C API.
pub(crate) unsafe fn to_ul(&self) -> ul_sys::ULConfig {
self.internal
}
/// Returns the library associated with this config.
pub(crate) fn lib(&self) -> &Arc<Library> {
&self.lib
}
}
impl Drop for Config {
fn drop(&mut self) {
unsafe {
self.lib.ultralight().ulDestroyConfig(self.internal);
}
}
}
/// Builder for the [`Config`] struct.
#[derive(Default)]
pub struct ConfigBuilder {
cache_path: Option<String>,
resource_path_prefix: Option<String>,
face_winding: Option<FaceWinding>,
font_hinting: Option<FontHinting>,
font_gamma: Option<f64>,
user_stylesheet: Option<String>,
force_repaint: Option<bool>,
animation_timer_delay: Option<f64>,
scroll_timer_delay: Option<f64>,
recycle_delay: Option<f64>,
memory_cache_size: Option<u32>,
page_cache_size: Option<u32>,
override_ram_size: Option<u32>,
min_large_heap_size: Option<u32>,
min_small_heap_size: Option<u32>,
num_renderer_threads: Option<u32>,
max_update_time: Option<f64>,
bitmap_alignment: Option<u32>,
}
impl ConfigBuilder {
/// A writable OS file path to store persistent Session data in.
///
/// This data may include cookies, cached network resources, indexed DB, etc.
///
/// Files are only written to disk when using a persistent Session (see
/// [`Renderer::create_session`](crate::renderer::Renderer::create_session)).
pub fn cache_path(mut self, path: &str) -> Self {
self.cache_path = Some(path.to_string());
self
}
/// The relative path to the resources folder (loaded via the FileSystem API).
/// The library loads certain resources (SSL certs, ICU data, etc.)
/// from the FileSystem API during runtime (eg, `file:///resources/cacert.pem`).
///
/// You can customize the relative file path to the resources folder by modifying this setting.
///
/// (Default = “resources/”)
pub fn resource_path_prefix(mut self, path: &str) -> Self {
self.resource_path_prefix = Some(path.to_string());
self
}
/// The winding order for front-facing triangles. (See [`FaceWinding`])
///
/// Note: This is only used when the GPU renderer is enabled.
pub fn face_winding(mut self, winding: FaceWinding) -> Self {
self.face_winding = Some(winding);
self
}
/// The hinting algorithm to use when rendering fonts. (See [`FontHinting`])
pub fn font_hinting(mut self, hinting: FontHinting) -> Self {
self.font_hinting = Some(hinting);
self
}
/// The gamma to use when compositing font glyphs, change this value to
/// adjust contrast (Adobe and Apple prefer 1.8, others may prefer 2.2).
pub fn font_gamma(mut self, gamma: f64) -> Self {
self.font_gamma = Some(gamma);
self
}
/// Default user stylesheet. You should set this to your own custom CSS
/// string to define default styles for various DOM elements, scrollbars,
/// and platform input widgets.
pub fn user_stylesheet(mut self, path: &str) -> Self {
self.user_stylesheet = Some(path.to_string());
self
}
/// Whether or not we should continuously repaint any Views or compositor
/// layers, regardless if they are dirty or not. This is mainly used to
/// diagnose painting/shader issues.
///
/// (Default = false)
pub fn force_repaint(mut self, force: bool) -> Self {
self.force_repaint = Some(force);
self
}
/// When a CSS animation is active, the amount of time (in seconds) to wait
/// before triggering another repaint.
///
/// (Default = 1.0 / 60.0)
pub fn animation_timer_delay(mut self, delay: f64) -> Self {
self.animation_timer_delay = Some(delay);
self
}
/// When a smooth scroll animation is active, the amount of time (in seconds)
/// to wait before triggering another repaint.
///
/// (Default = 1.0 / 60.0)
pub fn scroll_timer_delay(mut self, delay: f64) -> Self {
self.scroll_timer_delay = Some(delay);
self
}
/// The amount of time (in seconds) to wait before running the recycler
/// (will attempt to return excess memory back to the system).
pub fn recycle_delay(mut self, delay: f64) -> Self {
self.recycle_delay = Some(delay);
self
}
/// The size of WebCore's memory cache in bytes.
///
/// You should increase this if you anticipate handling pages with large
/// resources, Safari typically uses 128+ MiB for its cache.
///
/// `size` is in bytes.
///
/// (Default = 64 * 1024 * 1024)
pub fn memory_cache_size(mut self, size: u32) -> Self {
self.memory_cache_size = Some(size);
self
}
/// Number of pages to keep in the cache. Defaults to 0 (none).
///
/// Safari typically caches about 5 pages and maintains an on-disk cache
/// to support typical web-browsing activities. If you increase this,
/// you should probably increase the memory cache size as well.
pub fn page_cache_size(mut self, size: u32) -> Self {
self.page_cache_size = Some(size);
self
}
/// The system's physical RAM size in bytes.
///
/// JavaScriptCore tries to detect the system's physical RAM size to set
/// reasonable allocation limits. Set this to anything other than 0 to
/// override the detected value. `size` is in bytes.
///
/// This can be used to force JavaScriptCore to be more conservative
/// with its allocation strategy (at the cost of some performance).
pub fn override_ram_size(mut self, size: u32) -> Self {
self.override_ram_size = Some(size);
self
}
/// The minimum size of large VM heaps in JavaScriptCore. Set this to a lower value to make these
/// heaps start with a smaller initial value.
///
/// `size` is in bytes.
///
/// (Default = 32 * 1024 * 1024)
pub fn min_large_heap_size(mut self, size: u32) -> Self {
self.min_large_heap_size = Some(size);
self
}
/// The minimum size of small VM heaps in JavaScriptCore. Set this to a lower value to make these
/// heaps start with a smaller initial value.
///
/// `size` is in bytes.
///
/// (Default = 1 * 1024 * 1024)
pub fn min_small_heap_size(mut self, size: u32) -> Self {
self.min_small_heap_size = Some(size);
self
}
/// The number of threads to use in the Renderer (for parallel painting on the CPU, etc.).
///
/// You can set this to a certain number to limit the number of threads to spawn.
///
/// If this value is 0 (the default), the number of threads will be determined at runtime
/// using the following formula:
///
/// `max(PhysicalProcessorCount() - 1, 1)`
pub fn num_renderer_threads(mut self, threads: u32) -> Self {
self.num_renderer_threads = Some(threads);
self
}
/// The max amount of time (in seconds) to allow repeating timers to run during each call to
/// [`Renderer::update`](crate::renderer::Renderer::update).
/// The library will attempt to throttle timers and/or reschedule work if this
/// time budget is exceeded.
///
/// (Default = 1.0 / 200.0)
pub fn max_update_time(mut self, time: f64) -> Self {
self.max_update_time = Some(time);
self
}
/// **Note that this is currently is useless in this library**
/// **as we can't get the bitmap from [`Surface`](crate::surface::Surface)**
/// **when using CPU rendering**.
///
/// The alignment (in bytes) of the BitmapSurface when using the CPU renderer.
///
/// The underlying bitmap associated with each BitmapSurface will have
/// `row_bytes` padded to reach this `alignment`.
///
/// Aligning the bitmap helps improve performance when using the CPU renderer/
/// Determining the proper value to use depends on the CPU architecture and
/// max SIMD instruction set used.
///
/// We generally target the 128-bit SSE2 instruction set across most
/// PC platforms so '16' is a default and safe value to use.
///
/// You can set this to '0' to perform no padding
/// (row_bytes will always be `width * 4`) at a slight cost to performance.
pub fn bitmap_alignment(mut self, alignment: u32) -> Self {
self.bitmap_alignment = Some(alignment);
self
}
/// Builds the [`Config`] struct using the settings configured in this builder.
///
/// Returns [`None`] if failed to create [`Config`].
pub fn build(self, lib: Arc<Library>) -> Option<Config> {
let internal = unsafe { lib.ultralight().ulCreateConfig() };
if internal.is_null() {
return None;
}
set_config_str!(
internal,
self.cache_path,
lib.ultralight().ulConfigSetCachePath
);
set_config_str!(
internal,
self.resource_path_prefix,
lib.ultralight().ulConfigSetResourcePathPrefix
);
set_config!(
internal,
self.face_winding.map(|x| x as u32),
lib.ultralight().ulConfigSetFaceWinding
);
set_config!(
internal,
self.font_hinting.map(|x| x as u32),
lib.ultralight().ulConfigSetFontHinting
);
set_config!(
internal,
self.font_gamma,
lib.ultralight().ulConfigSetFontGamma
);
set_config_str!(
internal,
self.user_stylesheet,
lib.ultralight().ulConfigSetUserStylesheet
);
set_config!(
internal,
self.force_repaint,
lib.ultralight().ulConfigSetForceRepaint
);
set_config!(
internal,
self.animation_timer_delay,
lib.ultralight().ulConfigSetAnimationTimerDelay
);
set_config!(
internal,
self.scroll_timer_delay,
lib.ultralight().ulConfigSetScrollTimerDelay
);
set_config!(
internal,
self.recycle_delay,
lib.ultralight().ulConfigSetRecycleDelay
);
set_config!(
internal,
self.memory_cache_size,
lib.ultralight().ulConfigSetMemoryCacheSize
);
set_config!(
internal,
self.page_cache_size,
lib.ultralight().ulConfigSetPageCacheSize
);
set_config!(
internal,
self.override_ram_size,
lib.ultralight().ulConfigSetOverrideRAMSize
);
set_config!(
internal,
self.min_large_heap_size,
lib.ultralight().ulConfigSetMinLargeHeapSize
);
set_config!(
internal,
self.min_small_heap_size,
lib.ultralight().ulConfigSetMinSmallHeapSize
);
set_config!(
internal,
self.num_renderer_threads,
lib.ultralight().ulConfigSetNumRendererThreads
);
set_config!(
internal,
self.max_update_time,
lib.ultralight().ulConfigSetMaxUpdateTime
);
set_config!(
internal,
self.bitmap_alignment,
lib.ultralight().ulConfigSetBitmapAlignment
);
Some(Config { lib, internal })
}
}