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