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