1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #![allow(clippy::missing_safety_doc)]
6 #![allow(clippy::not_unsafe_ptr_arg_deref)]
7
8 use gleam::gl;
9 use std::cell::RefCell;
10 #[cfg(not(target_os = "macos"))]
11 use std::ffi::OsString;
12 use std::ffi::{CStr, CString};
13 use std::io::Cursor;
14 use std::marker::PhantomData;
15 use std::ops::Range;
16 #[cfg(target_os = "android")]
17 use std::os::raw::c_int;
18 use std::os::raw::{c_char, c_float, c_void};
19 #[cfg(not(any(target_os = "macos", target_os = "windows")))]
20 use std::os::unix::ffi::OsStringExt;
21 #[cfg(target_os = "windows")]
22 use std::os::windows::ffi::OsStringExt;
23 use std::path::PathBuf;
24 use std::rc::Rc;
25 use std::sync::atomic::{AtomicUsize, Ordering};
26 use std::sync::Arc;
27 use std::time::Duration;
28 use std::{env, mem, ptr, slice};
29 use thin_vec::ThinVec;
30
31 use euclid::SideOffsets2D;
32 use moz2d_renderer::Moz2dBlobImageHandler;
33 use nsstring::nsAString;
34 use num_cpus;
35 use program_cache::{remove_disk_cache, WrProgramCache};
36 use rayon;
37 use tracy_rs::register_thread_with_profiler;
38 use webrender::sw_compositor::SwCompositor;
39 use webrender::{
40 api::units::*, api::*, render_api::*, set_profiler_hooks, AsyncPropertySampler, AsyncScreenshotHandle, Compositor,
41 CompositorCapabilities, CompositorConfig, CompositorSurfaceTransform, DebugFlags, Device, MappableCompositor,
42 MappedTileInfo, NativeSurfaceId, NativeSurfaceInfo, NativeTileId, PartialPresentCompositor, PipelineInfo,
43 ProfilerHooks, RecordedFrameHandle, Renderer, RendererOptions, RendererStats, SWGLCompositeSurfaceInfo,
44 SceneBuilderHooks, ShaderPrecacheFlags, Shaders, SharedShaders, TextureCacheConfig, UploadMethod, WindowVisibility,
45 ONE_TIME_USAGE_HINT,
46 };
47 use wr_malloc_size_of::MallocSizeOfOps;
48
49 extern "C" {
50 #[cfg(target_os = "android")]
__android_log_write(prio: c_int, tag: *const c_char, text: *const c_char) -> c_int51 fn __android_log_write(prio: c_int, tag: *const c_char, text: *const c_char) -> c_int;
52 }
53
54 /// The unique id for WR resource identification.
55 static NEXT_NAMESPACE_ID: AtomicUsize = AtomicUsize::new(1);
56
57 /// Special value handled in this wrapper layer to signify a redundant clip chain.
58 pub const ROOT_CLIP_CHAIN: u64 = !0;
59
next_namespace_id() -> IdNamespace60 fn next_namespace_id() -> IdNamespace {
61 IdNamespace(NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed) as u32)
62 }
63
64 /// Whether a border should be antialiased.
65 #[repr(C)]
66 #[derive(Eq, PartialEq, Copy, Clone)]
67 pub enum AntialiasBorder {
68 No = 0,
69 Yes,
70 }
71
72 /// Used to indicate if an image is opaque, or has an alpha channel.
73 #[repr(u8)]
74 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
75 pub enum OpacityType {
76 Opaque = 0,
77 HasAlphaChannel = 1,
78 }
79
80 /// cbindgen:field-names=[mHandle]
81 /// cbindgen:derive-lt=true
82 /// cbindgen:derive-lte=true
83 /// cbindgen:derive-neq=true
84 type WrEpoch = Epoch;
85 /// cbindgen:field-names=[mHandle]
86 /// cbindgen:derive-lt=true
87 /// cbindgen:derive-lte=true
88 /// cbindgen:derive-neq=true
89 pub type WrIdNamespace = IdNamespace;
90
91 /// cbindgen:field-names=[mNamespace, mHandle]
92 type WrDocumentId = DocumentId;
93 /// cbindgen:field-names=[mNamespace, mHandle]
94 type WrPipelineId = PipelineId;
95 /// cbindgen:field-names=[mNamespace, mHandle]
96 /// cbindgen:derive-neq=true
97 type WrImageKey = ImageKey;
98 /// cbindgen:field-names=[mNamespace, mHandle]
99 pub type WrFontKey = FontKey;
100 /// cbindgen:field-names=[mNamespace, mHandle]
101 pub type WrFontInstanceKey = FontInstanceKey;
102 /// cbindgen:field-names=[mNamespace, mHandle]
103 type WrYuvColorSpace = YuvColorSpace;
104 /// cbindgen:field-names=[mNamespace, mHandle]
105 type WrColorDepth = ColorDepth;
106 /// cbindgen:field-names=[mNamespace, mHandle]
107 type WrColorRange = ColorRange;
108
109 #[inline]
clip_chain_id_to_webrender(id: u64, pipeline_id: WrPipelineId) -> ClipId110 fn clip_chain_id_to_webrender(id: u64, pipeline_id: WrPipelineId) -> ClipId {
111 if id == ROOT_CLIP_CHAIN {
112 ClipId::root(pipeline_id)
113 } else {
114 ClipId::ClipChain(ClipChainId(id, pipeline_id))
115 }
116 }
117
118 #[repr(C)]
119 pub struct WrSpaceAndClipChain {
120 space: WrSpatialId,
121 clip_chain: u64,
122 }
123
124 impl WrSpaceAndClipChain {
to_webrender(&self, pipeline_id: WrPipelineId) -> SpaceAndClipInfo125 fn to_webrender(&self, pipeline_id: WrPipelineId) -> SpaceAndClipInfo {
126 //Warning: special case here to support dummy clip chain
127 SpaceAndClipInfo {
128 spatial_id: self.space.to_webrender(pipeline_id),
129 clip_id: clip_chain_id_to_webrender(self.clip_chain, pipeline_id),
130 }
131 }
132 }
133
134 #[repr(C)]
135 pub enum WrStackingContextClip {
136 None,
137 ClipId(WrClipId),
138 ClipChain(u64),
139 }
140
141 impl WrStackingContextClip {
to_webrender(&self, pipeline_id: WrPipelineId) -> Option<ClipId>142 fn to_webrender(&self, pipeline_id: WrPipelineId) -> Option<ClipId> {
143 match *self {
144 WrStackingContextClip::None => None,
145 WrStackingContextClip::ClipChain(id) => Some(clip_chain_id_to_webrender(id, pipeline_id)),
146 WrStackingContextClip::ClipId(id) => Some(id.to_webrender(pipeline_id)),
147 }
148 }
149 }
150
make_slice<'a, T>(ptr: *const T, len: usize) -> &'a [T]151 unsafe fn make_slice<'a, T>(ptr: *const T, len: usize) -> &'a [T] {
152 if ptr.is_null() {
153 &[]
154 } else {
155 slice::from_raw_parts(ptr, len)
156 }
157 }
158
make_slice_mut<'a, T>(ptr: *mut T, len: usize) -> &'a mut [T]159 unsafe fn make_slice_mut<'a, T>(ptr: *mut T, len: usize) -> &'a mut [T] {
160 if ptr.is_null() {
161 &mut []
162 } else {
163 slice::from_raw_parts_mut(ptr, len)
164 }
165 }
166
167 pub struct DocumentHandle {
168 api: RenderApi,
169 document_id: DocumentId,
170 // One of the two options below is Some and the other None at all times.
171 // It would be nice to model with an enum, however it is tricky to express
172 // moving a variant's content into another variant without moving the
173 // containing enum.
174 hit_tester_request: Option<HitTesterRequest>,
175 hit_tester: Option<Arc<dyn ApiHitTester>>,
176 }
177
178 impl DocumentHandle {
new( api: RenderApi, hit_tester: Option<Arc<dyn ApiHitTester>>, size: DeviceIntSize, id: u32, ) -> DocumentHandle179 pub fn new(
180 api: RenderApi,
181 hit_tester: Option<Arc<dyn ApiHitTester>>,
182 size: DeviceIntSize,
183 id: u32,
184 ) -> DocumentHandle {
185 let doc = api.add_document_with_id(size, id);
186 let hit_tester_request = if hit_tester.is_none() {
187 // Request the hit tester early to reduce the likelihood of blocking on the
188 // first hit testing query.
189 Some(api.request_hit_tester(doc))
190 } else {
191 None
192 };
193
194 DocumentHandle {
195 api,
196 document_id: doc,
197 hit_tester_request,
198 hit_tester,
199 }
200 }
201
ensure_hit_tester(&mut self) -> &Arc<dyn ApiHitTester>202 fn ensure_hit_tester(&mut self) -> &Arc<dyn ApiHitTester> {
203 if let Some(ref ht) = self.hit_tester {
204 return ht;
205 }
206 self.hit_tester = Some(self.hit_tester_request.take().unwrap().resolve());
207 self.hit_tester.as_ref().unwrap()
208 }
209 }
210
211 #[repr(C)]
212 pub struct WrVecU8 {
213 data: *mut u8,
214 length: usize,
215 capacity: usize,
216 }
217
218 impl WrVecU8 {
into_vec(self) -> Vec<u8>219 fn into_vec(self) -> Vec<u8> {
220 unsafe { Vec::from_raw_parts(self.data, self.length, self.capacity) }
221 }
222
223 // Equivalent to `into_vec` but clears self instead of consuming the value.
flush_into_vec(&mut self) -> Vec<u8>224 fn flush_into_vec(&mut self) -> Vec<u8> {
225 self.convert_into_vec::<u8>()
226 }
227
228 // Like flush_into_vec, but also does an unsafe conversion to the desired type.
convert_into_vec<T>(&mut self) -> Vec<T>229 fn convert_into_vec<T>(&mut self) -> Vec<T> {
230 let vec = unsafe {
231 Vec::from_raw_parts(
232 self.data as *mut T,
233 self.length / mem::size_of::<T>(),
234 self.capacity / mem::size_of::<T>(),
235 )
236 };
237 self.data = ptr::null_mut();
238 self.length = 0;
239 self.capacity = 0;
240 vec
241 }
242
from_vec(mut v: Vec<u8>) -> WrVecU8243 fn from_vec(mut v: Vec<u8>) -> WrVecU8 {
244 let w = WrVecU8 {
245 data: v.as_mut_ptr(),
246 length: v.len(),
247 capacity: v.capacity(),
248 };
249 mem::forget(v);
250 w
251 }
252
reserve(&mut self, len: usize)253 fn reserve(&mut self, len: usize) {
254 let mut vec = self.flush_into_vec();
255 vec.reserve(len);
256 *self = Self::from_vec(vec);
257 }
258
push_bytes(&mut self, bytes: &[u8])259 fn push_bytes(&mut self, bytes: &[u8]) {
260 let mut vec = self.flush_into_vec();
261 vec.extend_from_slice(bytes);
262 *self = Self::from_vec(vec);
263 }
264 }
265
266 #[no_mangle]
wr_vec_u8_push_bytes(v: &mut WrVecU8, bytes: ByteSlice)267 pub extern "C" fn wr_vec_u8_push_bytes(v: &mut WrVecU8, bytes: ByteSlice) {
268 v.push_bytes(bytes.as_slice());
269 }
270
271 #[no_mangle]
wr_vec_u8_reserve(v: &mut WrVecU8, len: usize)272 pub extern "C" fn wr_vec_u8_reserve(v: &mut WrVecU8, len: usize) {
273 v.reserve(len);
274 }
275
276 #[no_mangle]
wr_vec_u8_free(v: WrVecU8)277 pub extern "C" fn wr_vec_u8_free(v: WrVecU8) {
278 v.into_vec();
279 }
280
281 #[repr(C)]
282 pub struct ByteSlice<'a> {
283 buffer: *const u8,
284 len: usize,
285 _phantom: PhantomData<&'a ()>,
286 }
287
288 impl<'a> ByteSlice<'a> {
new(slice: &'a [u8]) -> ByteSlice<'a>289 pub fn new(slice: &'a [u8]) -> ByteSlice<'a> {
290 ByteSlice {
291 buffer: slice.as_ptr(),
292 len: slice.len(),
293 _phantom: PhantomData,
294 }
295 }
296
as_slice(&self) -> &'a [u8]297 pub fn as_slice(&self) -> &'a [u8] {
298 unsafe { make_slice(self.buffer, self.len) }
299 }
300 }
301
302 #[repr(C)]
303 pub struct MutByteSlice<'a> {
304 buffer: *mut u8,
305 len: usize,
306 _phantom: PhantomData<&'a ()>,
307 }
308
309 impl<'a> MutByteSlice<'a> {
new(slice: &'a mut [u8]) -> MutByteSlice<'a>310 pub fn new(slice: &'a mut [u8]) -> MutByteSlice<'a> {
311 let len = slice.len();
312 MutByteSlice {
313 buffer: slice.as_mut_ptr(),
314 len,
315 _phantom: PhantomData,
316 }
317 }
318
as_mut_slice(&mut self) -> &'a mut [u8]319 pub fn as_mut_slice(&mut self) -> &'a mut [u8] {
320 unsafe { make_slice_mut(self.buffer, self.len) }
321 }
322 }
323
324 #[repr(C)]
325 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
326 pub struct WrImageDescriptor {
327 pub format: ImageFormat,
328 pub width: i32,
329 pub height: i32,
330 pub stride: i32,
331 pub opacity: OpacityType,
332 // TODO(gw): Remove this flag (use prim flags instead).
333 pub prefer_compositor_surface: bool,
334 }
335
336 impl<'a> From<&'a WrImageDescriptor> for ImageDescriptor {
from(desc: &'a WrImageDescriptor) -> ImageDescriptor337 fn from(desc: &'a WrImageDescriptor) -> ImageDescriptor {
338 let mut flags = ImageDescriptorFlags::empty();
339
340 if desc.opacity == OpacityType::Opaque {
341 flags |= ImageDescriptorFlags::IS_OPAQUE;
342 }
343
344 ImageDescriptor {
345 size: DeviceIntSize::new(desc.width, desc.height),
346 stride: if desc.stride != 0 { Some(desc.stride) } else { None },
347 format: desc.format,
348 offset: 0,
349 flags,
350 }
351 }
352 }
353
354 #[repr(u32)]
355 #[allow(dead_code)]
356 enum WrExternalImageType {
357 RawData,
358 NativeTexture,
359 Invalid,
360 }
361
362 #[repr(C)]
363 struct WrExternalImage {
364 image_type: WrExternalImageType,
365
366 // external texture handle
367 handle: u32,
368 // external texture coordinate
369 u0: f32,
370 v0: f32,
371 u1: f32,
372 v1: f32,
373
374 // external image buffer
375 buff: *const u8,
376 size: usize,
377 }
378
379 extern "C" {
wr_renderer_lock_external_image( renderer: *mut c_void, external_image_id: ExternalImageId, channel_index: u8, rendering: ImageRendering, ) -> WrExternalImage380 fn wr_renderer_lock_external_image(
381 renderer: *mut c_void,
382 external_image_id: ExternalImageId,
383 channel_index: u8,
384 rendering: ImageRendering,
385 ) -> WrExternalImage;
wr_renderer_unlock_external_image(renderer: *mut c_void, external_image_id: ExternalImageId, channel_index: u8)386 fn wr_renderer_unlock_external_image(renderer: *mut c_void, external_image_id: ExternalImageId, channel_index: u8);
387 }
388
389 #[repr(C)]
390 #[derive(Copy, Clone, Debug)]
391 pub struct WrExternalImageHandler {
392 external_image_obj: *mut c_void,
393 }
394
395 impl ExternalImageHandler for WrExternalImageHandler {
lock(&mut self, id: ExternalImageId, channel_index: u8, rendering: ImageRendering) -> ExternalImage396 fn lock(&mut self, id: ExternalImageId, channel_index: u8, rendering: ImageRendering) -> ExternalImage {
397 let image = unsafe { wr_renderer_lock_external_image(self.external_image_obj, id, channel_index, rendering) };
398 ExternalImage {
399 uv: TexelRect::new(image.u0, image.v0, image.u1, image.v1),
400 source: match image.image_type {
401 WrExternalImageType::NativeTexture => ExternalImageSource::NativeTexture(image.handle),
402 WrExternalImageType::RawData => {
403 ExternalImageSource::RawData(unsafe { make_slice(image.buff, image.size) })
404 },
405 WrExternalImageType::Invalid => ExternalImageSource::Invalid,
406 },
407 }
408 }
409
unlock(&mut self, id: ExternalImageId, channel_index: u8)410 fn unlock(&mut self, id: ExternalImageId, channel_index: u8) {
411 unsafe {
412 wr_renderer_unlock_external_image(self.external_image_obj, id, channel_index);
413 }
414 }
415 }
416
417 #[repr(C)]
418 #[derive(Clone, Copy)]
419 // Used for ComponentTransfer only
420 pub struct WrFilterData {
421 funcR_type: ComponentTransferFuncType,
422 R_values: *mut c_float,
423 R_values_count: usize,
424 funcG_type: ComponentTransferFuncType,
425 G_values: *mut c_float,
426 G_values_count: usize,
427 funcB_type: ComponentTransferFuncType,
428 B_values: *mut c_float,
429 B_values_count: usize,
430 funcA_type: ComponentTransferFuncType,
431 A_values: *mut c_float,
432 A_values_count: usize,
433 }
434
435 #[repr(u32)]
436 #[derive(Debug)]
437 pub enum WrAnimationType {
438 Transform = 0,
439 Opacity = 1,
440 BackgroundColor = 2,
441 }
442
443 #[repr(C)]
444 pub struct WrAnimationProperty {
445 effect_type: WrAnimationType,
446 id: u64,
447 key: SpatialTreeItemKey,
448 }
449
450 /// cbindgen:derive-eq=false
451 #[repr(C)]
452 #[derive(Debug)]
453 pub struct WrAnimationPropertyValue<T> {
454 pub id: u64,
455 pub value: T,
456 }
457
458 pub type WrTransformProperty = WrAnimationPropertyValue<LayoutTransform>;
459 pub type WrOpacityProperty = WrAnimationPropertyValue<f32>;
460 pub type WrColorProperty = WrAnimationPropertyValue<ColorF>;
461
462 /// cbindgen:field-names=[mHandle]
463 /// cbindgen:derive-lt=true
464 /// cbindgen:derive-lte=true
465 #[repr(C)]
466 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
467 pub struct WrWindowId(u64);
468
469 #[repr(C)]
470 #[derive(Debug)]
471 pub struct WrComputedTransformData {
472 pub scale_from: LayoutSize,
473 pub vertical_flip: bool,
474 pub rotation: WrRotation,
475 pub key: SpatialTreeItemKey,
476 }
477
478 #[repr(C)]
479 pub struct WrTransformInfo {
480 pub transform: LayoutTransform,
481 pub key: SpatialTreeItemKey,
482 }
483
get_proc_address(glcontext_ptr: *mut c_void, name: &str) -> *const c_void484 fn get_proc_address(glcontext_ptr: *mut c_void, name: &str) -> *const c_void {
485 extern "C" {
486 fn get_proc_address_from_glcontext(glcontext_ptr: *mut c_void, procname: *const c_char) -> *const c_void;
487 }
488
489 let symbol_name = CString::new(name).unwrap();
490 let symbol = unsafe { get_proc_address_from_glcontext(glcontext_ptr, symbol_name.as_ptr()) };
491 symbol as *const _
492 }
493
494 #[repr(C)]
495 pub enum TelemetryProbe {
496 SceneBuildTime = 0,
497 SceneSwapTime = 1,
498 FrameBuildTime = 2,
499 }
500
501 extern "C" {
is_in_compositor_thread() -> bool502 fn is_in_compositor_thread() -> bool;
is_in_render_thread() -> bool503 fn is_in_render_thread() -> bool;
is_in_main_thread() -> bool504 fn is_in_main_thread() -> bool;
is_glcontext_gles(glcontext_ptr: *mut c_void) -> bool505 fn is_glcontext_gles(glcontext_ptr: *mut c_void) -> bool;
is_glcontext_angle(glcontext_ptr: *mut c_void) -> bool506 fn is_glcontext_angle(glcontext_ptr: *mut c_void) -> bool;
gfx_wr_resource_path_override() -> *const c_char507 fn gfx_wr_resource_path_override() -> *const c_char;
gfx_wr_use_optimized_shaders() -> bool508 fn gfx_wr_use_optimized_shaders() -> bool;
509 // TODO: make gfx_critical_error() work.
510 // We still have problem to pass the error message from render/render_backend
511 // thread to main thread now.
512 #[allow(dead_code)]
gfx_critical_error(msg: *const c_char)513 fn gfx_critical_error(msg: *const c_char);
gfx_critical_note(msg: *const c_char)514 fn gfx_critical_note(msg: *const c_char);
record_telemetry_time(probe: TelemetryProbe, time_ns: u64)515 fn record_telemetry_time(probe: TelemetryProbe, time_ns: u64);
gfx_wr_set_crash_annotation(annotation: CrashAnnotation, value: *const c_char)516 fn gfx_wr_set_crash_annotation(annotation: CrashAnnotation, value: *const c_char);
gfx_wr_clear_crash_annotation(annotation: CrashAnnotation)517 fn gfx_wr_clear_crash_annotation(annotation: CrashAnnotation);
518 }
519
520 struct CppNotifier {
521 window_id: WrWindowId,
522 }
523
524 unsafe impl Send for CppNotifier {}
525
526 extern "C" {
wr_notifier_wake_up(window_id: WrWindowId, composite_needed: bool)527 fn wr_notifier_wake_up(window_id: WrWindowId, composite_needed: bool);
wr_notifier_new_frame_ready(window_id: WrWindowId)528 fn wr_notifier_new_frame_ready(window_id: WrWindowId);
wr_notifier_nop_frame_done(window_id: WrWindowId)529 fn wr_notifier_nop_frame_done(window_id: WrWindowId);
wr_notifier_external_event(window_id: WrWindowId, raw_event: usize)530 fn wr_notifier_external_event(window_id: WrWindowId, raw_event: usize);
wr_schedule_render(window_id: WrWindowId, reasons: RenderReasons)531 fn wr_schedule_render(window_id: WrWindowId, reasons: RenderReasons);
532 // NOTE: This moves away from pipeline_info.
wr_finished_scene_build(window_id: WrWindowId, pipeline_info: &mut WrPipelineInfo)533 fn wr_finished_scene_build(window_id: WrWindowId, pipeline_info: &mut WrPipelineInfo);
534
wr_transaction_notification_notified(handler: usize, when: Checkpoint)535 fn wr_transaction_notification_notified(handler: usize, when: Checkpoint);
536 }
537
538 impl RenderNotifier for CppNotifier {
clone(&self) -> Box<dyn RenderNotifier>539 fn clone(&self) -> Box<dyn RenderNotifier> {
540 Box::new(CppNotifier {
541 window_id: self.window_id,
542 })
543 }
544
wake_up(&self, composite_needed: bool)545 fn wake_up(&self, composite_needed: bool) {
546 unsafe {
547 wr_notifier_wake_up(self.window_id, composite_needed);
548 }
549 }
550
new_frame_ready(&self, _: DocumentId, _scrolled: bool, composite_needed: bool, render_time_ns: Option<u64>)551 fn new_frame_ready(&self, _: DocumentId, _scrolled: bool, composite_needed: bool, render_time_ns: Option<u64>) {
552 unsafe {
553 if let Some(time) = render_time_ns {
554 record_telemetry_time(TelemetryProbe::FrameBuildTime, time);
555 }
556 if composite_needed {
557 wr_notifier_new_frame_ready(self.window_id);
558 } else {
559 wr_notifier_nop_frame_done(self.window_id);
560 }
561 }
562 }
563
external_event(&self, event: ExternalEvent)564 fn external_event(&self, event: ExternalEvent) {
565 unsafe {
566 wr_notifier_external_event(self.window_id, event.unwrap());
567 }
568 }
569 }
570
571 struct MozCrashAnnotator;
572
573 unsafe impl Send for MozCrashAnnotator {}
574
575 impl CrashAnnotator for MozCrashAnnotator {
set(&self, annotation: CrashAnnotation, value: &std::ffi::CStr)576 fn set(&self, annotation: CrashAnnotation, value: &std::ffi::CStr) {
577 unsafe {
578 gfx_wr_set_crash_annotation(annotation, value.as_ptr());
579 }
580 }
581
clear(&self, annotation: CrashAnnotation)582 fn clear(&self, annotation: CrashAnnotation) {
583 unsafe {
584 gfx_wr_clear_crash_annotation(annotation);
585 }
586 }
587
box_clone(&self) -> Box<dyn CrashAnnotator>588 fn box_clone(&self) -> Box<dyn CrashAnnotator> {
589 Box::new(MozCrashAnnotator)
590 }
591 }
592
593 #[no_mangle]
wr_renderer_set_clear_color(renderer: &mut Renderer, color: ColorF)594 pub extern "C" fn wr_renderer_set_clear_color(renderer: &mut Renderer, color: ColorF) {
595 renderer.set_clear_color(color);
596 }
597
598 #[no_mangle]
wr_renderer_set_external_image_handler( renderer: &mut Renderer, external_image_handler: &mut WrExternalImageHandler, )599 pub extern "C" fn wr_renderer_set_external_image_handler(
600 renderer: &mut Renderer,
601 external_image_handler: &mut WrExternalImageHandler,
602 ) {
603 renderer.set_external_image_handler(Box::new(*external_image_handler));
604 }
605
606 #[no_mangle]
wr_renderer_update(renderer: &mut Renderer)607 pub extern "C" fn wr_renderer_update(renderer: &mut Renderer) {
608 renderer.update();
609 }
610
611 #[no_mangle]
wr_renderer_render( renderer: &mut Renderer, width: i32, height: i32, buffer_age: usize, out_stats: &mut RendererStats, out_dirty_rects: &mut ThinVec<DeviceIntRect>, ) -> bool612 pub extern "C" fn wr_renderer_render(
613 renderer: &mut Renderer,
614 width: i32,
615 height: i32,
616 buffer_age: usize,
617 out_stats: &mut RendererStats,
618 out_dirty_rects: &mut ThinVec<DeviceIntRect>,
619 ) -> bool {
620 match renderer.render(DeviceIntSize::new(width, height), buffer_age) {
621 Ok(results) => {
622 *out_stats = results.stats;
623 out_dirty_rects.extend(results.dirty_rects);
624 true
625 },
626 Err(errors) => {
627 for e in errors {
628 warn!(" Failed to render: {:?}", e);
629 let msg = CString::new(format!("wr_renderer_render: {:?}", e)).unwrap();
630 unsafe {
631 gfx_critical_note(msg.as_ptr());
632 }
633 }
634 false
635 },
636 }
637 }
638
639 #[no_mangle]
wr_renderer_force_redraw(renderer: &mut Renderer)640 pub extern "C" fn wr_renderer_force_redraw(renderer: &mut Renderer) {
641 renderer.force_redraw();
642 }
643
644 #[no_mangle]
wr_renderer_record_frame( renderer: &mut Renderer, image_format: ImageFormat, out_handle: &mut RecordedFrameHandle, out_width: &mut i32, out_height: &mut i32, ) -> bool645 pub extern "C" fn wr_renderer_record_frame(
646 renderer: &mut Renderer,
647 image_format: ImageFormat,
648 out_handle: &mut RecordedFrameHandle,
649 out_width: &mut i32,
650 out_height: &mut i32,
651 ) -> bool {
652 if let Some((handle, size)) = renderer.record_frame(image_format) {
653 *out_handle = handle;
654 *out_width = size.width;
655 *out_height = size.height;
656
657 true
658 } else {
659 false
660 }
661 }
662
663 #[no_mangle]
wr_renderer_map_recorded_frame( renderer: &mut Renderer, handle: RecordedFrameHandle, dst_buffer: *mut u8, dst_buffer_len: usize, dst_stride: usize, ) -> bool664 pub extern "C" fn wr_renderer_map_recorded_frame(
665 renderer: &mut Renderer,
666 handle: RecordedFrameHandle,
667 dst_buffer: *mut u8,
668 dst_buffer_len: usize,
669 dst_stride: usize,
670 ) -> bool {
671 renderer.map_recorded_frame(
672 handle,
673 unsafe { make_slice_mut(dst_buffer, dst_buffer_len) },
674 dst_stride,
675 )
676 }
677
678 #[no_mangle]
wr_renderer_release_composition_recorder_structures(renderer: &mut Renderer)679 pub extern "C" fn wr_renderer_release_composition_recorder_structures(renderer: &mut Renderer) {
680 renderer.release_composition_recorder_structures();
681 }
682
683 #[no_mangle]
wr_renderer_get_screenshot_async( renderer: &mut Renderer, window_x: i32, window_y: i32, window_width: i32, window_height: i32, buffer_width: i32, buffer_height: i32, image_format: ImageFormat, screenshot_width: *mut i32, screenshot_height: *mut i32, ) -> AsyncScreenshotHandle684 pub extern "C" fn wr_renderer_get_screenshot_async(
685 renderer: &mut Renderer,
686 window_x: i32,
687 window_y: i32,
688 window_width: i32,
689 window_height: i32,
690 buffer_width: i32,
691 buffer_height: i32,
692 image_format: ImageFormat,
693 screenshot_width: *mut i32,
694 screenshot_height: *mut i32,
695 ) -> AsyncScreenshotHandle {
696 assert!(!screenshot_width.is_null());
697 assert!(!screenshot_height.is_null());
698
699 let (handle, size) = renderer.get_screenshot_async(
700 DeviceIntRect::from_origin_and_size(
701 DeviceIntPoint::new(window_x, window_y),
702 DeviceIntSize::new(window_width, window_height),
703 ),
704 DeviceIntSize::new(buffer_width, buffer_height),
705 image_format,
706 );
707
708 unsafe {
709 *screenshot_width = size.width;
710 *screenshot_height = size.height;
711 }
712
713 handle
714 }
715
716 #[no_mangle]
wr_renderer_map_and_recycle_screenshot( renderer: &mut Renderer, handle: AsyncScreenshotHandle, dst_buffer: *mut u8, dst_buffer_len: usize, dst_stride: usize, ) -> bool717 pub extern "C" fn wr_renderer_map_and_recycle_screenshot(
718 renderer: &mut Renderer,
719 handle: AsyncScreenshotHandle,
720 dst_buffer: *mut u8,
721 dst_buffer_len: usize,
722 dst_stride: usize,
723 ) -> bool {
724 renderer.map_and_recycle_screenshot(
725 handle,
726 unsafe { make_slice_mut(dst_buffer, dst_buffer_len) },
727 dst_stride,
728 )
729 }
730
731 #[no_mangle]
wr_renderer_release_profiler_structures(renderer: &mut Renderer)732 pub extern "C" fn wr_renderer_release_profiler_structures(renderer: &mut Renderer) {
733 renderer.release_profiler_structures();
734 }
735
736 // Call wr_renderer_render() before calling this function.
737 #[no_mangle]
wr_renderer_readback( renderer: &mut Renderer, width: i32, height: i32, format: ImageFormat, dst_buffer: *mut u8, buffer_size: usize, )738 pub unsafe extern "C" fn wr_renderer_readback(
739 renderer: &mut Renderer,
740 width: i32,
741 height: i32,
742 format: ImageFormat,
743 dst_buffer: *mut u8,
744 buffer_size: usize,
745 ) {
746 assert!(is_in_render_thread());
747
748 let mut slice = make_slice_mut(dst_buffer, buffer_size);
749 renderer.read_pixels_into(FramebufferIntSize::new(width, height).into(), format, &mut slice);
750 }
751
752 #[no_mangle]
wr_renderer_set_profiler_ui(renderer: &mut Renderer, ui_str: *const u8, ui_str_len: usize)753 pub unsafe extern "C" fn wr_renderer_set_profiler_ui(renderer: &mut Renderer, ui_str: *const u8, ui_str_len: usize) {
754 let slice = std::slice::from_raw_parts(ui_str, ui_str_len);
755 if let Ok(ui_str) = std::str::from_utf8(slice) {
756 renderer.set_profiler_ui(ui_str);
757 }
758 }
759
760 #[no_mangle]
wr_renderer_delete(renderer: *mut Renderer)761 pub unsafe extern "C" fn wr_renderer_delete(renderer: *mut Renderer) {
762 let renderer = Box::from_raw(renderer);
763 renderer.deinit();
764 // let renderer go out of scope and get dropped
765 }
766
767 #[no_mangle]
wr_renderer_accumulate_memory_report( renderer: &mut Renderer, report: &mut MemoryReport, swgl: *mut c_void, )768 pub unsafe extern "C" fn wr_renderer_accumulate_memory_report(
769 renderer: &mut Renderer,
770 report: &mut MemoryReport,
771 swgl: *mut c_void,
772 ) {
773 *report += renderer.report_memory(swgl);
774 }
775
776 // cbindgen doesn't support tuples, so we have a little struct instead, with
777 // an Into implementation to convert from the tuple to the struct.
778 #[repr(C)]
779 pub struct WrPipelineEpoch {
780 pipeline_id: WrPipelineId,
781 document_id: WrDocumentId,
782 epoch: WrEpoch,
783 }
784
785 impl<'a> From<(&'a (WrPipelineId, WrDocumentId), &'a WrEpoch)> for WrPipelineEpoch {
from(tuple: (&(WrPipelineId, WrDocumentId), &WrEpoch)) -> WrPipelineEpoch786 fn from(tuple: (&(WrPipelineId, WrDocumentId), &WrEpoch)) -> WrPipelineEpoch {
787 WrPipelineEpoch {
788 pipeline_id: (tuple.0).0,
789 document_id: (tuple.0).1,
790 epoch: *tuple.1,
791 }
792 }
793 }
794
795 #[repr(C)]
796 pub struct WrPipelineIdAndEpoch {
797 pipeline_id: WrPipelineId,
798 epoch: WrEpoch,
799 }
800
801 impl<'a> From<(&WrPipelineId, &WrEpoch)> for WrPipelineIdAndEpoch {
from(tuple: (&WrPipelineId, &WrEpoch)) -> WrPipelineIdAndEpoch802 fn from(tuple: (&WrPipelineId, &WrEpoch)) -> WrPipelineIdAndEpoch {
803 WrPipelineIdAndEpoch {
804 pipeline_id: *tuple.0,
805 epoch: *tuple.1,
806 }
807 }
808 }
809
810 #[repr(C)]
811 pub struct WrRemovedPipeline {
812 pipeline_id: WrPipelineId,
813 document_id: WrDocumentId,
814 }
815
816 impl<'a> From<&'a (WrPipelineId, WrDocumentId)> for WrRemovedPipeline {
from(tuple: &(WrPipelineId, WrDocumentId)) -> WrRemovedPipeline817 fn from(tuple: &(WrPipelineId, WrDocumentId)) -> WrRemovedPipeline {
818 WrRemovedPipeline {
819 pipeline_id: tuple.0,
820 document_id: tuple.1,
821 }
822 }
823 }
824
825 #[repr(C)]
826 pub struct WrPipelineInfo {
827 /// This contains an entry for each pipeline that was rendered, along with
828 /// the epoch at which it was rendered. Rendered pipelines include the root
829 /// pipeline and any other pipelines that were reachable via IFrame display
830 /// items from the root pipeline.
831 epochs: ThinVec<WrPipelineEpoch>,
832 /// This contains an entry for each pipeline that was removed during the
833 /// last transaction. These pipelines would have been explicitly removed by
834 /// calling remove_pipeline on the transaction object; the pipeline showing
835 /// up in this array means that the data structures have been torn down on
836 /// the webrender side, and so any remaining data structures on the caller
837 /// side can now be torn down also.
838 removed_pipelines: ThinVec<WrRemovedPipeline>,
839 }
840
841 impl WrPipelineInfo {
new(info: &PipelineInfo) -> Self842 fn new(info: &PipelineInfo) -> Self {
843 WrPipelineInfo {
844 epochs: info.epochs.iter().map(WrPipelineEpoch::from).collect(),
845 removed_pipelines: info.removed_pipelines.iter().map(WrRemovedPipeline::from).collect(),
846 }
847 }
848 }
849
850 #[no_mangle]
wr_renderer_flush_pipeline_info(renderer: &mut Renderer, out: &mut WrPipelineInfo)851 pub unsafe extern "C" fn wr_renderer_flush_pipeline_info(renderer: &mut Renderer, out: &mut WrPipelineInfo) {
852 let info = renderer.flush_pipeline_info();
853 *out = WrPipelineInfo::new(&info);
854 }
855
856 extern "C" {
gecko_profiler_thread_is_being_profiled() -> bool857 pub fn gecko_profiler_thread_is_being_profiled() -> bool;
858 }
859
gecko_profiler_start_marker(name: &str)860 pub fn gecko_profiler_start_marker(name: &str) {
861 use gecko_profiler::{gecko_profiler_category, MarkerOptions, MarkerTiming, ProfilerTime, Tracing};
862 gecko_profiler::add_marker(
863 name,
864 gecko_profiler_category!(Graphics),
865 MarkerOptions {
866 timing: MarkerTiming::interval_start(ProfilerTime::now()),
867 ..Default::default()
868 },
869 Tracing("Webrender".to_string()),
870 );
871 }
gecko_profiler_end_marker(name: &str)872 pub fn gecko_profiler_end_marker(name: &str) {
873 use gecko_profiler::{gecko_profiler_category, MarkerOptions, MarkerTiming, ProfilerTime, Tracing};
874 gecko_profiler::add_marker(
875 name,
876 gecko_profiler_category!(Graphics),
877 MarkerOptions {
878 timing: MarkerTiming::interval_end(ProfilerTime::now()),
879 ..Default::default()
880 },
881 Tracing("Webrender".to_string()),
882 );
883 }
884
gecko_profiler_event_marker(name: &str)885 pub fn gecko_profiler_event_marker(name: &str) {
886 use gecko_profiler::{gecko_profiler_category, Tracing};
887 gecko_profiler::add_marker(
888 name,
889 gecko_profiler_category!(Graphics),
890 Default::default(),
891 Tracing("Webrender".to_string()),
892 );
893 }
894
gecko_profiler_add_text_marker(name: &str, text: &str, microseconds: f64)895 pub fn gecko_profiler_add_text_marker(name: &str, text: &str, microseconds: f64) {
896 use gecko_profiler::{gecko_profiler_category, MarkerOptions, MarkerTiming, ProfilerTime};
897 if !gecko_profiler::can_accept_markers() {
898 return;
899 }
900
901 let now = ProfilerTime::now();
902 let start = now.clone().subtract_microseconds(microseconds);
903 gecko_profiler::add_text_marker(
904 name,
905 gecko_profiler_category!(Graphics),
906 MarkerOptions {
907 timing: MarkerTiming::interval(start, now),
908 ..Default::default()
909 },
910 text,
911 );
912 }
913
914 /// Simple implementation of the WR ProfilerHooks trait to allow profile
915 /// markers to be seen in the Gecko profiler.
916 struct GeckoProfilerHooks;
917
918 impl ProfilerHooks for GeckoProfilerHooks {
register_thread(&self, thread_name: &str)919 fn register_thread(&self, thread_name: &str) {
920 gecko_profiler::register_thread(thread_name);
921 }
922
unregister_thread(&self)923 fn unregister_thread(&self) {
924 gecko_profiler::unregister_thread();
925 }
926
begin_marker(&self, label: &str)927 fn begin_marker(&self, label: &str) {
928 gecko_profiler_start_marker(label);
929 }
930
end_marker(&self, label: &str)931 fn end_marker(&self, label: &str) {
932 gecko_profiler_end_marker(label);
933 }
934
event_marker(&self, label: &str)935 fn event_marker(&self, label: &str) {
936 gecko_profiler_event_marker(label);
937 }
938
add_text_marker(&self, label: &str, text: &str, duration: Duration)939 fn add_text_marker(&self, label: &str, text: &str, duration: Duration) {
940 let micros = duration.as_micros() as f64;
941 gecko_profiler_add_text_marker(label, text, micros);
942 }
943
thread_is_being_profiled(&self) -> bool944 fn thread_is_being_profiled(&self) -> bool {
945 unsafe { gecko_profiler_thread_is_being_profiled() }
946 }
947 }
948
949 static PROFILER_HOOKS: GeckoProfilerHooks = GeckoProfilerHooks {};
950
951 #[allow(improper_ctypes)] // this is needed so that rustc doesn't complain about passing the &mut Transaction to an extern function
952 extern "C" {
953 // These callbacks are invoked from the scene builder thread (aka the APZ
954 // updater thread)
apz_register_updater(window_id: WrWindowId)955 fn apz_register_updater(window_id: WrWindowId);
apz_pre_scene_swap(window_id: WrWindowId)956 fn apz_pre_scene_swap(window_id: WrWindowId);
apz_post_scene_swap(window_id: WrWindowId, pipeline_info: &WrPipelineInfo)957 fn apz_post_scene_swap(window_id: WrWindowId, pipeline_info: &WrPipelineInfo);
apz_run_updater(window_id: WrWindowId)958 fn apz_run_updater(window_id: WrWindowId);
apz_deregister_updater(window_id: WrWindowId)959 fn apz_deregister_updater(window_id: WrWindowId);
960
961 // These callbacks are invoked from the render backend thread (aka the APZ
962 // sampler thread)
apz_register_sampler(window_id: WrWindowId)963 fn apz_register_sampler(window_id: WrWindowId);
apz_sample_transforms(window_id: WrWindowId, generated_frame_id: *const u64, transaction: &mut Transaction)964 fn apz_sample_transforms(window_id: WrWindowId, generated_frame_id: *const u64, transaction: &mut Transaction);
apz_deregister_sampler(window_id: WrWindowId)965 fn apz_deregister_sampler(window_id: WrWindowId);
966
omta_register_sampler(window_id: WrWindowId)967 fn omta_register_sampler(window_id: WrWindowId);
omta_sample(window_id: WrWindowId, transaction: &mut Transaction)968 fn omta_sample(window_id: WrWindowId, transaction: &mut Transaction);
omta_deregister_sampler(window_id: WrWindowId)969 fn omta_deregister_sampler(window_id: WrWindowId);
970 }
971
972 struct APZCallbacks {
973 window_id: WrWindowId,
974 }
975
976 impl APZCallbacks {
new(window_id: WrWindowId) -> Self977 pub fn new(window_id: WrWindowId) -> Self {
978 APZCallbacks { window_id }
979 }
980 }
981
982 impl SceneBuilderHooks for APZCallbacks {
register(&self)983 fn register(&self) {
984 unsafe { apz_register_updater(self.window_id) }
985 }
986
pre_scene_build(&self)987 fn pre_scene_build(&self) {
988 gecko_profiler_start_marker("SceneBuilding");
989 }
990
pre_scene_swap(&self, scenebuild_time: u64)991 fn pre_scene_swap(&self, scenebuild_time: u64) {
992 unsafe {
993 record_telemetry_time(TelemetryProbe::SceneBuildTime, scenebuild_time);
994 apz_pre_scene_swap(self.window_id);
995 }
996 }
997
post_scene_swap(&self, _document_ids: &Vec<DocumentId>, info: PipelineInfo, sceneswap_time: u64)998 fn post_scene_swap(&self, _document_ids: &Vec<DocumentId>, info: PipelineInfo, sceneswap_time: u64) {
999 let mut info = WrPipelineInfo::new(&info);
1000 unsafe {
1001 record_telemetry_time(TelemetryProbe::SceneSwapTime, sceneswap_time);
1002 apz_post_scene_swap(self.window_id, &info);
1003 }
1004
1005 // After a scene swap we should schedule a render for the next vsync,
1006 // otherwise there's no guarantee that the new scene will get rendered
1007 // anytime soon
1008 unsafe { wr_finished_scene_build(self.window_id, &mut info) }
1009 gecko_profiler_end_marker("SceneBuilding");
1010 }
1011
post_resource_update(&self, _document_ids: &Vec<DocumentId>)1012 fn post_resource_update(&self, _document_ids: &Vec<DocumentId>) {
1013 unsafe { wr_schedule_render(self.window_id, RenderReasons::POST_RESOURCE_UPDATES_HOOK) }
1014 gecko_profiler_end_marker("SceneBuilding");
1015 }
1016
post_empty_scene_build(&self)1017 fn post_empty_scene_build(&self) {
1018 gecko_profiler_end_marker("SceneBuilding");
1019 }
1020
poke(&self)1021 fn poke(&self) {
1022 unsafe { apz_run_updater(self.window_id) }
1023 }
1024
deregister(&self)1025 fn deregister(&self) {
1026 unsafe { apz_deregister_updater(self.window_id) }
1027 }
1028 }
1029
1030 struct SamplerCallback {
1031 window_id: WrWindowId,
1032 }
1033
1034 impl SamplerCallback {
new(window_id: WrWindowId) -> Self1035 pub fn new(window_id: WrWindowId) -> Self {
1036 SamplerCallback { window_id }
1037 }
1038 }
1039
1040 impl AsyncPropertySampler for SamplerCallback {
register(&self)1041 fn register(&self) {
1042 unsafe {
1043 apz_register_sampler(self.window_id);
1044 omta_register_sampler(self.window_id);
1045 }
1046 }
1047
sample(&self, _document_id: DocumentId, generated_frame_id: Option<u64>) -> Vec<FrameMsg>1048 fn sample(&self, _document_id: DocumentId, generated_frame_id: Option<u64>) -> Vec<FrameMsg> {
1049 let generated_frame_id_value;
1050 let generated_frame_id: *const u64 = match generated_frame_id {
1051 Some(id) => {
1052 generated_frame_id_value = id;
1053 &generated_frame_id_value
1054 },
1055 None => ptr::null_mut(),
1056 };
1057 let mut transaction = Transaction::new();
1058 // Reset the pending properties first because omta_sample and apz_sample_transforms
1059 // may be failed to reset them due to null samplers.
1060 transaction.reset_dynamic_properties();
1061 unsafe {
1062 apz_sample_transforms(self.window_id, generated_frame_id, &mut transaction);
1063 omta_sample(self.window_id, &mut transaction);
1064 };
1065 transaction.get_frame_ops()
1066 }
1067
deregister(&self)1068 fn deregister(&self) {
1069 unsafe {
1070 apz_deregister_sampler(self.window_id);
1071 omta_deregister_sampler(self.window_id);
1072 }
1073 }
1074 }
1075
1076 extern "C" {
wr_register_thread_local_arena()1077 fn wr_register_thread_local_arena();
1078 }
1079
1080 pub struct WrThreadPool(Arc<rayon::ThreadPool>);
1081
1082 #[no_mangle]
wr_thread_pool_new(low_priority: bool) -> *mut WrThreadPool1083 pub extern "C" fn wr_thread_pool_new(low_priority: bool) -> *mut WrThreadPool {
1084 // Clamp the number of workers between 1 and 4/8. We get diminishing returns
1085 // with high worker counts and extra overhead because of rayon and font
1086 // management.
1087
1088 // We clamp to 4 high priority threads because contention and memory usage
1089 // make it not worth going higher
1090 let max = if low_priority { 8 } else { 4 };
1091 let num_threads = num_cpus::get().min(max);
1092
1093 let priority_tag = if low_priority { "LP" } else { "" };
1094
1095 let worker = rayon::ThreadPoolBuilder::new()
1096 .thread_name(move |idx| format!("WRWorker{}#{}", priority_tag, idx))
1097 .num_threads(num_threads)
1098 .start_handler(move |idx| {
1099 unsafe {
1100 wr_register_thread_local_arena();
1101 }
1102 let name = format!("WRWorker{}#{}", priority_tag, idx);
1103 register_thread_with_profiler(name.clone());
1104 gecko_profiler::register_thread(&name);
1105 })
1106 .exit_handler(|_idx| {
1107 gecko_profiler::unregister_thread();
1108 })
1109 .build();
1110
1111 let workers = Arc::new(worker.unwrap());
1112
1113 // This effectively leaks the thread pool. Not great but we only create one and it lives
1114 // for as long as the browser.
1115 // Do this to avoid intermittent race conditions with nsThreadManager shutdown.
1116 // A better fix would involve removing the dependency between implicit nsThreadManager
1117 // and webrender's threads, or be able to synchronously terminate rayon's thread pool.
1118 mem::forget(Arc::clone(&workers));
1119
1120 Box::into_raw(Box::new(WrThreadPool(workers)))
1121 }
1122
1123 #[no_mangle]
wr_thread_pool_delete(thread_pool: *mut WrThreadPool)1124 pub unsafe extern "C" fn wr_thread_pool_delete(thread_pool: *mut WrThreadPool) {
1125 Box::from_raw(thread_pool);
1126 }
1127
1128 #[no_mangle]
wr_program_cache_new( prof_path: &nsAString, thread_pool: *mut WrThreadPool, ) -> *mut WrProgramCache1129 pub unsafe extern "C" fn wr_program_cache_new(
1130 prof_path: &nsAString,
1131 thread_pool: *mut WrThreadPool,
1132 ) -> *mut WrProgramCache {
1133 let workers = &(*thread_pool).0;
1134 let program_cache = WrProgramCache::new(prof_path, workers);
1135 Box::into_raw(Box::new(program_cache))
1136 }
1137
1138 #[no_mangle]
wr_program_cache_delete(program_cache: *mut WrProgramCache)1139 pub unsafe extern "C" fn wr_program_cache_delete(program_cache: *mut WrProgramCache) {
1140 Box::from_raw(program_cache);
1141 }
1142
1143 #[no_mangle]
wr_try_load_startup_shaders_from_disk(program_cache: *mut WrProgramCache)1144 pub unsafe extern "C" fn wr_try_load_startup_shaders_from_disk(program_cache: *mut WrProgramCache) {
1145 (*program_cache).try_load_startup_shaders_from_disk();
1146 }
1147
1148 #[no_mangle]
remove_program_binary_disk_cache(prof_path: &nsAString) -> bool1149 pub unsafe extern "C" fn remove_program_binary_disk_cache(prof_path: &nsAString) -> bool {
1150 match remove_disk_cache(prof_path) {
1151 Ok(_) => true,
1152 Err(_) => {
1153 error!("Failed to remove program binary disk cache");
1154 false
1155 },
1156 }
1157 }
1158
1159 // This matches IsEnvSet in gfxEnv.h
env_var_to_bool(key: &'static str) -> bool1160 fn env_var_to_bool(key: &'static str) -> bool {
1161 env::var(key).ok().map_or(false, |v| !v.is_empty())
1162 }
1163
1164 // Call MakeCurrent before this.
wr_device_new(gl_context: *mut c_void, pc: Option<&mut WrProgramCache>) -> Device1165 fn wr_device_new(gl_context: *mut c_void, pc: Option<&mut WrProgramCache>) -> Device {
1166 assert!(unsafe { is_in_render_thread() });
1167
1168 let gl;
1169 if unsafe { is_glcontext_gles(gl_context) } {
1170 gl = unsafe { gl::GlesFns::load_with(|symbol| get_proc_address(gl_context, symbol)) };
1171 } else {
1172 gl = unsafe { gl::GlFns::load_with(|symbol| get_proc_address(gl_context, symbol)) };
1173 }
1174
1175 let version = gl.get_string(gl::VERSION);
1176
1177 info!("WebRender - OpenGL version new {}", version);
1178
1179 let upload_method = if unsafe { is_glcontext_angle(gl_context) } {
1180 UploadMethod::Immediate
1181 } else {
1182 UploadMethod::PixelBuffer(ONE_TIME_USAGE_HINT)
1183 };
1184
1185 let resource_override_path = unsafe {
1186 let override_charptr = gfx_wr_resource_path_override();
1187 if override_charptr.is_null() {
1188 None
1189 } else {
1190 match CStr::from_ptr(override_charptr).to_str() {
1191 Ok(override_str) => Some(PathBuf::from(override_str)),
1192 _ => None,
1193 }
1194 }
1195 };
1196
1197 let use_optimized_shaders = unsafe { gfx_wr_use_optimized_shaders() };
1198
1199 let cached_programs = pc.map(|cached_programs| Rc::clone(cached_programs.rc_get()));
1200
1201 Device::new(
1202 gl,
1203 Some(Box::new(MozCrashAnnotator)),
1204 resource_override_path,
1205 use_optimized_shaders,
1206 upload_method,
1207 512 * 512,
1208 cached_programs,
1209 true,
1210 true,
1211 None,
1212 false,
1213 false,
1214 )
1215 }
1216
1217 extern "C" {
wr_compositor_create_surface( compositor: *mut c_void, id: NativeSurfaceId, virtual_offset: DeviceIntPoint, tile_size: DeviceIntSize, is_opaque: bool, )1218 fn wr_compositor_create_surface(
1219 compositor: *mut c_void,
1220 id: NativeSurfaceId,
1221 virtual_offset: DeviceIntPoint,
1222 tile_size: DeviceIntSize,
1223 is_opaque: bool,
1224 );
wr_compositor_create_external_surface(compositor: *mut c_void, id: NativeSurfaceId, is_opaque: bool)1225 fn wr_compositor_create_external_surface(compositor: *mut c_void, id: NativeSurfaceId, is_opaque: bool);
wr_compositor_destroy_surface(compositor: *mut c_void, id: NativeSurfaceId)1226 fn wr_compositor_destroy_surface(compositor: *mut c_void, id: NativeSurfaceId);
wr_compositor_create_tile(compositor: *mut c_void, id: NativeSurfaceId, x: i32, y: i32)1227 fn wr_compositor_create_tile(compositor: *mut c_void, id: NativeSurfaceId, x: i32, y: i32);
wr_compositor_destroy_tile(compositor: *mut c_void, id: NativeSurfaceId, x: i32, y: i32)1228 fn wr_compositor_destroy_tile(compositor: *mut c_void, id: NativeSurfaceId, x: i32, y: i32);
wr_compositor_attach_external_image( compositor: *mut c_void, id: NativeSurfaceId, external_image: ExternalImageId, )1229 fn wr_compositor_attach_external_image(
1230 compositor: *mut c_void,
1231 id: NativeSurfaceId,
1232 external_image: ExternalImageId,
1233 );
wr_compositor_bind( compositor: *mut c_void, id: NativeTileId, offset: &mut DeviceIntPoint, fbo_id: &mut u32, dirty_rect: DeviceIntRect, valid_rect: DeviceIntRect, )1234 fn wr_compositor_bind(
1235 compositor: *mut c_void,
1236 id: NativeTileId,
1237 offset: &mut DeviceIntPoint,
1238 fbo_id: &mut u32,
1239 dirty_rect: DeviceIntRect,
1240 valid_rect: DeviceIntRect,
1241 );
wr_compositor_unbind(compositor: *mut c_void)1242 fn wr_compositor_unbind(compositor: *mut c_void);
wr_compositor_begin_frame(compositor: *mut c_void)1243 fn wr_compositor_begin_frame(compositor: *mut c_void);
wr_compositor_add_surface( compositor: *mut c_void, id: NativeSurfaceId, transform: &CompositorSurfaceTransform, clip_rect: DeviceIntRect, image_rendering: ImageRendering, )1244 fn wr_compositor_add_surface(
1245 compositor: *mut c_void,
1246 id: NativeSurfaceId,
1247 transform: &CompositorSurfaceTransform,
1248 clip_rect: DeviceIntRect,
1249 image_rendering: ImageRendering,
1250 );
wr_compositor_start_compositing( compositor: *mut c_void, clear_color: ColorF, dirty_rects: *const DeviceIntRect, num_dirty_rects: usize, opaque_rects: *const DeviceIntRect, num_opaque_rects: usize, )1251 fn wr_compositor_start_compositing(
1252 compositor: *mut c_void,
1253 clear_color: ColorF,
1254 dirty_rects: *const DeviceIntRect,
1255 num_dirty_rects: usize,
1256 opaque_rects: *const DeviceIntRect,
1257 num_opaque_rects: usize,
1258 );
wr_compositor_end_frame(compositor: *mut c_void)1259 fn wr_compositor_end_frame(compositor: *mut c_void);
wr_compositor_enable_native_compositor(compositor: *mut c_void, enable: bool)1260 fn wr_compositor_enable_native_compositor(compositor: *mut c_void, enable: bool);
wr_compositor_deinit(compositor: *mut c_void)1261 fn wr_compositor_deinit(compositor: *mut c_void);
wr_compositor_get_capabilities(compositor: *mut c_void, caps: *mut CompositorCapabilities)1262 fn wr_compositor_get_capabilities(compositor: *mut c_void, caps: *mut CompositorCapabilities);
wr_compositor_get_window_visibility(compositor: *mut c_void, caps: *mut WindowVisibility)1263 fn wr_compositor_get_window_visibility(compositor: *mut c_void, caps: *mut WindowVisibility);
wr_compositor_map_tile( compositor: *mut c_void, id: NativeTileId, dirty_rect: DeviceIntRect, valid_rect: DeviceIntRect, data: &mut *mut c_void, stride: &mut i32, )1264 fn wr_compositor_map_tile(
1265 compositor: *mut c_void,
1266 id: NativeTileId,
1267 dirty_rect: DeviceIntRect,
1268 valid_rect: DeviceIntRect,
1269 data: &mut *mut c_void,
1270 stride: &mut i32,
1271 );
wr_compositor_unmap_tile(compositor: *mut c_void)1272 fn wr_compositor_unmap_tile(compositor: *mut c_void);
1273
wr_partial_present_compositor_set_buffer_damage_region( compositor: *mut c_void, rects: *const DeviceIntRect, n_rects: usize, )1274 fn wr_partial_present_compositor_set_buffer_damage_region(
1275 compositor: *mut c_void,
1276 rects: *const DeviceIntRect,
1277 n_rects: usize,
1278 );
1279 }
1280
1281 pub struct WrCompositor(*mut c_void);
1282
1283 impl Compositor for WrCompositor {
create_surface( &mut self, id: NativeSurfaceId, virtual_offset: DeviceIntPoint, tile_size: DeviceIntSize, is_opaque: bool, )1284 fn create_surface(
1285 &mut self,
1286 id: NativeSurfaceId,
1287 virtual_offset: DeviceIntPoint,
1288 tile_size: DeviceIntSize,
1289 is_opaque: bool,
1290 ) {
1291 unsafe {
1292 wr_compositor_create_surface(self.0, id, virtual_offset, tile_size, is_opaque);
1293 }
1294 }
1295
create_external_surface(&mut self, id: NativeSurfaceId, is_opaque: bool)1296 fn create_external_surface(&mut self, id: NativeSurfaceId, is_opaque: bool) {
1297 unsafe {
1298 wr_compositor_create_external_surface(self.0, id, is_opaque);
1299 }
1300 }
1301
destroy_surface(&mut self, id: NativeSurfaceId)1302 fn destroy_surface(&mut self, id: NativeSurfaceId) {
1303 unsafe {
1304 wr_compositor_destroy_surface(self.0, id);
1305 }
1306 }
1307
create_tile(&mut self, id: NativeTileId)1308 fn create_tile(&mut self, id: NativeTileId) {
1309 unsafe {
1310 wr_compositor_create_tile(self.0, id.surface_id, id.x, id.y);
1311 }
1312 }
1313
destroy_tile(&mut self, id: NativeTileId)1314 fn destroy_tile(&mut self, id: NativeTileId) {
1315 unsafe {
1316 wr_compositor_destroy_tile(self.0, id.surface_id, id.x, id.y);
1317 }
1318 }
1319
attach_external_image(&mut self, id: NativeSurfaceId, external_image: ExternalImageId)1320 fn attach_external_image(&mut self, id: NativeSurfaceId, external_image: ExternalImageId) {
1321 unsafe {
1322 wr_compositor_attach_external_image(self.0, id, external_image);
1323 }
1324 }
1325
bind(&mut self, id: NativeTileId, dirty_rect: DeviceIntRect, valid_rect: DeviceIntRect) -> NativeSurfaceInfo1326 fn bind(&mut self, id: NativeTileId, dirty_rect: DeviceIntRect, valid_rect: DeviceIntRect) -> NativeSurfaceInfo {
1327 let mut surface_info = NativeSurfaceInfo {
1328 origin: DeviceIntPoint::zero(),
1329 fbo_id: 0,
1330 };
1331
1332 unsafe {
1333 wr_compositor_bind(
1334 self.0,
1335 id,
1336 &mut surface_info.origin,
1337 &mut surface_info.fbo_id,
1338 dirty_rect,
1339 valid_rect,
1340 );
1341 }
1342
1343 surface_info
1344 }
1345
unbind(&mut self)1346 fn unbind(&mut self) {
1347 unsafe {
1348 wr_compositor_unbind(self.0);
1349 }
1350 }
1351
begin_frame(&mut self)1352 fn begin_frame(&mut self) {
1353 unsafe {
1354 wr_compositor_begin_frame(self.0);
1355 }
1356 }
1357
add_surface( &mut self, id: NativeSurfaceId, transform: CompositorSurfaceTransform, clip_rect: DeviceIntRect, image_rendering: ImageRendering, )1358 fn add_surface(
1359 &mut self,
1360 id: NativeSurfaceId,
1361 transform: CompositorSurfaceTransform,
1362 clip_rect: DeviceIntRect,
1363 image_rendering: ImageRendering,
1364 ) {
1365 unsafe {
1366 wr_compositor_add_surface(self.0, id, &transform, clip_rect, image_rendering);
1367 }
1368 }
1369
start_compositing( &mut self, clear_color: ColorF, dirty_rects: &[DeviceIntRect], opaque_rects: &[DeviceIntRect], )1370 fn start_compositing(
1371 &mut self,
1372 clear_color: ColorF,
1373 dirty_rects: &[DeviceIntRect],
1374 opaque_rects: &[DeviceIntRect],
1375 ) {
1376 unsafe {
1377 wr_compositor_start_compositing(
1378 self.0,
1379 clear_color,
1380 dirty_rects.as_ptr(),
1381 dirty_rects.len(),
1382 opaque_rects.as_ptr(),
1383 opaque_rects.len(),
1384 );
1385 }
1386 }
1387
end_frame(&mut self)1388 fn end_frame(&mut self) {
1389 unsafe {
1390 wr_compositor_end_frame(self.0);
1391 }
1392 }
1393
enable_native_compositor(&mut self, enable: bool)1394 fn enable_native_compositor(&mut self, enable: bool) {
1395 unsafe {
1396 wr_compositor_enable_native_compositor(self.0, enable);
1397 }
1398 }
1399
deinit(&mut self)1400 fn deinit(&mut self) {
1401 unsafe {
1402 wr_compositor_deinit(self.0);
1403 }
1404 }
1405
get_capabilities(&self) -> CompositorCapabilities1406 fn get_capabilities(&self) -> CompositorCapabilities {
1407 unsafe {
1408 let mut caps: CompositorCapabilities = Default::default();
1409 wr_compositor_get_capabilities(self.0, &mut caps);
1410 caps
1411 }
1412 }
1413
get_window_visibility(&self) -> WindowVisibility1414 fn get_window_visibility(&self) -> WindowVisibility {
1415 unsafe {
1416 let mut visibility: WindowVisibility = Default::default();
1417 wr_compositor_get_window_visibility(self.0, &mut visibility);
1418 visibility
1419 }
1420 }
1421 }
1422
1423 extern "C" {
wr_swgl_lock_composite_surface( ctx: *mut c_void, external_image_id: ExternalImageId, composite_info: *mut SWGLCompositeSurfaceInfo, ) -> bool1424 fn wr_swgl_lock_composite_surface(
1425 ctx: *mut c_void,
1426 external_image_id: ExternalImageId,
1427 composite_info: *mut SWGLCompositeSurfaceInfo,
1428 ) -> bool;
wr_swgl_unlock_composite_surface(ctx: *mut c_void, external_image_id: ExternalImageId)1429 fn wr_swgl_unlock_composite_surface(ctx: *mut c_void, external_image_id: ExternalImageId);
1430 }
1431
1432 impl MappableCompositor for WrCompositor {
1433 /// Map a tile's underlying buffer so it can be used as the backing for
1434 /// a SWGL framebuffer. This is intended to be a replacement for 'bind'
1435 /// in any compositors that intend to directly interoperate with SWGL
1436 /// while supporting some form of native layers.
map_tile( &mut self, id: NativeTileId, dirty_rect: DeviceIntRect, valid_rect: DeviceIntRect, ) -> Option<MappedTileInfo>1437 fn map_tile(
1438 &mut self,
1439 id: NativeTileId,
1440 dirty_rect: DeviceIntRect,
1441 valid_rect: DeviceIntRect,
1442 ) -> Option<MappedTileInfo> {
1443 let mut tile_info = MappedTileInfo {
1444 data: ptr::null_mut(),
1445 stride: 0,
1446 };
1447
1448 unsafe {
1449 wr_compositor_map_tile(
1450 self.0,
1451 id,
1452 dirty_rect,
1453 valid_rect,
1454 &mut tile_info.data,
1455 &mut tile_info.stride,
1456 );
1457 }
1458
1459 if !tile_info.data.is_null() && tile_info.stride != 0 {
1460 Some(tile_info)
1461 } else {
1462 None
1463 }
1464 }
1465
1466 /// Unmap a tile that was was previously mapped via map_tile to signal
1467 /// that SWGL is done rendering to the buffer.
unmap_tile(&mut self)1468 fn unmap_tile(&mut self) {
1469 unsafe {
1470 wr_compositor_unmap_tile(self.0);
1471 }
1472 }
1473
lock_composite_surface( &mut self, ctx: *mut c_void, external_image_id: ExternalImageId, composite_info: *mut SWGLCompositeSurfaceInfo, ) -> bool1474 fn lock_composite_surface(
1475 &mut self,
1476 ctx: *mut c_void,
1477 external_image_id: ExternalImageId,
1478 composite_info: *mut SWGLCompositeSurfaceInfo,
1479 ) -> bool {
1480 unsafe { wr_swgl_lock_composite_surface(ctx, external_image_id, composite_info) }
1481 }
unlock_composite_surface(&mut self, ctx: *mut c_void, external_image_id: ExternalImageId)1482 fn unlock_composite_surface(&mut self, ctx: *mut c_void, external_image_id: ExternalImageId) {
1483 unsafe { wr_swgl_unlock_composite_surface(ctx, external_image_id) }
1484 }
1485 }
1486
1487 pub struct WrPartialPresentCompositor(*mut c_void);
1488
1489 impl PartialPresentCompositor for WrPartialPresentCompositor {
set_buffer_damage_region(&mut self, rects: &[DeviceIntRect])1490 fn set_buffer_damage_region(&mut self, rects: &[DeviceIntRect]) {
1491 unsafe {
1492 wr_partial_present_compositor_set_buffer_damage_region(self.0, rects.as_ptr(), rects.len());
1493 }
1494 }
1495 }
1496
1497 /// A wrapper around a strong reference to a Shaders object.
1498 pub struct WrShaders(SharedShaders);
1499
1500 // Call MakeCurrent before this.
1501 #[no_mangle]
wr_window_new( window_id: WrWindowId, window_width: i32, window_height: i32, is_main_window: bool, support_low_priority_transactions: bool, support_low_priority_threadpool: bool, allow_texture_swizzling: bool, allow_scissored_cache_clears: bool, swgl_context: *mut c_void, gl_context: *mut c_void, surface_origin_is_top_left: bool, program_cache: Option<&mut WrProgramCache>, shaders: Option<&mut WrShaders>, thread_pool: *mut WrThreadPool, thread_pool_low_priority: *mut WrThreadPool, size_of_op: VoidPtrToSizeFn, enclosing_size_of_op: VoidPtrToSizeFn, document_id: u32, compositor: *mut c_void, use_native_compositor: bool, use_partial_present: bool, max_partial_present_rects: usize, draw_previous_partial_present_regions: bool, out_handle: &mut *mut DocumentHandle, out_renderer: &mut *mut Renderer, out_max_texture_size: *mut i32, out_err: &mut *mut c_char, enable_gpu_markers: bool, panic_on_gl_error: bool, picture_tile_width: i32, picture_tile_height: i32, reject_software_rasterizer: bool, low_quality_pinch_zoom: bool, ) -> bool1502 pub extern "C" fn wr_window_new(
1503 window_id: WrWindowId,
1504 window_width: i32,
1505 window_height: i32,
1506 is_main_window: bool,
1507 support_low_priority_transactions: bool,
1508 support_low_priority_threadpool: bool,
1509 allow_texture_swizzling: bool,
1510 allow_scissored_cache_clears: bool,
1511 swgl_context: *mut c_void,
1512 gl_context: *mut c_void,
1513 surface_origin_is_top_left: bool,
1514 program_cache: Option<&mut WrProgramCache>,
1515 shaders: Option<&mut WrShaders>,
1516 thread_pool: *mut WrThreadPool,
1517 thread_pool_low_priority: *mut WrThreadPool,
1518 size_of_op: VoidPtrToSizeFn,
1519 enclosing_size_of_op: VoidPtrToSizeFn,
1520 document_id: u32,
1521 compositor: *mut c_void,
1522 use_native_compositor: bool,
1523 use_partial_present: bool,
1524 max_partial_present_rects: usize,
1525 draw_previous_partial_present_regions: bool,
1526 out_handle: &mut *mut DocumentHandle,
1527 out_renderer: &mut *mut Renderer,
1528 out_max_texture_size: *mut i32,
1529 out_err: &mut *mut c_char,
1530 enable_gpu_markers: bool,
1531 panic_on_gl_error: bool,
1532 picture_tile_width: i32,
1533 picture_tile_height: i32,
1534 reject_software_rasterizer: bool,
1535 low_quality_pinch_zoom: bool,
1536 ) -> bool {
1537 assert!(unsafe { is_in_render_thread() });
1538
1539 // Ensure the WR profiler callbacks are hooked up to the Gecko profiler.
1540 set_profiler_hooks(Some(&PROFILER_HOOKS));
1541
1542 let software = !swgl_context.is_null();
1543 let (gl, sw_gl) = if software {
1544 let ctx = swgl::Context::from(swgl_context);
1545 ctx.make_current();
1546 (Rc::new(ctx) as Rc<dyn gl::Gl>, Some(ctx))
1547 } else {
1548 let gl = unsafe {
1549 if gl_context.is_null() {
1550 panic!("Native GL context required when not using SWGL!");
1551 } else if is_glcontext_gles(gl_context) {
1552 gl::GlesFns::load_with(|symbol| get_proc_address(gl_context, symbol))
1553 } else {
1554 gl::GlFns::load_with(|symbol| get_proc_address(gl_context, symbol))
1555 }
1556 };
1557 (gl, None)
1558 };
1559
1560 let version = gl.get_string(gl::VERSION);
1561
1562 info!("WebRender - OpenGL version new {}", version);
1563
1564 let workers = unsafe { Arc::clone(&(*thread_pool).0) };
1565 let workers_low_priority = unsafe {
1566 if support_low_priority_threadpool {
1567 Arc::clone(&(*thread_pool_low_priority).0)
1568 } else {
1569 Arc::clone(&(*thread_pool).0)
1570 }
1571 };
1572
1573 let upload_method = if !gl_context.is_null() && unsafe { is_glcontext_angle(gl_context) } {
1574 UploadMethod::Immediate
1575 } else {
1576 UploadMethod::PixelBuffer(ONE_TIME_USAGE_HINT)
1577 };
1578
1579 let precache_flags = if env_var_to_bool("MOZ_WR_PRECACHE_SHADERS") {
1580 ShaderPrecacheFlags::FULL_COMPILE
1581 } else {
1582 ShaderPrecacheFlags::empty()
1583 };
1584
1585 let cached_programs = program_cache.map(|program_cache| Rc::clone(&program_cache.rc_get()));
1586
1587 let color = if cfg!(target_os = "android") {
1588 // The color is for avoiding black flash before receiving display list.
1589 ColorF::new(1.0, 1.0, 1.0, 1.0)
1590 } else {
1591 ColorF::new(0.0, 0.0, 0.0, 0.0)
1592 };
1593
1594 let compositor_config = if software {
1595 CompositorConfig::Native {
1596 compositor: Box::new(SwCompositor::new(
1597 sw_gl.unwrap(),
1598 Box::new(WrCompositor(compositor)),
1599 use_native_compositor,
1600 )),
1601 }
1602 } else if use_native_compositor {
1603 CompositorConfig::Native {
1604 compositor: Box::new(WrCompositor(compositor)),
1605 }
1606 } else {
1607 CompositorConfig::Draw {
1608 max_partial_present_rects,
1609 draw_previous_partial_present_regions,
1610 partial_present: if use_partial_present {
1611 Some(Box::new(WrPartialPresentCompositor(compositor)))
1612 } else {
1613 None
1614 },
1615 }
1616 };
1617
1618 let picture_tile_size = if picture_tile_width > 0 && picture_tile_height > 0 {
1619 Some(DeviceIntSize::new(picture_tile_width, picture_tile_height))
1620 } else {
1621 None
1622 };
1623
1624 let texture_cache_config = if is_main_window {
1625 TextureCacheConfig::DEFAULT
1626 } else {
1627 TextureCacheConfig {
1628 color8_linear_texture_size: 512,
1629 color8_nearest_texture_size: 512,
1630 color8_glyph_texture_size: 512,
1631 alpha8_texture_size: 512,
1632 alpha8_glyph_texture_size: 512,
1633 alpha16_texture_size: 512,
1634 }
1635 };
1636
1637 let opts = RendererOptions {
1638 enable_aa: true,
1639 force_subpixel_aa: false,
1640 enable_subpixel_aa: cfg!(not(target_os = "android")),
1641 support_low_priority_transactions,
1642 allow_texture_swizzling,
1643 blob_image_handler: Some(Box::new(Moz2dBlobImageHandler::new(
1644 workers.clone(),
1645 workers_low_priority,
1646 ))),
1647 crash_annotator: Some(Box::new(MozCrashAnnotator)),
1648 workers: Some(workers),
1649 size_of_op: Some(size_of_op),
1650 enclosing_size_of_op: Some(enclosing_size_of_op),
1651 cached_programs,
1652 resource_override_path: unsafe {
1653 let override_charptr = gfx_wr_resource_path_override();
1654 if override_charptr.is_null() {
1655 None
1656 } else {
1657 match CStr::from_ptr(override_charptr).to_str() {
1658 Ok(override_str) => Some(PathBuf::from(override_str)),
1659 _ => None,
1660 }
1661 }
1662 },
1663 use_optimized_shaders: unsafe { gfx_wr_use_optimized_shaders() },
1664 renderer_id: Some(window_id.0),
1665 upload_method,
1666 scene_builder_hooks: Some(Box::new(APZCallbacks::new(window_id))),
1667 sampler: Some(Box::new(SamplerCallback::new(window_id))),
1668 max_internal_texture_size: Some(8192), // We want to tile if larger than this
1669 clear_color: color,
1670 precache_flags,
1671 namespace_alloc_by_client: true,
1672 // SWGL doesn't support the GL_ALWAYS depth comparison function used by
1673 // `clear_caches_with_quads`, but scissored clears work well.
1674 clear_caches_with_quads: !software && !allow_scissored_cache_clears,
1675 // SWGL supports KHR_blend_equation_advanced safely, but we haven't yet
1676 // tested other HW platforms determine if it is safe to allow them.
1677 allow_advanced_blend_equation: software,
1678 surface_origin_is_top_left,
1679 compositor_config,
1680 enable_gpu_markers,
1681 panic_on_gl_error,
1682 picture_tile_size,
1683 texture_cache_config,
1684 reject_software_rasterizer,
1685 low_quality_pinch_zoom,
1686 ..Default::default()
1687 };
1688
1689 let window_size = DeviceIntSize::new(window_width, window_height);
1690 let notifier = Box::new(CppNotifier { window_id });
1691 let (renderer, sender) = match Renderer::new(gl, notifier, opts, shaders.map(|sh| &sh.0)) {
1692 Ok((renderer, sender)) => (renderer, sender),
1693 Err(e) => {
1694 warn!(" Failed to create a Renderer: {:?}", e);
1695 let msg = CString::new(format!("wr_window_new: {:?}", e)).unwrap();
1696 unsafe {
1697 gfx_critical_note(msg.as_ptr());
1698 }
1699 *out_err = msg.into_raw();
1700 return false;
1701 },
1702 };
1703
1704 unsafe {
1705 *out_max_texture_size = renderer.get_max_texture_size();
1706 }
1707 *out_handle = Box::into_raw(Box::new(DocumentHandle::new(
1708 sender.create_api_by_client(next_namespace_id()),
1709 None,
1710 window_size,
1711 document_id,
1712 )));
1713 *out_renderer = Box::into_raw(Box::new(renderer));
1714
1715 true
1716 }
1717
1718 #[no_mangle]
wr_api_free_error_msg(msg: *mut c_char)1719 pub unsafe extern "C" fn wr_api_free_error_msg(msg: *mut c_char) {
1720 if !msg.is_null() {
1721 drop(CString::from_raw(msg));
1722 }
1723 }
1724
1725 #[no_mangle]
wr_api_delete_document(dh: &mut DocumentHandle)1726 pub unsafe extern "C" fn wr_api_delete_document(dh: &mut DocumentHandle) {
1727 dh.api.delete_document(dh.document_id);
1728 }
1729
1730 #[no_mangle]
wr_api_clone(dh: &mut DocumentHandle, out_handle: &mut *mut DocumentHandle)1731 pub extern "C" fn wr_api_clone(dh: &mut DocumentHandle, out_handle: &mut *mut DocumentHandle) {
1732 assert!(unsafe { is_in_compositor_thread() });
1733
1734 let hit_tester = dh.ensure_hit_tester().clone();
1735
1736 let handle = DocumentHandle {
1737 api: dh.api.create_sender().create_api_by_client(next_namespace_id()),
1738 document_id: dh.document_id,
1739 hit_tester: Some(hit_tester),
1740 hit_tester_request: None,
1741 };
1742 *out_handle = Box::into_raw(Box::new(handle));
1743 }
1744
1745 #[no_mangle]
wr_api_delete(dh: *mut DocumentHandle)1746 pub unsafe extern "C" fn wr_api_delete(dh: *mut DocumentHandle) {
1747 let _ = Box::from_raw(dh);
1748 }
1749
1750 #[no_mangle]
wr_api_stop_render_backend(dh: &mut DocumentHandle)1751 pub unsafe extern "C" fn wr_api_stop_render_backend(dh: &mut DocumentHandle) {
1752 dh.api.stop_render_backend();
1753 }
1754
1755 #[no_mangle]
wr_api_shut_down(dh: &mut DocumentHandle)1756 pub unsafe extern "C" fn wr_api_shut_down(dh: &mut DocumentHandle) {
1757 dh.api.shut_down(true);
1758 }
1759
1760 #[no_mangle]
wr_api_notify_memory_pressure(dh: &mut DocumentHandle)1761 pub unsafe extern "C" fn wr_api_notify_memory_pressure(dh: &mut DocumentHandle) {
1762 dh.api.notify_memory_pressure();
1763 }
1764
1765 #[no_mangle]
wr_api_set_debug_flags(dh: &mut DocumentHandle, flags: DebugFlags)1766 pub extern "C" fn wr_api_set_debug_flags(dh: &mut DocumentHandle, flags: DebugFlags) {
1767 dh.api.set_debug_flags(flags);
1768 }
1769
1770 #[no_mangle]
wr_api_set_bool(dh: &mut DocumentHandle, param_name: BoolParameter, val: bool)1771 pub extern "C" fn wr_api_set_bool(dh: &mut DocumentHandle, param_name: BoolParameter, val: bool) {
1772 dh.api.set_parameter(Parameter::Bool(param_name, val));
1773 }
1774
1775 #[no_mangle]
wr_api_set_int(dh: &mut DocumentHandle, param_name: IntParameter, val: i32)1776 pub extern "C" fn wr_api_set_int(dh: &mut DocumentHandle, param_name: IntParameter, val: i32) {
1777 dh.api.set_parameter(Parameter::Int(param_name, val));
1778 }
1779
1780 #[no_mangle]
wr_api_accumulate_memory_report( dh: &mut DocumentHandle, report: &mut MemoryReport, size_of_op: unsafe extern "C" fn(ptr: *const c_void) -> usize, enclosing_size_of_op: Option<unsafe extern "C" fn(ptr: *const c_void) -> usize>, )1781 pub unsafe extern "C" fn wr_api_accumulate_memory_report(
1782 dh: &mut DocumentHandle,
1783 report: &mut MemoryReport,
1784 // we manually expand VoidPtrToSizeFn here because cbindgen otherwise fails to fold the Option<fn()>
1785 // https://github.com/eqrion/cbindgen/issues/552
1786 size_of_op: unsafe extern "C" fn(ptr: *const c_void) -> usize,
1787 enclosing_size_of_op: Option<unsafe extern "C" fn(ptr: *const c_void) -> usize>,
1788 ) {
1789 let ops = MallocSizeOfOps::new(size_of_op, enclosing_size_of_op);
1790 *report += dh.api.report_memory(ops);
1791 }
1792
1793 #[no_mangle]
wr_api_clear_all_caches(dh: &mut DocumentHandle)1794 pub unsafe extern "C" fn wr_api_clear_all_caches(dh: &mut DocumentHandle) {
1795 dh.api.send_debug_cmd(DebugCommand::ClearCaches(ClearCache::all()));
1796 }
1797
1798 #[no_mangle]
wr_api_enable_native_compositor(dh: &mut DocumentHandle, enable: bool)1799 pub unsafe extern "C" fn wr_api_enable_native_compositor(dh: &mut DocumentHandle, enable: bool) {
1800 dh.api.send_debug_cmd(DebugCommand::EnableNativeCompositor(enable));
1801 }
1802
1803 #[no_mangle]
wr_api_set_batching_lookback(dh: &mut DocumentHandle, count: u32)1804 pub unsafe extern "C" fn wr_api_set_batching_lookback(dh: &mut DocumentHandle, count: u32) {
1805 dh.api.send_debug_cmd(DebugCommand::SetBatchingLookback(count));
1806 }
1807
make_transaction(do_async: bool) -> Transaction1808 fn make_transaction(do_async: bool) -> Transaction {
1809 let mut transaction = Transaction::new();
1810 // Ensure that we either use async scene building or not based on the
1811 // gecko pref, regardless of what the default is. We can remove this once
1812 // the scene builder thread is enabled everywhere and working well.
1813 if do_async {
1814 transaction.use_scene_builder_thread();
1815 } else {
1816 transaction.skip_scene_builder();
1817 }
1818 transaction
1819 }
1820
1821 #[no_mangle]
wr_transaction_new(do_async: bool) -> *mut Transaction1822 pub extern "C" fn wr_transaction_new(do_async: bool) -> *mut Transaction {
1823 Box::into_raw(Box::new(make_transaction(do_async)))
1824 }
1825
1826 #[no_mangle]
wr_transaction_delete(txn: *mut Transaction)1827 pub extern "C" fn wr_transaction_delete(txn: *mut Transaction) {
1828 unsafe {
1829 let _ = Box::from_raw(txn);
1830 }
1831 }
1832
1833 #[no_mangle]
wr_transaction_set_low_priority(txn: &mut Transaction, low_priority: bool)1834 pub extern "C" fn wr_transaction_set_low_priority(txn: &mut Transaction, low_priority: bool) {
1835 txn.set_low_priority(low_priority);
1836 }
1837
1838 #[no_mangle]
wr_transaction_is_empty(txn: &Transaction) -> bool1839 pub extern "C" fn wr_transaction_is_empty(txn: &Transaction) -> bool {
1840 txn.is_empty()
1841 }
1842
1843 #[no_mangle]
wr_transaction_resource_updates_is_empty(txn: &Transaction) -> bool1844 pub extern "C" fn wr_transaction_resource_updates_is_empty(txn: &Transaction) -> bool {
1845 txn.resource_updates.is_empty()
1846 }
1847
1848 #[no_mangle]
wr_transaction_is_rendered_frame_invalidated(txn: &Transaction) -> bool1849 pub extern "C" fn wr_transaction_is_rendered_frame_invalidated(txn: &Transaction) -> bool {
1850 txn.invalidate_rendered_frame
1851 }
1852
1853 #[no_mangle]
wr_transaction_notify(txn: &mut Transaction, when: Checkpoint, event: usize)1854 pub extern "C" fn wr_transaction_notify(txn: &mut Transaction, when: Checkpoint, event: usize) {
1855 struct GeckoNotification(usize);
1856 impl NotificationHandler for GeckoNotification {
1857 fn notify(&self, when: Checkpoint) {
1858 unsafe {
1859 wr_transaction_notification_notified(self.0, when);
1860 }
1861 }
1862 }
1863
1864 let handler = Box::new(GeckoNotification(event));
1865 txn.notify(NotificationRequest::new(when, handler));
1866 }
1867
1868 #[no_mangle]
wr_transaction_update_epoch(txn: &mut Transaction, pipeline_id: WrPipelineId, epoch: WrEpoch)1869 pub extern "C" fn wr_transaction_update_epoch(txn: &mut Transaction, pipeline_id: WrPipelineId, epoch: WrEpoch) {
1870 txn.update_epoch(pipeline_id, epoch);
1871 }
1872
1873 #[no_mangle]
wr_transaction_set_root_pipeline(txn: &mut Transaction, pipeline_id: WrPipelineId)1874 pub extern "C" fn wr_transaction_set_root_pipeline(txn: &mut Transaction, pipeline_id: WrPipelineId) {
1875 txn.set_root_pipeline(pipeline_id);
1876 }
1877
1878 #[no_mangle]
wr_transaction_remove_pipeline(txn: &mut Transaction, pipeline_id: WrPipelineId)1879 pub extern "C" fn wr_transaction_remove_pipeline(txn: &mut Transaction, pipeline_id: WrPipelineId) {
1880 txn.remove_pipeline(pipeline_id);
1881 }
1882
1883 #[no_mangle]
wr_transaction_set_display_list( txn: &mut Transaction, epoch: WrEpoch, background: ColorF, viewport_size: LayoutSize, pipeline_id: WrPipelineId, dl_descriptor: BuiltDisplayListDescriptor, dl_items_data: &mut WrVecU8, dl_cache_data: &mut WrVecU8, dl_spatial_tree_data: &mut WrVecU8, )1884 pub extern "C" fn wr_transaction_set_display_list(
1885 txn: &mut Transaction,
1886 epoch: WrEpoch,
1887 background: ColorF,
1888 viewport_size: LayoutSize,
1889 pipeline_id: WrPipelineId,
1890 dl_descriptor: BuiltDisplayListDescriptor,
1891 dl_items_data: &mut WrVecU8,
1892 dl_cache_data: &mut WrVecU8,
1893 dl_spatial_tree_data: &mut WrVecU8,
1894 ) {
1895 let color = if background.a == 0.0 { None } else { Some(background) };
1896
1897 let payload = DisplayListPayload {
1898 items_data: dl_items_data.flush_into_vec(),
1899 cache_data: dl_cache_data.flush_into_vec(),
1900 spatial_tree: dl_spatial_tree_data.flush_into_vec(),
1901 };
1902
1903 let dl = BuiltDisplayList::from_data(payload, dl_descriptor);
1904
1905 txn.set_display_list(epoch, color, viewport_size, (pipeline_id, dl));
1906 }
1907
1908 #[no_mangle]
wr_transaction_set_document_view(txn: &mut Transaction, doc_rect: &DeviceIntRect)1909 pub extern "C" fn wr_transaction_set_document_view(txn: &mut Transaction, doc_rect: &DeviceIntRect) {
1910 txn.set_document_view(*doc_rect);
1911 }
1912
1913 #[no_mangle]
wr_transaction_generate_frame(txn: &mut Transaction, id: u64, reasons: RenderReasons)1914 pub extern "C" fn wr_transaction_generate_frame(txn: &mut Transaction, id: u64, reasons: RenderReasons) {
1915 txn.generate_frame(id, reasons);
1916 }
1917
1918 #[no_mangle]
wr_transaction_invalidate_rendered_frame(txn: &mut Transaction, reasons: RenderReasons)1919 pub extern "C" fn wr_transaction_invalidate_rendered_frame(txn: &mut Transaction, reasons: RenderReasons) {
1920 txn.invalidate_rendered_frame(reasons);
1921 }
1922
wr_animation_properties_into_vec<T>( animation_array: *const WrAnimationPropertyValue<T>, array_count: usize, vec: &mut Vec<PropertyValue<T>>, ) where T: Copy,1923 fn wr_animation_properties_into_vec<T>(
1924 animation_array: *const WrAnimationPropertyValue<T>,
1925 array_count: usize,
1926 vec: &mut Vec<PropertyValue<T>>,
1927 ) where
1928 T: Copy,
1929 {
1930 if array_count > 0 {
1931 debug_assert!(
1932 vec.capacity() - vec.len() >= array_count,
1933 "The Vec should have fufficient free capacity"
1934 );
1935 let slice = unsafe { make_slice(animation_array, array_count) };
1936
1937 for element in slice.iter() {
1938 let prop = PropertyValue {
1939 key: PropertyBindingKey::new(element.id),
1940 value: element.value,
1941 };
1942
1943 vec.push(prop);
1944 }
1945 }
1946 }
1947
1948 #[no_mangle]
wr_transaction_append_dynamic_properties( txn: &mut Transaction, opacity_array: *const WrOpacityProperty, opacity_count: usize, transform_array: *const WrTransformProperty, transform_count: usize, color_array: *const WrColorProperty, color_count: usize, )1949 pub extern "C" fn wr_transaction_append_dynamic_properties(
1950 txn: &mut Transaction,
1951 opacity_array: *const WrOpacityProperty,
1952 opacity_count: usize,
1953 transform_array: *const WrTransformProperty,
1954 transform_count: usize,
1955 color_array: *const WrColorProperty,
1956 color_count: usize,
1957 ) {
1958 if opacity_count == 0 && transform_count == 0 && color_count == 0 {
1959 return;
1960 }
1961
1962 let mut properties = DynamicProperties {
1963 transforms: Vec::with_capacity(transform_count),
1964 floats: Vec::with_capacity(opacity_count),
1965 colors: Vec::with_capacity(color_count),
1966 };
1967
1968 wr_animation_properties_into_vec(transform_array, transform_count, &mut properties.transforms);
1969
1970 wr_animation_properties_into_vec(opacity_array, opacity_count, &mut properties.floats);
1971
1972 wr_animation_properties_into_vec(color_array, color_count, &mut properties.colors);
1973
1974 txn.append_dynamic_properties(properties);
1975 }
1976
1977 #[no_mangle]
wr_transaction_append_transform_properties( txn: &mut Transaction, transform_array: *const WrTransformProperty, transform_count: usize, )1978 pub extern "C" fn wr_transaction_append_transform_properties(
1979 txn: &mut Transaction,
1980 transform_array: *const WrTransformProperty,
1981 transform_count: usize,
1982 ) {
1983 if transform_count == 0 {
1984 return;
1985 }
1986
1987 let mut transforms = Vec::with_capacity(transform_count);
1988 wr_animation_properties_into_vec(transform_array, transform_count, &mut transforms);
1989
1990 txn.append_dynamic_transform_properties(transforms);
1991 }
1992
1993 #[no_mangle]
wr_transaction_scroll_layer( txn: &mut Transaction, pipeline_id: WrPipelineId, scroll_id: u64, sampled_scroll_offsets: &ThinVec<SampledScrollOffset>, )1994 pub extern "C" fn wr_transaction_scroll_layer(
1995 txn: &mut Transaction,
1996 pipeline_id: WrPipelineId,
1997 scroll_id: u64,
1998 sampled_scroll_offsets: &ThinVec<SampledScrollOffset>,
1999 ) {
2000 let scroll_id = ExternalScrollId(scroll_id, pipeline_id);
2001 txn.set_scroll_offsets(scroll_id, sampled_scroll_offsets.to_vec());
2002 }
2003
2004 #[no_mangle]
wr_transaction_set_is_transform_async_zooming( txn: &mut Transaction, animation_id: u64, is_zooming: bool, )2005 pub extern "C" fn wr_transaction_set_is_transform_async_zooming(
2006 txn: &mut Transaction,
2007 animation_id: u64,
2008 is_zooming: bool,
2009 ) {
2010 txn.set_is_transform_async_zooming(is_zooming, PropertyBindingId::new(animation_id));
2011 }
2012
2013 #[no_mangle]
wr_transaction_set_quality_settings(txn: &mut Transaction, force_subpixel_aa_where_possible: bool)2014 pub extern "C" fn wr_transaction_set_quality_settings(txn: &mut Transaction, force_subpixel_aa_where_possible: bool) {
2015 txn.set_quality_settings(QualitySettings {
2016 force_subpixel_aa_where_possible,
2017 });
2018 }
2019
2020 #[no_mangle]
wr_resource_updates_add_image( txn: &mut Transaction, image_key: WrImageKey, descriptor: &WrImageDescriptor, bytes: &mut WrVecU8, )2021 pub extern "C" fn wr_resource_updates_add_image(
2022 txn: &mut Transaction,
2023 image_key: WrImageKey,
2024 descriptor: &WrImageDescriptor,
2025 bytes: &mut WrVecU8,
2026 ) {
2027 txn.add_image(
2028 image_key,
2029 descriptor.into(),
2030 ImageData::new(bytes.flush_into_vec()),
2031 None,
2032 );
2033 }
2034
2035 #[no_mangle]
wr_resource_updates_add_blob_image( txn: &mut Transaction, image_key: BlobImageKey, descriptor: &WrImageDescriptor, tile_size: u16, bytes: &mut WrVecU8, visible_rect: DeviceIntRect, )2036 pub extern "C" fn wr_resource_updates_add_blob_image(
2037 txn: &mut Transaction,
2038 image_key: BlobImageKey,
2039 descriptor: &WrImageDescriptor,
2040 tile_size: u16,
2041 bytes: &mut WrVecU8,
2042 visible_rect: DeviceIntRect,
2043 ) {
2044 txn.add_blob_image(
2045 image_key,
2046 descriptor.into(),
2047 Arc::new(bytes.flush_into_vec()),
2048 visible_rect,
2049 if descriptor.format == ImageFormat::BGRA8 {
2050 Some(tile_size)
2051 } else {
2052 None
2053 },
2054 );
2055 }
2056
2057 #[no_mangle]
wr_resource_updates_add_external_image( txn: &mut Transaction, image_key: WrImageKey, descriptor: &WrImageDescriptor, external_image_id: ExternalImageId, image_type: &ExternalImageType, channel_index: u8, )2058 pub extern "C" fn wr_resource_updates_add_external_image(
2059 txn: &mut Transaction,
2060 image_key: WrImageKey,
2061 descriptor: &WrImageDescriptor,
2062 external_image_id: ExternalImageId,
2063 image_type: &ExternalImageType,
2064 channel_index: u8,
2065 ) {
2066 txn.add_image(
2067 image_key,
2068 descriptor.into(),
2069 ImageData::External(ExternalImageData {
2070 id: external_image_id,
2071 channel_index,
2072 image_type: *image_type,
2073 }),
2074 None,
2075 );
2076 }
2077
2078 #[no_mangle]
wr_resource_updates_update_image( txn: &mut Transaction, key: WrImageKey, descriptor: &WrImageDescriptor, bytes: &mut WrVecU8, )2079 pub extern "C" fn wr_resource_updates_update_image(
2080 txn: &mut Transaction,
2081 key: WrImageKey,
2082 descriptor: &WrImageDescriptor,
2083 bytes: &mut WrVecU8,
2084 ) {
2085 txn.update_image(
2086 key,
2087 descriptor.into(),
2088 ImageData::new(bytes.flush_into_vec()),
2089 &DirtyRect::All,
2090 );
2091 }
2092
2093 #[no_mangle]
wr_resource_updates_set_blob_image_visible_area( txn: &mut Transaction, key: BlobImageKey, area: &DeviceIntRect, )2094 pub extern "C" fn wr_resource_updates_set_blob_image_visible_area(
2095 txn: &mut Transaction,
2096 key: BlobImageKey,
2097 area: &DeviceIntRect,
2098 ) {
2099 txn.set_blob_image_visible_area(key, *area);
2100 }
2101
2102 #[no_mangle]
wr_resource_updates_update_external_image( txn: &mut Transaction, key: WrImageKey, descriptor: &WrImageDescriptor, external_image_id: ExternalImageId, image_type: &ExternalImageType, channel_index: u8, )2103 pub extern "C" fn wr_resource_updates_update_external_image(
2104 txn: &mut Transaction,
2105 key: WrImageKey,
2106 descriptor: &WrImageDescriptor,
2107 external_image_id: ExternalImageId,
2108 image_type: &ExternalImageType,
2109 channel_index: u8,
2110 ) {
2111 txn.update_image(
2112 key,
2113 descriptor.into(),
2114 ImageData::External(ExternalImageData {
2115 id: external_image_id,
2116 channel_index,
2117 image_type: *image_type,
2118 }),
2119 &DirtyRect::All,
2120 );
2121 }
2122
2123 #[no_mangle]
wr_resource_updates_update_external_image_with_dirty_rect( txn: &mut Transaction, key: WrImageKey, descriptor: &WrImageDescriptor, external_image_id: ExternalImageId, image_type: &ExternalImageType, channel_index: u8, dirty_rect: DeviceIntRect, )2124 pub extern "C" fn wr_resource_updates_update_external_image_with_dirty_rect(
2125 txn: &mut Transaction,
2126 key: WrImageKey,
2127 descriptor: &WrImageDescriptor,
2128 external_image_id: ExternalImageId,
2129 image_type: &ExternalImageType,
2130 channel_index: u8,
2131 dirty_rect: DeviceIntRect,
2132 ) {
2133 txn.update_image(
2134 key,
2135 descriptor.into(),
2136 ImageData::External(ExternalImageData {
2137 id: external_image_id,
2138 channel_index,
2139 image_type: *image_type,
2140 }),
2141 &DirtyRect::Partial(dirty_rect),
2142 );
2143 }
2144
2145 #[no_mangle]
wr_resource_updates_update_blob_image( txn: &mut Transaction, image_key: BlobImageKey, descriptor: &WrImageDescriptor, bytes: &mut WrVecU8, visible_rect: DeviceIntRect, dirty_rect: LayoutIntRect, )2146 pub extern "C" fn wr_resource_updates_update_blob_image(
2147 txn: &mut Transaction,
2148 image_key: BlobImageKey,
2149 descriptor: &WrImageDescriptor,
2150 bytes: &mut WrVecU8,
2151 visible_rect: DeviceIntRect,
2152 dirty_rect: LayoutIntRect,
2153 ) {
2154 txn.update_blob_image(
2155 image_key,
2156 descriptor.into(),
2157 Arc::new(bytes.flush_into_vec()),
2158 visible_rect,
2159 &DirtyRect::Partial(dirty_rect),
2160 );
2161 }
2162
2163 #[no_mangle]
wr_resource_updates_delete_image(txn: &mut Transaction, key: WrImageKey)2164 pub extern "C" fn wr_resource_updates_delete_image(txn: &mut Transaction, key: WrImageKey) {
2165 txn.delete_image(key);
2166 }
2167
2168 #[no_mangle]
wr_resource_updates_delete_blob_image(txn: &mut Transaction, key: BlobImageKey)2169 pub extern "C" fn wr_resource_updates_delete_blob_image(txn: &mut Transaction, key: BlobImageKey) {
2170 txn.delete_blob_image(key);
2171 }
2172
2173 #[no_mangle]
wr_api_send_transaction(dh: &mut DocumentHandle, transaction: &mut Transaction, is_async: bool)2174 pub extern "C" fn wr_api_send_transaction(dh: &mut DocumentHandle, transaction: &mut Transaction, is_async: bool) {
2175 if transaction.is_empty() {
2176 return;
2177 }
2178 let new_txn = make_transaction(is_async);
2179 let txn = mem::replace(transaction, new_txn);
2180 dh.api.send_transaction(dh.document_id, txn);
2181 }
2182
2183 #[no_mangle]
wr_transaction_clear_display_list( txn: &mut Transaction, epoch: WrEpoch, pipeline_id: WrPipelineId, )2184 pub unsafe extern "C" fn wr_transaction_clear_display_list(
2185 txn: &mut Transaction,
2186 epoch: WrEpoch,
2187 pipeline_id: WrPipelineId,
2188 ) {
2189 let mut frame_builder = WebRenderFrameBuilder::new(pipeline_id);
2190 frame_builder.dl_builder.begin();
2191
2192 txn.set_display_list(epoch, None, LayoutSize::new(0.0, 0.0), frame_builder.dl_builder.end());
2193 }
2194
2195 #[no_mangle]
wr_api_send_external_event(dh: &mut DocumentHandle, evt: usize)2196 pub extern "C" fn wr_api_send_external_event(dh: &mut DocumentHandle, evt: usize) {
2197 assert!(unsafe { !is_in_render_thread() });
2198
2199 dh.api.send_external_event(ExternalEvent::from_raw(evt));
2200 }
2201
2202 #[no_mangle]
wr_resource_updates_add_raw_font( txn: &mut Transaction, key: WrFontKey, bytes: &mut WrVecU8, index: u32, )2203 pub extern "C" fn wr_resource_updates_add_raw_font(
2204 txn: &mut Transaction,
2205 key: WrFontKey,
2206 bytes: &mut WrVecU8,
2207 index: u32,
2208 ) {
2209 txn.add_raw_font(key, bytes.flush_into_vec(), index);
2210 }
2211
generate_capture_path(path: *const c_char) -> Option<PathBuf>2212 fn generate_capture_path(path: *const c_char) -> Option<PathBuf> {
2213 use std::fs::{create_dir_all, File};
2214 use std::io::Write;
2215
2216 let cstr = unsafe { CStr::from_ptr(path) };
2217 let local_dir = PathBuf::from(&*cstr.to_string_lossy());
2218
2219 // On Android we need to write into a particular folder on external
2220 // storage so that (a) it can be written without requiring permissions
2221 // and (b) it can be pulled off via `adb pull`. This env var is set
2222 // in GeckoLoader.java.
2223 // When running in Firefox CI, the MOZ_UPLOAD_DIR variable is set to a path
2224 // that taskcluster will export artifacts from, so let's put it there.
2225 let mut path = if let Ok(storage_path) = env::var("PUBLIC_STORAGE") {
2226 PathBuf::from(storage_path).join(local_dir)
2227 } else if let Ok(storage_path) = env::var("MOZ_UPLOAD_DIR") {
2228 PathBuf::from(storage_path).join(local_dir)
2229 } else if let Some(storage_path) = dirs::home_dir() {
2230 storage_path.join(local_dir)
2231 } else {
2232 local_dir
2233 };
2234
2235 // Increment the extension until we find a fresh path
2236 while path.is_dir() {
2237 let count: u32 = path
2238 .extension()
2239 .and_then(|x| x.to_str())
2240 .and_then(|x| x.parse().ok())
2241 .unwrap_or(0);
2242 path.set_extension((count + 1).to_string());
2243 }
2244
2245 // Use warn! so that it gets emitted to logcat on android as well
2246 let border = "--------------------------\n";
2247 warn!("{} Capturing WR state to: {:?}\n{}", &border, &path, &border);
2248
2249 let _ = create_dir_all(&path);
2250 match File::create(path.join("wr.txt")) {
2251 Ok(mut file) => {
2252 // The Gecko HG revision is available at compile time
2253 if let Some(moz_revision) = option_env!("GECKO_HEAD_REV") {
2254 writeln!(file, "mozilla-central {}", moz_revision).unwrap();
2255 }
2256 Some(path)
2257 },
2258 Err(e) => {
2259 warn!("Unable to create path '{:?}' for capture: {:?}", path, e);
2260 None
2261 },
2262 }
2263 }
2264
2265 #[no_mangle]
wr_api_capture(dh: &mut DocumentHandle, path: *const c_char, bits_raw: u32)2266 pub extern "C" fn wr_api_capture(dh: &mut DocumentHandle, path: *const c_char, bits_raw: u32) {
2267 if let Some(path) = generate_capture_path(path) {
2268 let bits = CaptureBits::from_bits(bits_raw as _).unwrap();
2269 dh.api.save_capture(path, bits);
2270 }
2271 }
2272
2273 #[no_mangle]
wr_api_start_capture_sequence(dh: &mut DocumentHandle, path: *const c_char, bits_raw: u32)2274 pub extern "C" fn wr_api_start_capture_sequence(dh: &mut DocumentHandle, path: *const c_char, bits_raw: u32) {
2275 if let Some(path) = generate_capture_path(path) {
2276 let bits = CaptureBits::from_bits(bits_raw as _).unwrap();
2277 dh.api.start_capture_sequence(path, bits);
2278 }
2279 }
2280
2281 #[no_mangle]
wr_api_stop_capture_sequence(dh: &mut DocumentHandle)2282 pub extern "C" fn wr_api_stop_capture_sequence(dh: &mut DocumentHandle) {
2283 let border = "--------------------------\n";
2284 warn!("{} Stop capturing WR state\n{}", &border, &border);
2285 dh.api.stop_capture_sequence();
2286 }
2287
2288 #[cfg(target_os = "windows")]
read_font_descriptor(bytes: &mut WrVecU8, index: u32) -> NativeFontHandle2289 fn read_font_descriptor(bytes: &mut WrVecU8, index: u32) -> NativeFontHandle {
2290 let wchars = bytes.convert_into_vec::<u16>();
2291 NativeFontHandle {
2292 path: PathBuf::from(OsString::from_wide(&wchars)),
2293 index,
2294 }
2295 }
2296
2297 #[cfg(target_os = "macos")]
read_font_descriptor(bytes: &mut WrVecU8, _index: u32) -> NativeFontHandle2298 fn read_font_descriptor(bytes: &mut WrVecU8, _index: u32) -> NativeFontHandle {
2299 let chars = bytes.flush_into_vec();
2300 NativeFontHandle {
2301 name: String::from_utf8(chars).unwrap()
2302 }
2303 }
2304
2305 #[cfg(not(any(target_os = "macos", target_os = "windows")))]
read_font_descriptor(bytes: &mut WrVecU8, index: u32) -> NativeFontHandle2306 fn read_font_descriptor(bytes: &mut WrVecU8, index: u32) -> NativeFontHandle {
2307 let chars = bytes.flush_into_vec();
2308 NativeFontHandle {
2309 path: PathBuf::from(OsString::from_vec(chars)),
2310 index,
2311 }
2312 }
2313
2314 #[no_mangle]
wr_resource_updates_add_font_descriptor( txn: &mut Transaction, key: WrFontKey, bytes: &mut WrVecU8, index: u32, )2315 pub extern "C" fn wr_resource_updates_add_font_descriptor(
2316 txn: &mut Transaction,
2317 key: WrFontKey,
2318 bytes: &mut WrVecU8,
2319 index: u32,
2320 ) {
2321 let native_font_handle = read_font_descriptor(bytes, index);
2322 txn.add_native_font(key, native_font_handle);
2323 }
2324
2325 #[no_mangle]
wr_resource_updates_delete_font(txn: &mut Transaction, key: WrFontKey)2326 pub extern "C" fn wr_resource_updates_delete_font(txn: &mut Transaction, key: WrFontKey) {
2327 txn.delete_font(key);
2328 }
2329
2330 #[no_mangle]
wr_resource_updates_add_font_instance( txn: &mut Transaction, key: WrFontInstanceKey, font_key: WrFontKey, glyph_size: f32, options: *const FontInstanceOptions, platform_options: *const FontInstancePlatformOptions, variations: &mut WrVecU8, )2331 pub extern "C" fn wr_resource_updates_add_font_instance(
2332 txn: &mut Transaction,
2333 key: WrFontInstanceKey,
2334 font_key: WrFontKey,
2335 glyph_size: f32,
2336 options: *const FontInstanceOptions,
2337 platform_options: *const FontInstancePlatformOptions,
2338 variations: &mut WrVecU8,
2339 ) {
2340 txn.add_font_instance(
2341 key,
2342 font_key,
2343 glyph_size,
2344 unsafe { options.as_ref().cloned() },
2345 unsafe { platform_options.as_ref().cloned() },
2346 variations.convert_into_vec::<FontVariation>(),
2347 );
2348 }
2349
2350 #[no_mangle]
wr_resource_updates_delete_font_instance(txn: &mut Transaction, key: WrFontInstanceKey)2351 pub extern "C" fn wr_resource_updates_delete_font_instance(txn: &mut Transaction, key: WrFontInstanceKey) {
2352 txn.delete_font_instance(key);
2353 }
2354
2355 #[no_mangle]
wr_resource_updates_clear(txn: &mut Transaction)2356 pub extern "C" fn wr_resource_updates_clear(txn: &mut Transaction) {
2357 txn.resource_updates.clear();
2358 }
2359
2360 #[no_mangle]
wr_api_get_namespace(dh: &mut DocumentHandle) -> WrIdNamespace2361 pub unsafe extern "C" fn wr_api_get_namespace(dh: &mut DocumentHandle) -> WrIdNamespace {
2362 dh.api.get_namespace_id()
2363 }
2364
2365 #[no_mangle]
wr_api_wake_scene_builder(dh: &mut DocumentHandle)2366 pub unsafe extern "C" fn wr_api_wake_scene_builder(dh: &mut DocumentHandle) {
2367 dh.api.wake_scene_builder();
2368 }
2369
2370 #[no_mangle]
wr_api_flush_scene_builder(dh: &mut DocumentHandle)2371 pub unsafe extern "C" fn wr_api_flush_scene_builder(dh: &mut DocumentHandle) {
2372 dh.api.flush_scene_builder();
2373 }
2374
2375 // RenderThread WIP notes:
2376 // In order to separate the compositor thread (or ipc receiver) and the render
2377 // thread, some of the logic below needs to be rewritten. In particular
2378 // the WrWindowState and Notifier implementations aren't designed to work with
2379 // a separate render thread.
2380 // As part of that I am moving the bindings closer to WebRender's API boundary,
2381 // and moving more of the logic in C++ land.
2382 // This work is tracked by bug 1328602.
2383 //
2384 // See RenderThread.h for some notes about how the pieces fit together.
2385
2386 pub struct WebRenderFrameBuilder {
2387 pub root_pipeline_id: WrPipelineId,
2388 pub dl_builder: DisplayListBuilder,
2389 }
2390
2391 impl WebRenderFrameBuilder {
new(root_pipeline_id: WrPipelineId) -> WebRenderFrameBuilder2392 pub fn new(root_pipeline_id: WrPipelineId) -> WebRenderFrameBuilder {
2393 WebRenderFrameBuilder {
2394 root_pipeline_id,
2395 dl_builder: DisplayListBuilder::new(root_pipeline_id),
2396 }
2397 }
2398 }
2399
2400 pub struct WrState {
2401 pipeline_id: WrPipelineId,
2402 frame_builder: WebRenderFrameBuilder,
2403 }
2404
2405 #[no_mangle]
wr_state_new(pipeline_id: WrPipelineId) -> *mut WrState2406 pub extern "C" fn wr_state_new(pipeline_id: WrPipelineId) -> *mut WrState {
2407 assert!(unsafe { !is_in_render_thread() });
2408
2409 let state = Box::new(WrState {
2410 pipeline_id,
2411 frame_builder: WebRenderFrameBuilder::new(pipeline_id),
2412 });
2413
2414 Box::into_raw(state)
2415 }
2416
2417 #[no_mangle]
wr_state_delete(state: *mut WrState)2418 pub extern "C" fn wr_state_delete(state: *mut WrState) {
2419 assert!(unsafe { !is_in_render_thread() });
2420
2421 unsafe {
2422 Box::from_raw(state);
2423 }
2424 }
2425
2426 #[no_mangle]
wr_dp_save(state: &mut WrState)2427 pub extern "C" fn wr_dp_save(state: &mut WrState) {
2428 state.frame_builder.dl_builder.save();
2429 }
2430
2431 #[no_mangle]
wr_dp_restore(state: &mut WrState)2432 pub extern "C" fn wr_dp_restore(state: &mut WrState) {
2433 state.frame_builder.dl_builder.restore();
2434 }
2435
2436 #[no_mangle]
wr_dp_clear_save(state: &mut WrState)2437 pub extern "C" fn wr_dp_clear_save(state: &mut WrState) {
2438 state.frame_builder.dl_builder.clear_save();
2439 }
2440
2441 #[repr(u8)]
2442 #[derive(PartialEq, Eq, Debug)]
2443 pub enum WrReferenceFrameKind {
2444 Transform,
2445 Perspective,
2446 }
2447
2448 #[repr(u8)]
2449 #[derive(PartialEq, Eq, Debug)]
2450 pub enum WrRotation {
2451 Degree0,
2452 Degree90,
2453 Degree180,
2454 Degree270,
2455 }
2456
2457 /// IMPORTANT: If you add fields to this struct, you need to also add initializers
2458 /// for those fields in WebRenderAPI.h.
2459 #[repr(C)]
2460 pub struct WrStackingContextParams {
2461 pub clip: WrStackingContextClip,
2462 pub animation: *const WrAnimationProperty,
2463 pub opacity: *const f32,
2464 pub computed_transform: *const WrComputedTransformData,
2465 pub transform_style: TransformStyle,
2466 pub reference_frame_kind: WrReferenceFrameKind,
2467 pub is_2d_scale_translation: bool,
2468 pub should_snap: bool,
2469 pub paired_with_perspective: bool,
2470 pub scrolling_relative_to: *const u64,
2471 pub prim_flags: PrimitiveFlags,
2472 pub mix_blend_mode: MixBlendMode,
2473 pub flags: StackingContextFlags,
2474 }
2475
2476 #[no_mangle]
wr_dp_push_stacking_context( state: &mut WrState, bounds: LayoutRect, spatial_id: WrSpatialId, params: &WrStackingContextParams, transform: *const WrTransformInfo, filters: *const FilterOp, filter_count: usize, filter_datas: *const WrFilterData, filter_datas_count: usize, glyph_raster_space: RasterSpace, ) -> WrSpatialId2477 pub extern "C" fn wr_dp_push_stacking_context(
2478 state: &mut WrState,
2479 bounds: LayoutRect,
2480 spatial_id: WrSpatialId,
2481 params: &WrStackingContextParams,
2482 transform: *const WrTransformInfo,
2483 filters: *const FilterOp,
2484 filter_count: usize,
2485 filter_datas: *const WrFilterData,
2486 filter_datas_count: usize,
2487 glyph_raster_space: RasterSpace,
2488 ) -> WrSpatialId {
2489 debug_assert!(unsafe { !is_in_render_thread() });
2490
2491 let c_filters = unsafe { make_slice(filters, filter_count) };
2492 let mut filters: Vec<FilterOp> = c_filters.iter().copied().collect();
2493
2494 let c_filter_datas = unsafe { make_slice(filter_datas, filter_datas_count) };
2495 let r_filter_datas: Vec<FilterData> = c_filter_datas
2496 .iter()
2497 .map(|c_filter_data| FilterData {
2498 func_r_type: c_filter_data.funcR_type,
2499 r_values: unsafe { make_slice(c_filter_data.R_values, c_filter_data.R_values_count).to_vec() },
2500 func_g_type: c_filter_data.funcG_type,
2501 g_values: unsafe { make_slice(c_filter_data.G_values, c_filter_data.G_values_count).to_vec() },
2502 func_b_type: c_filter_data.funcB_type,
2503 b_values: unsafe { make_slice(c_filter_data.B_values, c_filter_data.B_values_count).to_vec() },
2504 func_a_type: c_filter_data.funcA_type,
2505 a_values: unsafe { make_slice(c_filter_data.A_values, c_filter_data.A_values_count).to_vec() },
2506 })
2507 .collect();
2508
2509 let transform_ref = unsafe { transform.as_ref() };
2510 let mut transform_binding = transform_ref.map(|info| (PropertyBinding::Value(info.transform), info.key));
2511
2512 let computed_ref = unsafe { params.computed_transform.as_ref() };
2513 let opacity_ref = unsafe { params.opacity.as_ref() };
2514 let mut has_opacity_animation = false;
2515 let anim = unsafe { params.animation.as_ref() };
2516 if let Some(anim) = anim {
2517 debug_assert!(anim.id > 0);
2518 match anim.effect_type {
2519 WrAnimationType::Opacity => {
2520 filters.push(FilterOp::Opacity(
2521 PropertyBinding::Binding(
2522 PropertyBindingKey::new(anim.id),
2523 // We have to set the static opacity value as
2524 // the value for the case where the animation is
2525 // in not in-effect (e.g. in the delay phase
2526 // with no corresponding fill mode).
2527 opacity_ref.cloned().unwrap_or(1.0),
2528 ),
2529 1.0,
2530 ));
2531 has_opacity_animation = true;
2532 },
2533 WrAnimationType::Transform => {
2534 transform_binding = Some((
2535 PropertyBinding::Binding(
2536 PropertyBindingKey::new(anim.id),
2537 // Same as above opacity case.
2538 transform_ref
2539 .map(|info| info.transform)
2540 .unwrap_or_else(LayoutTransform::identity),
2541 ),
2542 anim.key,
2543 ));
2544 },
2545 _ => unreachable!("{:?} should not create a stacking context", anim.effect_type),
2546 }
2547 }
2548
2549 if let Some(opacity) = opacity_ref {
2550 if !has_opacity_animation && *opacity < 1.0 {
2551 filters.push(FilterOp::Opacity(PropertyBinding::Value(*opacity), *opacity));
2552 }
2553 }
2554
2555 let mut wr_spatial_id = spatial_id.to_webrender(state.pipeline_id);
2556 let wr_clip_id = params.clip.to_webrender(state.pipeline_id);
2557
2558 let mut origin = bounds.min;
2559
2560 // Note: 0 has special meaning in WR land, standing for ROOT_REFERENCE_FRAME.
2561 // However, it is never returned by `push_reference_frame`, and we need to return
2562 // an option here across FFI, so we take that 0 value for the None semantics.
2563 // This is resolved into proper `Maybe<WrSpatialId>` inside `WebRenderAPI::PushStackingContext`.
2564 let mut result = WrSpatialId { id: 0 };
2565 if let Some(transform_binding) = transform_binding {
2566 let scrolling_relative_to = match unsafe { params.scrolling_relative_to.as_ref() } {
2567 Some(scroll_id) => {
2568 debug_assert_eq!(params.reference_frame_kind, WrReferenceFrameKind::Perspective);
2569 Some(ExternalScrollId(*scroll_id, state.pipeline_id))
2570 },
2571 None => None,
2572 };
2573
2574 let reference_frame_kind = match params.reference_frame_kind {
2575 WrReferenceFrameKind::Transform => ReferenceFrameKind::Transform {
2576 is_2d_scale_translation: params.is_2d_scale_translation,
2577 should_snap: params.should_snap,
2578 paired_with_perspective: params.paired_with_perspective,
2579 },
2580 WrReferenceFrameKind::Perspective => ReferenceFrameKind::Perspective { scrolling_relative_to },
2581 };
2582 wr_spatial_id = state.frame_builder.dl_builder.push_reference_frame(
2583 origin,
2584 wr_spatial_id,
2585 params.transform_style,
2586 transform_binding.0,
2587 reference_frame_kind,
2588 transform_binding.1,
2589 );
2590
2591 origin = LayoutPoint::zero();
2592 result.id = wr_spatial_id.0;
2593 assert_ne!(wr_spatial_id.0, 0);
2594 } else if let Some(data) = computed_ref {
2595 let rotation = match data.rotation {
2596 WrRotation::Degree0 => Rotation::Degree0,
2597 WrRotation::Degree90 => Rotation::Degree90,
2598 WrRotation::Degree180 => Rotation::Degree180,
2599 WrRotation::Degree270 => Rotation::Degree270,
2600 };
2601 wr_spatial_id = state.frame_builder.dl_builder.push_computed_frame(
2602 origin,
2603 wr_spatial_id,
2604 Some(data.scale_from),
2605 data.vertical_flip,
2606 rotation,
2607 data.key,
2608 );
2609
2610 origin = LayoutPoint::zero();
2611 result.id = wr_spatial_id.0;
2612 assert_ne!(wr_spatial_id.0, 0);
2613 }
2614
2615 state.frame_builder.dl_builder.push_stacking_context(
2616 origin,
2617 wr_spatial_id,
2618 params.prim_flags,
2619 wr_clip_id,
2620 params.transform_style,
2621 params.mix_blend_mode,
2622 &filters,
2623 &r_filter_datas,
2624 &[],
2625 glyph_raster_space,
2626 params.flags,
2627 );
2628
2629 result
2630 }
2631
2632 #[no_mangle]
wr_dp_pop_stacking_context(state: &mut WrState, is_reference_frame: bool)2633 pub extern "C" fn wr_dp_pop_stacking_context(state: &mut WrState, is_reference_frame: bool) {
2634 debug_assert!(unsafe { !is_in_render_thread() });
2635 state.frame_builder.dl_builder.pop_stacking_context();
2636 if is_reference_frame {
2637 state.frame_builder.dl_builder.pop_reference_frame();
2638 }
2639 }
2640
2641 #[no_mangle]
wr_dp_define_clipchain( state: &mut WrState, parent_clipchain_id: *const u64, clips: *const WrClipId, clips_count: usize, ) -> u642642 pub extern "C" fn wr_dp_define_clipchain(
2643 state: &mut WrState,
2644 parent_clipchain_id: *const u64,
2645 clips: *const WrClipId,
2646 clips_count: usize,
2647 ) -> u64 {
2648 debug_assert!(unsafe { is_in_main_thread() });
2649 let parent = unsafe { parent_clipchain_id.as_ref() }.map(|id| ClipChainId(*id, state.pipeline_id));
2650
2651 let pipeline_id = state.pipeline_id;
2652 let clips = unsafe { make_slice(clips, clips_count) }
2653 .iter()
2654 .map(|clip_id| clip_id.to_webrender(pipeline_id));
2655
2656 let clipchain_id = state.frame_builder.dl_builder.define_clip_chain(parent, clips);
2657 assert!(clipchain_id.1 == state.pipeline_id);
2658 clipchain_id.0
2659 }
2660
2661 #[no_mangle]
wr_dp_define_image_mask_clip_with_parent_clip_chain( state: &mut WrState, parent: &WrSpaceAndClipChain, mask: ImageMask, points: *const LayoutPoint, point_count: usize, fill_rule: FillRule, ) -> WrClipId2662 pub extern "C" fn wr_dp_define_image_mask_clip_with_parent_clip_chain(
2663 state: &mut WrState,
2664 parent: &WrSpaceAndClipChain,
2665 mask: ImageMask,
2666 points: *const LayoutPoint,
2667 point_count: usize,
2668 fill_rule: FillRule,
2669 ) -> WrClipId {
2670 debug_assert!(unsafe { is_in_main_thread() });
2671
2672 let c_points = unsafe { make_slice(points, point_count) };
2673 let points: Vec<LayoutPoint> = c_points.iter().copied().collect();
2674
2675 let clip_id = state.frame_builder.dl_builder.define_clip_image_mask(
2676 &parent.to_webrender(state.pipeline_id),
2677 mask,
2678 &points,
2679 fill_rule,
2680 );
2681 WrClipId::from_webrender(clip_id)
2682 }
2683
2684 #[no_mangle]
wr_dp_define_rounded_rect_clip( state: &mut WrState, space: WrSpatialId, complex: ComplexClipRegion, ) -> WrClipId2685 pub extern "C" fn wr_dp_define_rounded_rect_clip(
2686 state: &mut WrState,
2687 space: WrSpatialId,
2688 complex: ComplexClipRegion,
2689 ) -> WrClipId {
2690 debug_assert!(unsafe { is_in_main_thread() });
2691
2692 let space_and_clip = SpaceAndClipInfo {
2693 spatial_id: space.to_webrender(state.pipeline_id),
2694 clip_id: ClipId::root(state.pipeline_id),
2695 };
2696
2697 let clip_id = state
2698 .frame_builder
2699 .dl_builder
2700 .define_clip_rounded_rect(&space_and_clip, complex);
2701 WrClipId::from_webrender(clip_id)
2702 }
2703
2704 #[no_mangle]
wr_dp_define_rounded_rect_clip_with_parent_clip_chain( state: &mut WrState, parent: &WrSpaceAndClipChain, complex: ComplexClipRegion, ) -> WrClipId2705 pub extern "C" fn wr_dp_define_rounded_rect_clip_with_parent_clip_chain(
2706 state: &mut WrState,
2707 parent: &WrSpaceAndClipChain,
2708 complex: ComplexClipRegion,
2709 ) -> WrClipId {
2710 debug_assert!(unsafe { is_in_main_thread() });
2711
2712 let clip_id = state
2713 .frame_builder
2714 .dl_builder
2715 .define_clip_rounded_rect(&parent.to_webrender(state.pipeline_id), complex);
2716 WrClipId::from_webrender(clip_id)
2717 }
2718
2719 #[no_mangle]
wr_dp_define_rect_clip(state: &mut WrState, space: WrSpatialId, clip_rect: LayoutRect) -> WrClipId2720 pub extern "C" fn wr_dp_define_rect_clip(state: &mut WrState, space: WrSpatialId, clip_rect: LayoutRect) -> WrClipId {
2721 debug_assert!(unsafe { is_in_main_thread() });
2722
2723 let space_and_clip = SpaceAndClipInfo {
2724 spatial_id: space.to_webrender(state.pipeline_id),
2725 clip_id: ClipId::root(state.pipeline_id),
2726 };
2727
2728 let clip_id = state
2729 .frame_builder
2730 .dl_builder
2731 .define_clip_rect(&space_and_clip, clip_rect);
2732 WrClipId::from_webrender(clip_id)
2733 }
2734
2735 #[no_mangle]
wr_dp_define_rect_clip_with_parent_clip_chain( state: &mut WrState, parent: &WrSpaceAndClipChain, clip_rect: LayoutRect, ) -> WrClipId2736 pub extern "C" fn wr_dp_define_rect_clip_with_parent_clip_chain(
2737 state: &mut WrState,
2738 parent: &WrSpaceAndClipChain,
2739 clip_rect: LayoutRect,
2740 ) -> WrClipId {
2741 debug_assert!(unsafe { is_in_main_thread() });
2742
2743 let clip_id = state
2744 .frame_builder
2745 .dl_builder
2746 .define_clip_rect(&parent.to_webrender(state.pipeline_id), clip_rect);
2747 WrClipId::from_webrender(clip_id)
2748 }
2749
2750 #[no_mangle]
wr_dp_define_sticky_frame( state: &mut WrState, parent_spatial_id: WrSpatialId, content_rect: LayoutRect, top_margin: *const f32, right_margin: *const f32, bottom_margin: *const f32, left_margin: *const f32, vertical_bounds: StickyOffsetBounds, horizontal_bounds: StickyOffsetBounds, applied_offset: LayoutVector2D, key: SpatialTreeItemKey, ) -> WrSpatialId2751 pub extern "C" fn wr_dp_define_sticky_frame(
2752 state: &mut WrState,
2753 parent_spatial_id: WrSpatialId,
2754 content_rect: LayoutRect,
2755 top_margin: *const f32,
2756 right_margin: *const f32,
2757 bottom_margin: *const f32,
2758 left_margin: *const f32,
2759 vertical_bounds: StickyOffsetBounds,
2760 horizontal_bounds: StickyOffsetBounds,
2761 applied_offset: LayoutVector2D,
2762 key: SpatialTreeItemKey,
2763 ) -> WrSpatialId {
2764 assert!(unsafe { is_in_main_thread() });
2765 let spatial_id = state.frame_builder.dl_builder.define_sticky_frame(
2766 parent_spatial_id.to_webrender(state.pipeline_id),
2767 content_rect,
2768 SideOffsets2D::new(
2769 unsafe { top_margin.as_ref() }.cloned(),
2770 unsafe { right_margin.as_ref() }.cloned(),
2771 unsafe { bottom_margin.as_ref() }.cloned(),
2772 unsafe { left_margin.as_ref() }.cloned(),
2773 ),
2774 vertical_bounds,
2775 horizontal_bounds,
2776 applied_offset,
2777 key,
2778 );
2779
2780 WrSpatialId { id: spatial_id.0 }
2781 }
2782
2783 #[no_mangle]
wr_dp_define_scroll_layer( state: &mut WrState, external_scroll_id: u64, parent: &WrSpatialId, content_rect: LayoutRect, clip_rect: LayoutRect, scroll_offset: LayoutVector2D, scroll_offset_generation: APZScrollGeneration, has_scroll_linked_effect: HasScrollLinkedEffect, key: SpatialTreeItemKey, ) -> WrSpatialId2784 pub extern "C" fn wr_dp_define_scroll_layer(
2785 state: &mut WrState,
2786 external_scroll_id: u64,
2787 parent: &WrSpatialId,
2788 content_rect: LayoutRect,
2789 clip_rect: LayoutRect,
2790 scroll_offset: LayoutVector2D,
2791 scroll_offset_generation: APZScrollGeneration,
2792 has_scroll_linked_effect: HasScrollLinkedEffect,
2793 key: SpatialTreeItemKey,
2794 ) -> WrSpatialId {
2795 assert!(unsafe { is_in_main_thread() });
2796
2797 let space_and_clip = state.frame_builder.dl_builder.define_scroll_frame(
2798 parent.to_webrender(state.pipeline_id),
2799 ExternalScrollId(external_scroll_id, state.pipeline_id),
2800 content_rect,
2801 clip_rect,
2802 scroll_offset,
2803 scroll_offset_generation,
2804 has_scroll_linked_effect,
2805 key,
2806 );
2807
2808 WrSpatialId::from_webrender(space_and_clip)
2809 }
2810
2811 #[no_mangle]
wr_dp_push_iframe( state: &mut WrState, rect: LayoutRect, clip: LayoutRect, _is_backface_visible: bool, parent: &WrSpaceAndClipChain, pipeline_id: WrPipelineId, ignore_missing_pipeline: bool, )2812 pub extern "C" fn wr_dp_push_iframe(
2813 state: &mut WrState,
2814 rect: LayoutRect,
2815 clip: LayoutRect,
2816 _is_backface_visible: bool,
2817 parent: &WrSpaceAndClipChain,
2818 pipeline_id: WrPipelineId,
2819 ignore_missing_pipeline: bool,
2820 ) {
2821 debug_assert!(unsafe { is_in_main_thread() });
2822
2823 state.frame_builder.dl_builder.push_iframe(
2824 rect,
2825 clip,
2826 &parent.to_webrender(state.pipeline_id),
2827 pipeline_id,
2828 ignore_missing_pipeline,
2829 );
2830 }
2831
2832 // A helper fn to construct a PrimitiveFlags
prim_flags(is_backface_visible: bool, prefer_compositor_surface: bool) -> PrimitiveFlags2833 fn prim_flags(is_backface_visible: bool, prefer_compositor_surface: bool) -> PrimitiveFlags {
2834 let mut flags = PrimitiveFlags::empty();
2835
2836 if is_backface_visible {
2837 flags |= PrimitiveFlags::IS_BACKFACE_VISIBLE;
2838 }
2839
2840 if prefer_compositor_surface {
2841 flags |= PrimitiveFlags::PREFER_COMPOSITOR_SURFACE;
2842 }
2843
2844 flags
2845 }
2846
prim_flags2( is_backface_visible: bool, prefer_compositor_surface: bool, supports_external_compositing: bool, ) -> PrimitiveFlags2847 fn prim_flags2(
2848 is_backface_visible: bool,
2849 prefer_compositor_surface: bool,
2850 supports_external_compositing: bool,
2851 ) -> PrimitiveFlags {
2852 let mut flags = PrimitiveFlags::empty();
2853
2854 if supports_external_compositing {
2855 flags |= PrimitiveFlags::SUPPORTS_EXTERNAL_COMPOSITOR_SURFACE;
2856 }
2857
2858 flags | prim_flags(is_backface_visible, prefer_compositor_surface)
2859 }
2860
common_item_properties_for_rect( state: &mut WrState, clip_rect: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, ) -> CommonItemProperties2861 fn common_item_properties_for_rect(
2862 state: &mut WrState,
2863 clip_rect: LayoutRect,
2864 is_backface_visible: bool,
2865 parent: &WrSpaceAndClipChain,
2866 ) -> CommonItemProperties {
2867 let space_and_clip = parent.to_webrender(state.pipeline_id);
2868
2869 CommonItemProperties {
2870 // NB: the damp-e10s talos-test will frequently crash on startup if we
2871 // early-return here for empty rects. I couldn't figure out why, but
2872 // it's pretty harmless to feed these through, so, uh, we do?
2873 clip_rect,
2874 clip_id: space_and_clip.clip_id,
2875 spatial_id: space_and_clip.spatial_id,
2876 flags: prim_flags(is_backface_visible, /* prefer_compositor_surface */ false),
2877 }
2878 }
2879
2880 #[no_mangle]
wr_dp_push_rect( state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, force_antialiasing: bool, parent: &WrSpaceAndClipChain, color: ColorF, )2881 pub extern "C" fn wr_dp_push_rect(
2882 state: &mut WrState,
2883 rect: LayoutRect,
2884 clip: LayoutRect,
2885 is_backface_visible: bool,
2886 force_antialiasing: bool,
2887 parent: &WrSpaceAndClipChain,
2888 color: ColorF,
2889 ) {
2890 debug_assert!(unsafe { !is_in_render_thread() });
2891
2892 let mut prim_info = common_item_properties_for_rect(state, clip, is_backface_visible, parent);
2893 if force_antialiasing {
2894 prim_info.flags |= PrimitiveFlags::ANTIALISED;
2895 }
2896
2897 state.frame_builder.dl_builder.push_rect(&prim_info, rect, color);
2898 }
2899
2900 #[no_mangle]
wr_dp_push_rect_with_animation( state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, color: ColorF, animation: *const WrAnimationProperty, )2901 pub extern "C" fn wr_dp_push_rect_with_animation(
2902 state: &mut WrState,
2903 rect: LayoutRect,
2904 clip: LayoutRect,
2905 is_backface_visible: bool,
2906 parent: &WrSpaceAndClipChain,
2907 color: ColorF,
2908 animation: *const WrAnimationProperty,
2909 ) {
2910 debug_assert!(unsafe { !is_in_render_thread() });
2911
2912 let prim_info = common_item_properties_for_rect(state, clip, is_backface_visible, parent);
2913
2914 let anim = unsafe { animation.as_ref() };
2915 if let Some(anim) = anim {
2916 debug_assert!(anim.id > 0);
2917 match anim.effect_type {
2918 WrAnimationType::BackgroundColor => state.frame_builder.dl_builder.push_rect_with_animation(
2919 &prim_info,
2920 rect,
2921 PropertyBinding::Binding(PropertyBindingKey::new(anim.id), color),
2922 ),
2923 _ => unreachable!("Didn't expect {:?} animation", anim.effect_type),
2924 }
2925 }
2926 }
2927
2928 #[no_mangle]
wr_dp_push_backdrop_filter( state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, filters: *const FilterOp, filter_count: usize, filter_datas: *const WrFilterData, filter_datas_count: usize, )2929 pub extern "C" fn wr_dp_push_backdrop_filter(
2930 state: &mut WrState,
2931 rect: LayoutRect,
2932 clip: LayoutRect,
2933 is_backface_visible: bool,
2934 parent: &WrSpaceAndClipChain,
2935 filters: *const FilterOp,
2936 filter_count: usize,
2937 filter_datas: *const WrFilterData,
2938 filter_datas_count: usize,
2939 ) {
2940 debug_assert!(unsafe { !is_in_render_thread() });
2941
2942 let c_filters = unsafe { make_slice(filters, filter_count) };
2943 let filters: Vec<FilterOp> = c_filters.iter().copied().collect();
2944
2945 let c_filter_datas = unsafe { make_slice(filter_datas, filter_datas_count) };
2946 let filter_datas: Vec<FilterData> = c_filter_datas
2947 .iter()
2948 .map(|c_filter_data| FilterData {
2949 func_r_type: c_filter_data.funcR_type,
2950 r_values: unsafe { make_slice(c_filter_data.R_values, c_filter_data.R_values_count).to_vec() },
2951 func_g_type: c_filter_data.funcG_type,
2952 g_values: unsafe { make_slice(c_filter_data.G_values, c_filter_data.G_values_count).to_vec() },
2953 func_b_type: c_filter_data.funcB_type,
2954 b_values: unsafe { make_slice(c_filter_data.B_values, c_filter_data.B_values_count).to_vec() },
2955 func_a_type: c_filter_data.funcA_type,
2956 a_values: unsafe { make_slice(c_filter_data.A_values, c_filter_data.A_values_count).to_vec() },
2957 })
2958 .collect();
2959
2960 let space_and_clip = parent.to_webrender(state.pipeline_id);
2961
2962 let clip_rect = clip.intersection(&rect);
2963 if clip_rect.is_none() {
2964 return;
2965 }
2966
2967 let prim_info = CommonItemProperties {
2968 clip_rect: clip_rect.unwrap(),
2969 clip_id: space_and_clip.clip_id,
2970 spatial_id: space_and_clip.spatial_id,
2971 flags: prim_flags(is_backface_visible, /* prefer_compositor_surface */ false),
2972 };
2973
2974 state
2975 .frame_builder
2976 .dl_builder
2977 .push_backdrop_filter(&prim_info, &filters, &filter_datas, &[]);
2978 }
2979
2980 #[no_mangle]
wr_dp_push_clear_rect( state: &mut WrState, rect: LayoutRect, clip_rect: LayoutRect, parent: &WrSpaceAndClipChain, )2981 pub extern "C" fn wr_dp_push_clear_rect(
2982 state: &mut WrState,
2983 rect: LayoutRect,
2984 clip_rect: LayoutRect,
2985 parent: &WrSpaceAndClipChain,
2986 ) {
2987 debug_assert!(unsafe { !is_in_render_thread() });
2988
2989 let space_and_clip = parent.to_webrender(state.pipeline_id);
2990
2991 let prim_info = CommonItemProperties {
2992 clip_rect,
2993 clip_id: space_and_clip.clip_id,
2994 spatial_id: space_and_clip.spatial_id,
2995 flags: prim_flags(true, /* prefer_compositor_surface */ false),
2996 };
2997
2998 state.frame_builder.dl_builder.push_clear_rect(&prim_info, rect);
2999 }
3000
3001 #[no_mangle]
wr_dp_push_hit_test( state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, scroll_id: u64, hit_info: u16, )3002 pub extern "C" fn wr_dp_push_hit_test(
3003 state: &mut WrState,
3004 rect: LayoutRect,
3005 clip: LayoutRect,
3006 is_backface_visible: bool,
3007 parent: &WrSpaceAndClipChain,
3008 scroll_id: u64,
3009 hit_info: u16,
3010 ) {
3011 debug_assert!(unsafe { !is_in_render_thread() });
3012
3013 let space_and_clip = parent.to_webrender(state.pipeline_id);
3014
3015 let clip_rect = clip.intersection(&rect);
3016 if clip_rect.is_none() {
3017 return;
3018 }
3019 let tag = (scroll_id, hit_info);
3020
3021 let prim_info = CommonItemProperties {
3022 clip_rect: clip_rect.unwrap(),
3023 clip_id: space_and_clip.clip_id,
3024 spatial_id: space_and_clip.spatial_id,
3025 flags: prim_flags(is_backface_visible, /* prefer_compositor_surface */ false),
3026 };
3027
3028 state.frame_builder.dl_builder.push_hit_test(&prim_info, tag);
3029 }
3030
3031 #[no_mangle]
wr_dp_push_image( state: &mut WrState, bounds: LayoutRect, clip: LayoutRect, is_backface_visible: bool, force_antialiasing: bool, parent: &WrSpaceAndClipChain, image_rendering: ImageRendering, key: WrImageKey, premultiplied_alpha: bool, color: ColorF, prefer_compositor_surface: bool, supports_external_compositing: bool, )3032 pub extern "C" fn wr_dp_push_image(
3033 state: &mut WrState,
3034 bounds: LayoutRect,
3035 clip: LayoutRect,
3036 is_backface_visible: bool,
3037 force_antialiasing: bool,
3038 parent: &WrSpaceAndClipChain,
3039 image_rendering: ImageRendering,
3040 key: WrImageKey,
3041 premultiplied_alpha: bool,
3042 color: ColorF,
3043 prefer_compositor_surface: bool,
3044 supports_external_compositing: bool,
3045 ) {
3046 debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
3047
3048 let space_and_clip = parent.to_webrender(state.pipeline_id);
3049
3050 let mut flags = prim_flags2(
3051 is_backface_visible,
3052 prefer_compositor_surface,
3053 supports_external_compositing,
3054 );
3055
3056 if force_antialiasing {
3057 flags |= PrimitiveFlags::ANTIALISED;
3058 }
3059
3060 let prim_info = CommonItemProperties {
3061 clip_rect: clip,
3062 clip_id: space_and_clip.clip_id,
3063 spatial_id: space_and_clip.spatial_id,
3064 flags,
3065 };
3066
3067 let alpha_type = if premultiplied_alpha {
3068 AlphaType::PremultipliedAlpha
3069 } else {
3070 AlphaType::Alpha
3071 };
3072
3073 state
3074 .frame_builder
3075 .dl_builder
3076 .push_image(&prim_info, bounds, image_rendering, alpha_type, key, color);
3077 }
3078
3079 #[no_mangle]
wr_dp_push_repeating_image( state: &mut WrState, bounds: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, stretch_size: LayoutSize, tile_spacing: LayoutSize, image_rendering: ImageRendering, key: WrImageKey, premultiplied_alpha: bool, color: ColorF, )3080 pub extern "C" fn wr_dp_push_repeating_image(
3081 state: &mut WrState,
3082 bounds: LayoutRect,
3083 clip: LayoutRect,
3084 is_backface_visible: bool,
3085 parent: &WrSpaceAndClipChain,
3086 stretch_size: LayoutSize,
3087 tile_spacing: LayoutSize,
3088 image_rendering: ImageRendering,
3089 key: WrImageKey,
3090 premultiplied_alpha: bool,
3091 color: ColorF,
3092 ) {
3093 debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
3094
3095 let space_and_clip = parent.to_webrender(state.pipeline_id);
3096
3097 let prim_info = CommonItemProperties {
3098 clip_rect: clip,
3099 clip_id: space_and_clip.clip_id,
3100 spatial_id: space_and_clip.spatial_id,
3101 flags: prim_flags(is_backface_visible, /* prefer_compositor_surface */ false),
3102 };
3103
3104 let alpha_type = if premultiplied_alpha {
3105 AlphaType::PremultipliedAlpha
3106 } else {
3107 AlphaType::Alpha
3108 };
3109
3110 state.frame_builder.dl_builder.push_repeating_image(
3111 &prim_info,
3112 bounds,
3113 stretch_size,
3114 tile_spacing,
3115 image_rendering,
3116 alpha_type,
3117 key,
3118 color,
3119 );
3120 }
3121
3122 /// Push a 3 planar yuv image.
3123 #[no_mangle]
wr_dp_push_yuv_planar_image( state: &mut WrState, bounds: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, image_key_0: WrImageKey, image_key_1: WrImageKey, image_key_2: WrImageKey, color_depth: WrColorDepth, color_space: WrYuvColorSpace, color_range: WrColorRange, image_rendering: ImageRendering, prefer_compositor_surface: bool, supports_external_compositing: bool, )3124 pub extern "C" fn wr_dp_push_yuv_planar_image(
3125 state: &mut WrState,
3126 bounds: LayoutRect,
3127 clip: LayoutRect,
3128 is_backface_visible: bool,
3129 parent: &WrSpaceAndClipChain,
3130 image_key_0: WrImageKey,
3131 image_key_1: WrImageKey,
3132 image_key_2: WrImageKey,
3133 color_depth: WrColorDepth,
3134 color_space: WrYuvColorSpace,
3135 color_range: WrColorRange,
3136 image_rendering: ImageRendering,
3137 prefer_compositor_surface: bool,
3138 supports_external_compositing: bool,
3139 ) {
3140 debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
3141
3142 let space_and_clip = parent.to_webrender(state.pipeline_id);
3143
3144 let prim_info = CommonItemProperties {
3145 clip_rect: clip,
3146 clip_id: space_and_clip.clip_id,
3147 spatial_id: space_and_clip.spatial_id,
3148 flags: prim_flags2(
3149 is_backface_visible,
3150 prefer_compositor_surface,
3151 supports_external_compositing,
3152 ),
3153 };
3154
3155 state.frame_builder.dl_builder.push_yuv_image(
3156 &prim_info,
3157 bounds,
3158 YuvData::PlanarYCbCr(image_key_0, image_key_1, image_key_2),
3159 color_depth,
3160 color_space,
3161 color_range,
3162 image_rendering,
3163 );
3164 }
3165
3166 /// Push a 2 planar NV12 image.
3167 #[no_mangle]
wr_dp_push_yuv_NV12_image( state: &mut WrState, bounds: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, image_key_0: WrImageKey, image_key_1: WrImageKey, color_depth: WrColorDepth, color_space: WrYuvColorSpace, color_range: WrColorRange, image_rendering: ImageRendering, prefer_compositor_surface: bool, supports_external_compositing: bool, )3168 pub extern "C" fn wr_dp_push_yuv_NV12_image(
3169 state: &mut WrState,
3170 bounds: LayoutRect,
3171 clip: LayoutRect,
3172 is_backface_visible: bool,
3173 parent: &WrSpaceAndClipChain,
3174 image_key_0: WrImageKey,
3175 image_key_1: WrImageKey,
3176 color_depth: WrColorDepth,
3177 color_space: WrYuvColorSpace,
3178 color_range: WrColorRange,
3179 image_rendering: ImageRendering,
3180 prefer_compositor_surface: bool,
3181 supports_external_compositing: bool,
3182 ) {
3183 debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
3184
3185 let space_and_clip = parent.to_webrender(state.pipeline_id);
3186
3187 let prim_info = CommonItemProperties {
3188 clip_rect: clip,
3189 clip_id: space_and_clip.clip_id,
3190 spatial_id: space_and_clip.spatial_id,
3191 flags: prim_flags2(
3192 is_backface_visible,
3193 prefer_compositor_surface,
3194 supports_external_compositing,
3195 ),
3196 };
3197
3198 state.frame_builder.dl_builder.push_yuv_image(
3199 &prim_info,
3200 bounds,
3201 YuvData::NV12(image_key_0, image_key_1),
3202 color_depth,
3203 color_space,
3204 color_range,
3205 image_rendering,
3206 );
3207 }
3208
3209 /// Push a 2 planar P010 image.
3210 #[no_mangle]
wr_dp_push_yuv_P010_image( state: &mut WrState, bounds: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, image_key_0: WrImageKey, image_key_1: WrImageKey, color_depth: WrColorDepth, color_space: WrYuvColorSpace, color_range: WrColorRange, image_rendering: ImageRendering, prefer_compositor_surface: bool, supports_external_compositing: bool, )3211 pub extern "C" fn wr_dp_push_yuv_P010_image(
3212 state: &mut WrState,
3213 bounds: LayoutRect,
3214 clip: LayoutRect,
3215 is_backface_visible: bool,
3216 parent: &WrSpaceAndClipChain,
3217 image_key_0: WrImageKey,
3218 image_key_1: WrImageKey,
3219 color_depth: WrColorDepth,
3220 color_space: WrYuvColorSpace,
3221 color_range: WrColorRange,
3222 image_rendering: ImageRendering,
3223 prefer_compositor_surface: bool,
3224 supports_external_compositing: bool,
3225 ) {
3226 debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
3227
3228 let space_and_clip = parent.to_webrender(state.pipeline_id);
3229
3230 let prim_info = CommonItemProperties {
3231 clip_rect: clip,
3232 clip_id: space_and_clip.clip_id,
3233 spatial_id: space_and_clip.spatial_id,
3234 flags: prim_flags2(
3235 is_backface_visible,
3236 prefer_compositor_surface,
3237 supports_external_compositing,
3238 ),
3239 };
3240
3241 state.frame_builder.dl_builder.push_yuv_image(
3242 &prim_info,
3243 bounds,
3244 YuvData::P010(image_key_0, image_key_1),
3245 color_depth,
3246 color_space,
3247 color_range,
3248 image_rendering,
3249 );
3250 }
3251
3252 /// Push a yuv interleaved image.
3253 #[no_mangle]
wr_dp_push_yuv_interleaved_image( state: &mut WrState, bounds: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, image_key_0: WrImageKey, color_depth: WrColorDepth, color_space: WrYuvColorSpace, color_range: WrColorRange, image_rendering: ImageRendering, prefer_compositor_surface: bool, supports_external_compositing: bool, )3254 pub extern "C" fn wr_dp_push_yuv_interleaved_image(
3255 state: &mut WrState,
3256 bounds: LayoutRect,
3257 clip: LayoutRect,
3258 is_backface_visible: bool,
3259 parent: &WrSpaceAndClipChain,
3260 image_key_0: WrImageKey,
3261 color_depth: WrColorDepth,
3262 color_space: WrYuvColorSpace,
3263 color_range: WrColorRange,
3264 image_rendering: ImageRendering,
3265 prefer_compositor_surface: bool,
3266 supports_external_compositing: bool,
3267 ) {
3268 debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
3269
3270 let space_and_clip = parent.to_webrender(state.pipeline_id);
3271
3272 let prim_info = CommonItemProperties {
3273 clip_rect: clip,
3274 clip_id: space_and_clip.clip_id,
3275 spatial_id: space_and_clip.spatial_id,
3276 flags: prim_flags2(
3277 is_backface_visible,
3278 prefer_compositor_surface,
3279 supports_external_compositing,
3280 ),
3281 };
3282
3283 state.frame_builder.dl_builder.push_yuv_image(
3284 &prim_info,
3285 bounds,
3286 YuvData::InterleavedYCbCr(image_key_0),
3287 color_depth,
3288 color_space,
3289 color_range,
3290 image_rendering,
3291 );
3292 }
3293
3294 #[no_mangle]
wr_dp_push_text( state: &mut WrState, bounds: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, color: ColorF, font_key: WrFontInstanceKey, glyphs: *const GlyphInstance, glyph_count: u32, glyph_options: *const GlyphOptions, )3295 pub extern "C" fn wr_dp_push_text(
3296 state: &mut WrState,
3297 bounds: LayoutRect,
3298 clip: LayoutRect,
3299 is_backface_visible: bool,
3300 parent: &WrSpaceAndClipChain,
3301 color: ColorF,
3302 font_key: WrFontInstanceKey,
3303 glyphs: *const GlyphInstance,
3304 glyph_count: u32,
3305 glyph_options: *const GlyphOptions,
3306 ) {
3307 debug_assert!(unsafe { is_in_main_thread() });
3308
3309 let glyph_slice = unsafe { make_slice(glyphs, glyph_count as usize) };
3310
3311 let space_and_clip = parent.to_webrender(state.pipeline_id);
3312
3313 let prim_info = CommonItemProperties {
3314 clip_rect: clip,
3315 spatial_id: space_and_clip.spatial_id,
3316 clip_id: space_and_clip.clip_id,
3317 flags: prim_flags(is_backface_visible, /* prefer_compositor_surface */ false),
3318 };
3319
3320 state
3321 .frame_builder
3322 .dl_builder
3323 .push_text(&prim_info, bounds, &glyph_slice, font_key, color, unsafe {
3324 glyph_options.as_ref().cloned()
3325 });
3326 }
3327
3328 #[no_mangle]
wr_dp_push_shadow( state: &mut WrState, _bounds: LayoutRect, _clip: LayoutRect, _is_backface_visible: bool, parent: &WrSpaceAndClipChain, shadow: Shadow, should_inflate: bool, )3329 pub extern "C" fn wr_dp_push_shadow(
3330 state: &mut WrState,
3331 _bounds: LayoutRect,
3332 _clip: LayoutRect,
3333 _is_backface_visible: bool,
3334 parent: &WrSpaceAndClipChain,
3335 shadow: Shadow,
3336 should_inflate: bool,
3337 ) {
3338 debug_assert!(unsafe { is_in_main_thread() });
3339
3340 state
3341 .frame_builder
3342 .dl_builder
3343 .push_shadow(&parent.to_webrender(state.pipeline_id), shadow, should_inflate);
3344 }
3345
3346 #[no_mangle]
wr_dp_pop_all_shadows(state: &mut WrState)3347 pub extern "C" fn wr_dp_pop_all_shadows(state: &mut WrState) {
3348 debug_assert!(unsafe { is_in_main_thread() });
3349
3350 state.frame_builder.dl_builder.pop_all_shadows();
3351 }
3352
3353 #[no_mangle]
wr_dp_push_line( state: &mut WrState, clip: &LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, bounds: &LayoutRect, wavy_line_thickness: f32, orientation: LineOrientation, color: &ColorF, style: LineStyle, )3354 pub extern "C" fn wr_dp_push_line(
3355 state: &mut WrState,
3356 clip: &LayoutRect,
3357 is_backface_visible: bool,
3358 parent: &WrSpaceAndClipChain,
3359 bounds: &LayoutRect,
3360 wavy_line_thickness: f32,
3361 orientation: LineOrientation,
3362 color: &ColorF,
3363 style: LineStyle,
3364 ) {
3365 debug_assert!(unsafe { is_in_main_thread() });
3366
3367 let space_and_clip = parent.to_webrender(state.pipeline_id);
3368
3369 let prim_info = CommonItemProperties {
3370 clip_rect: *clip,
3371 clip_id: space_and_clip.clip_id,
3372 spatial_id: space_and_clip.spatial_id,
3373 flags: prim_flags(is_backface_visible, /* prefer_compositor_surface */ false),
3374 };
3375
3376 state
3377 .frame_builder
3378 .dl_builder
3379 .push_line(&prim_info, bounds, wavy_line_thickness, orientation, color, style);
3380 }
3381
3382 #[no_mangle]
wr_dp_push_border( state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, do_aa: AntialiasBorder, widths: LayoutSideOffsets, top: BorderSide, right: BorderSide, bottom: BorderSide, left: BorderSide, radius: BorderRadius, )3383 pub extern "C" fn wr_dp_push_border(
3384 state: &mut WrState,
3385 rect: LayoutRect,
3386 clip: LayoutRect,
3387 is_backface_visible: bool,
3388 parent: &WrSpaceAndClipChain,
3389 do_aa: AntialiasBorder,
3390 widths: LayoutSideOffsets,
3391 top: BorderSide,
3392 right: BorderSide,
3393 bottom: BorderSide,
3394 left: BorderSide,
3395 radius: BorderRadius,
3396 ) {
3397 debug_assert!(unsafe { is_in_main_thread() });
3398
3399 let border_details = BorderDetails::Normal(NormalBorder {
3400 left,
3401 right,
3402 top,
3403 bottom,
3404 radius,
3405 do_aa: do_aa == AntialiasBorder::Yes,
3406 });
3407
3408 let space_and_clip = parent.to_webrender(state.pipeline_id);
3409
3410 let prim_info = CommonItemProperties {
3411 clip_rect: clip,
3412 clip_id: space_and_clip.clip_id,
3413 spatial_id: space_and_clip.spatial_id,
3414 flags: prim_flags(is_backface_visible, /* prefer_compositor_surface */ false),
3415 };
3416
3417 state
3418 .frame_builder
3419 .dl_builder
3420 .push_border(&prim_info, rect, widths, border_details);
3421 }
3422
3423 #[repr(C)]
3424 pub struct WrBorderImage {
3425 widths: LayoutSideOffsets,
3426 image: WrImageKey,
3427 image_rendering: ImageRendering,
3428 width: i32,
3429 height: i32,
3430 fill: bool,
3431 slice: DeviceIntSideOffsets,
3432 outset: LayoutSideOffsets,
3433 repeat_horizontal: RepeatMode,
3434 repeat_vertical: RepeatMode,
3435 }
3436
3437 #[no_mangle]
wr_dp_push_border_image( state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, params: &WrBorderImage, )3438 pub extern "C" fn wr_dp_push_border_image(
3439 state: &mut WrState,
3440 rect: LayoutRect,
3441 clip: LayoutRect,
3442 is_backface_visible: bool,
3443 parent: &WrSpaceAndClipChain,
3444 params: &WrBorderImage,
3445 ) {
3446 debug_assert!(unsafe { is_in_main_thread() });
3447 let border_details = BorderDetails::NinePatch(NinePatchBorder {
3448 source: NinePatchBorderSource::Image(params.image, params.image_rendering),
3449 width: params.width,
3450 height: params.height,
3451 slice: params.slice,
3452 fill: params.fill,
3453 outset: params.outset,
3454 repeat_horizontal: params.repeat_horizontal,
3455 repeat_vertical: params.repeat_vertical,
3456 });
3457 let space_and_clip = parent.to_webrender(state.pipeline_id);
3458
3459 let prim_info = CommonItemProperties {
3460 clip_rect: clip,
3461 clip_id: space_and_clip.clip_id,
3462 spatial_id: space_and_clip.spatial_id,
3463 flags: prim_flags(is_backface_visible, /* prefer_compositor_surface */ false),
3464 };
3465
3466 state
3467 .frame_builder
3468 .dl_builder
3469 .push_border(&prim_info, rect, params.widths, border_details);
3470 }
3471
3472 #[no_mangle]
wr_dp_push_border_gradient( state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, widths: LayoutSideOffsets, width: i32, height: i32, fill: bool, slice: DeviceIntSideOffsets, start_point: LayoutPoint, end_point: LayoutPoint, stops: *const GradientStop, stops_count: usize, extend_mode: ExtendMode, outset: LayoutSideOffsets, )3473 pub extern "C" fn wr_dp_push_border_gradient(
3474 state: &mut WrState,
3475 rect: LayoutRect,
3476 clip: LayoutRect,
3477 is_backface_visible: bool,
3478 parent: &WrSpaceAndClipChain,
3479 widths: LayoutSideOffsets,
3480 width: i32,
3481 height: i32,
3482 fill: bool,
3483 slice: DeviceIntSideOffsets,
3484 start_point: LayoutPoint,
3485 end_point: LayoutPoint,
3486 stops: *const GradientStop,
3487 stops_count: usize,
3488 extend_mode: ExtendMode,
3489 outset: LayoutSideOffsets,
3490 ) {
3491 debug_assert!(unsafe { is_in_main_thread() });
3492
3493 let stops_slice = unsafe { make_slice(stops, stops_count) };
3494 let stops_vector = stops_slice.to_owned();
3495
3496 let gradient = state
3497 .frame_builder
3498 .dl_builder
3499 .create_gradient(start_point, end_point, stops_vector, extend_mode);
3500
3501 let border_details = BorderDetails::NinePatch(NinePatchBorder {
3502 source: NinePatchBorderSource::Gradient(gradient),
3503 width,
3504 height,
3505 slice,
3506 fill,
3507 outset,
3508 repeat_horizontal: RepeatMode::Stretch,
3509 repeat_vertical: RepeatMode::Stretch,
3510 });
3511
3512 let space_and_clip = parent.to_webrender(state.pipeline_id);
3513
3514 let prim_info = CommonItemProperties {
3515 clip_rect: clip,
3516 clip_id: space_and_clip.clip_id,
3517 spatial_id: space_and_clip.spatial_id,
3518 flags: prim_flags(is_backface_visible, /* prefer_compositor_surface */ false),
3519 };
3520
3521 state
3522 .frame_builder
3523 .dl_builder
3524 .push_border(&prim_info, rect, widths, border_details);
3525 }
3526
3527 #[no_mangle]
wr_dp_push_border_radial_gradient( state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, widths: LayoutSideOffsets, fill: bool, center: LayoutPoint, radius: LayoutSize, stops: *const GradientStop, stops_count: usize, extend_mode: ExtendMode, outset: LayoutSideOffsets, )3528 pub extern "C" fn wr_dp_push_border_radial_gradient(
3529 state: &mut WrState,
3530 rect: LayoutRect,
3531 clip: LayoutRect,
3532 is_backface_visible: bool,
3533 parent: &WrSpaceAndClipChain,
3534 widths: LayoutSideOffsets,
3535 fill: bool,
3536 center: LayoutPoint,
3537 radius: LayoutSize,
3538 stops: *const GradientStop,
3539 stops_count: usize,
3540 extend_mode: ExtendMode,
3541 outset: LayoutSideOffsets,
3542 ) {
3543 debug_assert!(unsafe { is_in_main_thread() });
3544
3545 let stops_slice = unsafe { make_slice(stops, stops_count) };
3546 let stops_vector = stops_slice.to_owned();
3547
3548 let slice = SideOffsets2D::new(
3549 widths.top as i32,
3550 widths.right as i32,
3551 widths.bottom as i32,
3552 widths.left as i32,
3553 );
3554
3555 let gradient = state
3556 .frame_builder
3557 .dl_builder
3558 .create_radial_gradient(center, radius, stops_vector, extend_mode);
3559
3560 let border_details = BorderDetails::NinePatch(NinePatchBorder {
3561 source: NinePatchBorderSource::RadialGradient(gradient),
3562 width: rect.width() as i32,
3563 height: rect.height() as i32,
3564 slice,
3565 fill,
3566 outset,
3567 repeat_horizontal: RepeatMode::Stretch,
3568 repeat_vertical: RepeatMode::Stretch,
3569 });
3570
3571 let space_and_clip = parent.to_webrender(state.pipeline_id);
3572
3573 let prim_info = CommonItemProperties {
3574 clip_rect: clip,
3575 clip_id: space_and_clip.clip_id,
3576 spatial_id: space_and_clip.spatial_id,
3577 flags: prim_flags(is_backface_visible, /* prefer_compositor_surface */ false),
3578 };
3579
3580 state
3581 .frame_builder
3582 .dl_builder
3583 .push_border(&prim_info, rect, widths, border_details);
3584 }
3585
3586 #[no_mangle]
wr_dp_push_border_conic_gradient( state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, widths: LayoutSideOffsets, fill: bool, center: LayoutPoint, angle: f32, stops: *const GradientStop, stops_count: usize, extend_mode: ExtendMode, outset: LayoutSideOffsets, )3587 pub extern "C" fn wr_dp_push_border_conic_gradient(
3588 state: &mut WrState,
3589 rect: LayoutRect,
3590 clip: LayoutRect,
3591 is_backface_visible: bool,
3592 parent: &WrSpaceAndClipChain,
3593 widths: LayoutSideOffsets,
3594 fill: bool,
3595 center: LayoutPoint,
3596 angle: f32,
3597 stops: *const GradientStop,
3598 stops_count: usize,
3599 extend_mode: ExtendMode,
3600 outset: LayoutSideOffsets,
3601 ) {
3602 debug_assert!(unsafe { is_in_main_thread() });
3603
3604 let stops_slice = unsafe { make_slice(stops, stops_count) };
3605 let stops_vector = stops_slice.to_owned();
3606
3607 let slice = SideOffsets2D::new(
3608 widths.top as i32,
3609 widths.right as i32,
3610 widths.bottom as i32,
3611 widths.left as i32,
3612 );
3613
3614 let gradient = state
3615 .frame_builder
3616 .dl_builder
3617 .create_conic_gradient(center, angle, stops_vector, extend_mode);
3618
3619 let border_details = BorderDetails::NinePatch(NinePatchBorder {
3620 source: NinePatchBorderSource::ConicGradient(gradient),
3621 width: rect.width() as i32,
3622 height: rect.height() as i32,
3623 slice,
3624 fill,
3625 outset,
3626 repeat_horizontal: RepeatMode::Stretch,
3627 repeat_vertical: RepeatMode::Stretch,
3628 });
3629
3630 let space_and_clip = parent.to_webrender(state.pipeline_id);
3631
3632 let prim_info = CommonItemProperties {
3633 clip_rect: clip,
3634 clip_id: space_and_clip.clip_id,
3635 spatial_id: space_and_clip.spatial_id,
3636 flags: prim_flags(is_backface_visible, /* prefer_compositor_surface */ false),
3637 };
3638
3639 state
3640 .frame_builder
3641 .dl_builder
3642 .push_border(&prim_info, rect, widths, border_details);
3643 }
3644
3645 #[no_mangle]
wr_dp_push_linear_gradient( state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, start_point: LayoutPoint, end_point: LayoutPoint, stops: *const GradientStop, stops_count: usize, extend_mode: ExtendMode, tile_size: LayoutSize, tile_spacing: LayoutSize, )3646 pub extern "C" fn wr_dp_push_linear_gradient(
3647 state: &mut WrState,
3648 rect: LayoutRect,
3649 clip: LayoutRect,
3650 is_backface_visible: bool,
3651 parent: &WrSpaceAndClipChain,
3652 start_point: LayoutPoint,
3653 end_point: LayoutPoint,
3654 stops: *const GradientStop,
3655 stops_count: usize,
3656 extend_mode: ExtendMode,
3657 tile_size: LayoutSize,
3658 tile_spacing: LayoutSize,
3659 ) {
3660 debug_assert!(unsafe { is_in_main_thread() });
3661
3662 let stops_slice = unsafe { make_slice(stops, stops_count) };
3663 let stops_vector = stops_slice.to_owned();
3664
3665 let gradient = state
3666 .frame_builder
3667 .dl_builder
3668 .create_gradient(start_point, end_point, stops_vector, extend_mode);
3669
3670 let space_and_clip = parent.to_webrender(state.pipeline_id);
3671
3672 let prim_info = CommonItemProperties {
3673 clip_rect: clip,
3674 clip_id: space_and_clip.clip_id,
3675 spatial_id: space_and_clip.spatial_id,
3676 flags: prim_flags(is_backface_visible, /* prefer_compositor_surface */ false),
3677 };
3678
3679 state
3680 .frame_builder
3681 .dl_builder
3682 .push_gradient(&prim_info, rect, gradient, tile_size, tile_spacing);
3683 }
3684
3685 #[no_mangle]
wr_dp_push_radial_gradient( state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, center: LayoutPoint, radius: LayoutSize, stops: *const GradientStop, stops_count: usize, extend_mode: ExtendMode, tile_size: LayoutSize, tile_spacing: LayoutSize, )3686 pub extern "C" fn wr_dp_push_radial_gradient(
3687 state: &mut WrState,
3688 rect: LayoutRect,
3689 clip: LayoutRect,
3690 is_backface_visible: bool,
3691 parent: &WrSpaceAndClipChain,
3692 center: LayoutPoint,
3693 radius: LayoutSize,
3694 stops: *const GradientStop,
3695 stops_count: usize,
3696 extend_mode: ExtendMode,
3697 tile_size: LayoutSize,
3698 tile_spacing: LayoutSize,
3699 ) {
3700 debug_assert!(unsafe { is_in_main_thread() });
3701
3702 let stops_slice = unsafe { make_slice(stops, stops_count) };
3703 let stops_vector = stops_slice.to_owned();
3704
3705 let gradient = state
3706 .frame_builder
3707 .dl_builder
3708 .create_radial_gradient(center, radius, stops_vector, extend_mode);
3709
3710 let space_and_clip = parent.to_webrender(state.pipeline_id);
3711
3712 let prim_info = CommonItemProperties {
3713 clip_rect: clip,
3714 clip_id: space_and_clip.clip_id,
3715 spatial_id: space_and_clip.spatial_id,
3716 flags: prim_flags(is_backface_visible, /* prefer_compositor_surface */ false),
3717 };
3718
3719 state
3720 .frame_builder
3721 .dl_builder
3722 .push_radial_gradient(&prim_info, rect, gradient, tile_size, tile_spacing);
3723 }
3724
3725 #[no_mangle]
wr_dp_push_conic_gradient( state: &mut WrState, rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, center: LayoutPoint, angle: f32, stops: *const GradientStop, stops_count: usize, extend_mode: ExtendMode, tile_size: LayoutSize, tile_spacing: LayoutSize, )3726 pub extern "C" fn wr_dp_push_conic_gradient(
3727 state: &mut WrState,
3728 rect: LayoutRect,
3729 clip: LayoutRect,
3730 is_backface_visible: bool,
3731 parent: &WrSpaceAndClipChain,
3732 center: LayoutPoint,
3733 angle: f32,
3734 stops: *const GradientStop,
3735 stops_count: usize,
3736 extend_mode: ExtendMode,
3737 tile_size: LayoutSize,
3738 tile_spacing: LayoutSize,
3739 ) {
3740 debug_assert!(unsafe { is_in_main_thread() });
3741
3742 let stops_slice = unsafe { make_slice(stops, stops_count) };
3743 let stops_vector = stops_slice.to_owned();
3744
3745 let gradient = state
3746 .frame_builder
3747 .dl_builder
3748 .create_conic_gradient(center, angle, stops_vector, extend_mode);
3749
3750 let space_and_clip = parent.to_webrender(state.pipeline_id);
3751
3752 let prim_info = CommonItemProperties {
3753 clip_rect: clip,
3754 clip_id: space_and_clip.clip_id,
3755 spatial_id: space_and_clip.spatial_id,
3756 flags: prim_flags(is_backface_visible, /* prefer_compositor_surface */ false),
3757 };
3758
3759 state
3760 .frame_builder
3761 .dl_builder
3762 .push_conic_gradient(&prim_info, rect, gradient, tile_size, tile_spacing);
3763 }
3764
3765 #[no_mangle]
wr_dp_push_box_shadow( state: &mut WrState, _rect: LayoutRect, clip: LayoutRect, is_backface_visible: bool, parent: &WrSpaceAndClipChain, box_bounds: LayoutRect, offset: LayoutVector2D, color: ColorF, blur_radius: f32, spread_radius: f32, border_radius: BorderRadius, clip_mode: BoxShadowClipMode, )3766 pub extern "C" fn wr_dp_push_box_shadow(
3767 state: &mut WrState,
3768 _rect: LayoutRect,
3769 clip: LayoutRect,
3770 is_backface_visible: bool,
3771 parent: &WrSpaceAndClipChain,
3772 box_bounds: LayoutRect,
3773 offset: LayoutVector2D,
3774 color: ColorF,
3775 blur_radius: f32,
3776 spread_radius: f32,
3777 border_radius: BorderRadius,
3778 clip_mode: BoxShadowClipMode,
3779 ) {
3780 debug_assert!(unsafe { is_in_main_thread() });
3781
3782 let space_and_clip = parent.to_webrender(state.pipeline_id);
3783
3784 let prim_info = CommonItemProperties {
3785 clip_rect: clip,
3786 clip_id: space_and_clip.clip_id,
3787 spatial_id: space_and_clip.spatial_id,
3788 flags: prim_flags(is_backface_visible, /* prefer_compositor_surface */ false),
3789 };
3790
3791 state.frame_builder.dl_builder.push_box_shadow(
3792 &prim_info,
3793 box_bounds,
3794 offset,
3795 color,
3796 blur_radius,
3797 spread_radius,
3798 border_radius,
3799 clip_mode,
3800 );
3801 }
3802
3803 #[no_mangle]
wr_dp_start_item_group(state: &mut WrState)3804 pub extern "C" fn wr_dp_start_item_group(state: &mut WrState) {
3805 state.frame_builder.dl_builder.start_item_group();
3806 }
3807
3808 #[no_mangle]
wr_dp_cancel_item_group(state: &mut WrState, discard: bool)3809 pub extern "C" fn wr_dp_cancel_item_group(state: &mut WrState, discard: bool) {
3810 state.frame_builder.dl_builder.cancel_item_group(discard);
3811 }
3812
3813 #[no_mangle]
wr_dp_finish_item_group(state: &mut WrState, key: ItemKey) -> bool3814 pub extern "C" fn wr_dp_finish_item_group(state: &mut WrState, key: ItemKey) -> bool {
3815 state.frame_builder.dl_builder.finish_item_group(key)
3816 }
3817
3818 #[no_mangle]
wr_dp_push_reuse_items(state: &mut WrState, key: ItemKey)3819 pub extern "C" fn wr_dp_push_reuse_items(state: &mut WrState, key: ItemKey) {
3820 state.frame_builder.dl_builder.push_reuse_items(key);
3821 }
3822
3823 #[no_mangle]
wr_dp_set_cache_size(state: &mut WrState, cache_size: usize)3824 pub extern "C" fn wr_dp_set_cache_size(state: &mut WrState, cache_size: usize) {
3825 state.frame_builder.dl_builder.set_cache_size(cache_size);
3826 }
3827
3828 #[no_mangle]
wr_dump_display_list( state: &mut WrState, indent: usize, start: *const usize, end: *const usize, ) -> usize3829 pub extern "C" fn wr_dump_display_list(
3830 state: &mut WrState,
3831 indent: usize,
3832 start: *const usize,
3833 end: *const usize,
3834 ) -> usize {
3835 let start = unsafe { start.as_ref().cloned() };
3836 let end = unsafe { end.as_ref().cloned() };
3837 let range = Range { start, end };
3838 let mut sink = Cursor::new(Vec::new());
3839 let index = state
3840 .frame_builder
3841 .dl_builder
3842 .emit_display_list(indent, range, &mut sink);
3843
3844 // For Android, dump to logcat instead of stderr. This is the same as
3845 // what printf_stderr does on the C++ side.
3846
3847 #[cfg(target_os = "android")]
3848 unsafe {
3849 let gecko = CString::new("Gecko").unwrap();
3850 let sink = CString::new(sink.into_inner()).unwrap();
3851 __android_log_write(4 /* info */, gecko.as_ptr(), sink.as_ptr());
3852 }
3853
3854 #[cfg(not(target_os = "android"))]
3855 eprint!("{}", String::from_utf8(sink.into_inner()).unwrap());
3856
3857 index
3858 }
3859
3860 #[no_mangle]
wr_dump_serialized_display_list(state: &mut WrState)3861 pub extern "C" fn wr_dump_serialized_display_list(state: &mut WrState) {
3862 state.frame_builder.dl_builder.dump_serialized_display_list();
3863 }
3864
3865 #[no_mangle]
wr_api_begin_builder(state: &mut WrState)3866 pub unsafe extern "C" fn wr_api_begin_builder(state: &mut WrState) {
3867 state.frame_builder.dl_builder.begin();
3868 }
3869
3870 #[no_mangle]
wr_api_end_builder( state: &mut WrState, dl_descriptor: &mut BuiltDisplayListDescriptor, dl_items_data: &mut WrVecU8, dl_cache_data: &mut WrVecU8, dl_spatial_tree: &mut WrVecU8, )3871 pub unsafe extern "C" fn wr_api_end_builder(
3872 state: &mut WrState,
3873 dl_descriptor: &mut BuiltDisplayListDescriptor,
3874 dl_items_data: &mut WrVecU8,
3875 dl_cache_data: &mut WrVecU8,
3876 dl_spatial_tree: &mut WrVecU8,
3877 ) {
3878 let (_, dl) = state.frame_builder.dl_builder.end();
3879 let (payload, descriptor) = dl.into_data();
3880 *dl_items_data = WrVecU8::from_vec(payload.items_data);
3881 *dl_cache_data = WrVecU8::from_vec(payload.cache_data);
3882 *dl_spatial_tree = WrVecU8::from_vec(payload.spatial_tree);
3883 *dl_descriptor = descriptor;
3884 }
3885
3886 #[repr(C)]
3887 pub struct HitResult {
3888 pipeline_id: WrPipelineId,
3889 scroll_id: u64,
3890 hit_info: u16,
3891 }
3892
3893 #[no_mangle]
wr_api_hit_test(dh: &mut DocumentHandle, point: WorldPoint, out_results: &mut ThinVec<HitResult>)3894 pub extern "C" fn wr_api_hit_test(dh: &mut DocumentHandle, point: WorldPoint, out_results: &mut ThinVec<HitResult>) {
3895 let result = dh.ensure_hit_tester().hit_test(point);
3896 for item in &result.items {
3897 out_results.push(HitResult {
3898 pipeline_id: item.pipeline,
3899 scroll_id: item.tag.0,
3900 hit_info: item.tag.1,
3901 });
3902 }
3903 }
3904
3905 pub type VecU8 = Vec<u8>;
3906 pub type ArcVecU8 = Arc<VecU8>;
3907
3908 #[no_mangle]
wr_add_ref_arc(arc: &ArcVecU8) -> *const VecU83909 pub extern "C" fn wr_add_ref_arc(arc: &ArcVecU8) -> *const VecU8 {
3910 Arc::into_raw(arc.clone())
3911 }
3912
3913 #[no_mangle]
wr_dec_ref_arc(arc: *const VecU8)3914 pub unsafe extern "C" fn wr_dec_ref_arc(arc: *const VecU8) {
3915 Arc::from_raw(arc);
3916 }
3917
3918 // TODO: nical
3919 // Update for the new blob image interface changes.
3920 //
3921 extern "C" {
3922 // TODO: figure out the API for tiled blob images.
wr_moz2d_render_cb( blob: ByteSlice, format: ImageFormat, render_rect: &LayoutIntRect, visible_rect: &DeviceIntRect, tile_size: u16, tile_offset: &TileOffset, dirty_rect: Option<&LayoutIntRect>, output: MutByteSlice, ) -> bool3923 pub fn wr_moz2d_render_cb(
3924 blob: ByteSlice,
3925 format: ImageFormat,
3926 render_rect: &LayoutIntRect,
3927 visible_rect: &DeviceIntRect,
3928 tile_size: u16,
3929 tile_offset: &TileOffset,
3930 dirty_rect: Option<&LayoutIntRect>,
3931 output: MutByteSlice,
3932 ) -> bool;
3933 }
3934
3935 #[no_mangle]
wr_root_scroll_node_id() -> WrSpatialId3936 pub extern "C" fn wr_root_scroll_node_id() -> WrSpatialId {
3937 // The PipelineId doesn't matter here, since we just want the numeric part of the id
3938 // produced for any given root reference frame.
3939 WrSpatialId {
3940 id: SpatialId::root_scroll_node(PipelineId(0, 0)).0,
3941 }
3942 }
3943
3944 #[no_mangle]
wr_root_clip_id() -> WrClipId3945 pub extern "C" fn wr_root_clip_id() -> WrClipId {
3946 // The PipelineId doesn't matter here, since we just want the numeric part of the id
3947 // produced for any given root reference frame.
3948 WrClipId::from_webrender(ClipId::root(PipelineId(0, 0)))
3949 }
3950
3951 #[repr(C)]
3952 #[derive(Clone, Copy)]
3953 pub struct WrClipId {
3954 id: usize,
3955 }
3956
3957 impl WrClipId {
to_webrender(&self, pipeline_id: WrPipelineId) -> ClipId3958 fn to_webrender(&self, pipeline_id: WrPipelineId) -> ClipId {
3959 ClipId::Clip(self.id, pipeline_id)
3960 }
3961
from_webrender(clip_id: ClipId) -> Self3962 fn from_webrender(clip_id: ClipId) -> Self {
3963 match clip_id {
3964 ClipId::Clip(id, _) => WrClipId { id },
3965 ClipId::ClipChain(_) => panic!("Unexpected clip chain"),
3966 }
3967 }
3968 }
3969
3970 #[repr(C)]
3971 #[derive(Clone, Copy)]
3972 pub struct WrSpatialId {
3973 id: usize,
3974 }
3975
3976 impl WrSpatialId {
to_webrender(&self, pipeline_id: WrPipelineId) -> SpatialId3977 fn to_webrender(&self, pipeline_id: WrPipelineId) -> SpatialId {
3978 SpatialId::new(self.id, pipeline_id)
3979 }
3980
from_webrender(id: SpatialId) -> Self3981 fn from_webrender(id: SpatialId) -> Self {
3982 WrSpatialId { id: id.0 }
3983 }
3984 }
3985
3986 #[no_mangle]
wr_device_delete(device: *mut Device)3987 pub unsafe extern "C" fn wr_device_delete(device: *mut Device) {
3988 Box::from_raw(device);
3989 }
3990
3991 // Call MakeCurrent before this.
3992 #[no_mangle]
wr_shaders_new( gl_context: *mut c_void, program_cache: Option<&mut WrProgramCache>, precache_shaders: bool, ) -> *mut WrShaders3993 pub extern "C" fn wr_shaders_new(
3994 gl_context: *mut c_void,
3995 program_cache: Option<&mut WrProgramCache>,
3996 precache_shaders: bool,
3997 ) -> *mut WrShaders {
3998 let mut device = wr_device_new(gl_context, program_cache);
3999
4000 let precache_flags = if precache_shaders || env_var_to_bool("MOZ_WR_PRECACHE_SHADERS") {
4001 ShaderPrecacheFlags::FULL_COMPILE
4002 } else {
4003 ShaderPrecacheFlags::ASYNC_COMPILE
4004 };
4005
4006 let opts = RendererOptions {
4007 precache_flags,
4008 ..Default::default()
4009 };
4010
4011 let gl_type = device.gl().get_type();
4012 device.begin_frame();
4013
4014 let shaders = Rc::new(RefCell::new(match Shaders::new(&mut device, gl_type, &opts) {
4015 Ok(shaders) => shaders,
4016 Err(e) => {
4017 warn!(" Failed to create a Shaders: {:?}", e);
4018 let msg = CString::new(format!("wr_shaders_new: {:?}", e)).unwrap();
4019 unsafe {
4020 gfx_critical_note(msg.as_ptr());
4021 }
4022 return ptr::null_mut();
4023 },
4024 }));
4025
4026 let shaders = WrShaders(shaders);
4027
4028 device.end_frame();
4029 Box::into_raw(Box::new(shaders))
4030 }
4031
4032 #[no_mangle]
wr_shaders_delete(shaders: *mut WrShaders, gl_context: *mut c_void)4033 pub unsafe extern "C" fn wr_shaders_delete(shaders: *mut WrShaders, gl_context: *mut c_void) {
4034 let mut device = wr_device_new(gl_context, None);
4035 let shaders = Box::from_raw(shaders);
4036 if let Ok(shaders) = Rc::try_unwrap(shaders.0) {
4037 shaders.into_inner().deinit(&mut device);
4038 }
4039 // let shaders go out of scope and get dropped
4040 }
4041
4042 #[no_mangle]
wr_program_cache_report_memory( cache: *const WrProgramCache, size_of_op: VoidPtrToSizeFn, ) -> usize4043 pub unsafe extern "C" fn wr_program_cache_report_memory(
4044 cache: *const WrProgramCache,
4045 size_of_op: VoidPtrToSizeFn,
4046 ) -> usize {
4047 (*cache).program_cache.report_memory(size_of_op)
4048 }
4049