Bug 1731136 Part 1: Extend compositor to manage backdrop surfaces. r=gw
[gecko.git] / gfx / webrender_bindings / src / bindings.rs
blob45ae70291f481642f6797371d22294d812f63806
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/. */
5 #![allow(clippy::missing_safety_doc)]
6 #![allow(clippy::not_unsafe_ptr_arg_deref)]
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;
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,
47 use wr_malloc_size_of::MallocSizeOfOps;
49 extern "C" {
50     #[cfg(target_os = "android")]
51     fn __android_log_write(prio: c_int, tag: *const c_char, text: *const c_char) -> c_int;
54 /// The unique id for WR resource identification.
55 static NEXT_NAMESPACE_ID: AtomicUsize = AtomicUsize::new(1);
57 /// Special value handled in this wrapper layer to signify a redundant clip chain.
58 pub const ROOT_CLIP_CHAIN: u64 = !0;
60 fn next_namespace_id() -> IdNamespace {
61     IdNamespace(NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed) as u32)
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,
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,
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;
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;
109 #[inline]
110 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     }
118 #[repr(C)]
119 pub struct WrSpaceAndClipChain {
120     space: WrSpatialId,
121     clip_chain: u64,
124 impl WrSpaceAndClipChain {
125     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     }
134 #[repr(C)]
135 pub enum WrStackingContextClip {
136     None,
137     ClipId(WrClipId),
138     ClipChain(u64),
141 impl WrStackingContextClip {
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     }
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     }
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     }
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>>,
178 impl DocumentHandle {
179     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         };
194         DocumentHandle {
195             api,
196             document_id: doc,
197             hit_tester_request,
198             hit_tester,
199         }
200     }
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     }
211 #[repr(C)]
212 pub struct WrVecU8 {
213     data: *mut u8,
214     length: usize,
215     capacity: usize,
218 impl WrVecU8 {
219     fn into_vec(self) -> Vec<u8> {
220         unsafe { Vec::from_raw_parts(self.data, self.length, self.capacity) }
221     }
223     // Equivalent to `into_vec` but clears self instead of consuming the value.
224     fn flush_into_vec(&mut self) -> Vec<u8> {
225         self.convert_into_vec::<u8>()
226     }
228     // Like flush_into_vec, but also does an unsafe conversion to the desired type.
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     }
243     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     }
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     }
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     }
266 #[no_mangle]
267 pub extern "C" fn wr_vec_u8_push_bytes(v: &mut WrVecU8, bytes: ByteSlice) {
268     v.push_bytes(bytes.as_slice());
271 #[no_mangle]
272 pub extern "C" fn wr_vec_u8_reserve(v: &mut WrVecU8, len: usize) {
273     v.reserve(len);
276 #[no_mangle]
277 pub extern "C" fn wr_vec_u8_free(v: WrVecU8) {
278     v.into_vec();
281 #[repr(C)]
282 pub struct ByteSlice<'a> {
283     buffer: *const u8,
284     len: usize,
285     _phantom: PhantomData<&'a ()>,
288 impl<'a> 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     }
297     pub fn as_slice(&self) -> &'a [u8] {
298         unsafe { make_slice(self.buffer, self.len) }
299     }
302 #[repr(C)]
303 pub struct MutByteSlice<'a> {
304     buffer: *mut u8,
305     len: usize,
306     _phantom: PhantomData<&'a ()>,
309 impl<'a> 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     }
319     pub fn as_mut_slice(&mut self) -> &'a mut [u8] {
320         unsafe { make_slice_mut(self.buffer, self.len) }
321     }
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,
336 impl<'a> From<&'a WrImageDescriptor> for ImageDescriptor {
337     fn from(desc: &'a WrImageDescriptor) -> ImageDescriptor {
338         let mut flags = ImageDescriptorFlags::empty();
340         if desc.opacity == OpacityType::Opaque {
341             flags |= ImageDescriptorFlags::IS_OPAQUE;
342         }
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     }
354 #[repr(u32)]
355 #[allow(dead_code)]
356 enum WrExternalImageType {
357     RawData,
358     NativeTexture,
359     Invalid,
362 #[repr(C)]
363 struct WrExternalImage {
364     image_type: WrExternalImageType,
366     // external texture handle
367     handle: u32,
368     // external texture coordinate
369     u0: f32,
370     v0: f32,
371     u1: f32,
372     v1: f32,
374     // external image buffer
375     buff: *const u8,
376     size: usize,
379 extern "C" {
380     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;
386     fn wr_renderer_unlock_external_image(renderer: *mut c_void, external_image_id: ExternalImageId, channel_index: u8);
389 #[repr(C)]
390 #[derive(Copy, Clone, Debug)]
391 pub struct WrExternalImageHandler {
392     external_image_obj: *mut c_void,
395 impl ExternalImageHandler for WrExternalImageHandler {
396     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     }
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     }
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,
435 #[repr(u32)]
436 #[derive(Debug)]
437 pub enum WrAnimationType {
438     Transform = 0,
439     Opacity = 1,
440     BackgroundColor = 2,
443 #[repr(C)]
444 pub struct WrAnimationProperty {
445     effect_type: WrAnimationType,
446     id: u64,
447     key: SpatialTreeItemKey,
450 /// cbindgen:derive-eq=false
451 #[repr(C)]
452 #[derive(Debug)]
453 pub struct WrAnimationPropertyValue<T> {
454     pub id: u64,
455     pub value: T,
458 pub type WrTransformProperty = WrAnimationPropertyValue<LayoutTransform>;
459 pub type WrOpacityProperty = WrAnimationPropertyValue<f32>;
460 pub type WrColorProperty = WrAnimationPropertyValue<ColorF>;
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);
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,
478 #[repr(C)]
479 pub struct WrTransformInfo {
480     pub transform: LayoutTransform,
481     pub key: SpatialTreeItemKey,
484 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     }
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 _
494 #[repr(C)]
495 pub enum TelemetryProbe {
496     SceneBuildTime = 0,
497     SceneSwapTime = 1,
498     FrameBuildTime = 2,
501 extern "C" {
502     fn is_in_compositor_thread() -> bool;
503     fn is_in_render_thread() -> bool;
504     fn is_in_main_thread() -> bool;
505     fn is_glcontext_gles(glcontext_ptr: *mut c_void) -> bool;
506     fn is_glcontext_angle(glcontext_ptr: *mut c_void) -> bool;
507     fn gfx_wr_resource_path_override() -> *const c_char;
508     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)]
513     fn gfx_critical_error(msg: *const c_char);
514     fn gfx_critical_note(msg: *const c_char);
515     fn gfx_wr_set_crash_annotation(annotation: CrashAnnotation, value: *const c_char);
516     fn gfx_wr_clear_crash_annotation(annotation: CrashAnnotation);
519 struct CppNotifier {
520     window_id: WrWindowId,
523 unsafe impl Send for CppNotifier {}
525 extern "C" {
526     fn wr_notifier_wake_up(window_id: WrWindowId, composite_needed: bool);
527     fn wr_notifier_new_frame_ready(window_id: WrWindowId);
528     fn wr_notifier_nop_frame_done(window_id: WrWindowId);
529     fn wr_notifier_external_event(window_id: WrWindowId, raw_event: usize);
530     fn wr_schedule_render(window_id: WrWindowId, reasons: RenderReasons);
531     // NOTE: This moves away from pipeline_info.
532     fn wr_finished_scene_build(window_id: WrWindowId, pipeline_info: &mut WrPipelineInfo);
534     fn wr_transaction_notification_notified(handler: usize, when: Checkpoint);
537 impl RenderNotifier for CppNotifier {
538     fn clone(&self) -> Box<dyn RenderNotifier> {
539         Box::new(CppNotifier {
540             window_id: self.window_id,
541         })
542     }
544     fn wake_up(&self, composite_needed: bool) {
545         unsafe {
546             wr_notifier_wake_up(self.window_id, composite_needed);
547         }
548     }
550     fn new_frame_ready(&self, _: DocumentId, _scrolled: bool, composite_needed: bool) {
551         unsafe {
552             if composite_needed {
553                 wr_notifier_new_frame_ready(self.window_id);
554             } else {
555                 wr_notifier_nop_frame_done(self.window_id);
556             }
557         }
558     }
560     fn external_event(&self, event: ExternalEvent) {
561         unsafe {
562             wr_notifier_external_event(self.window_id, event.unwrap());
563         }
564     }
567 struct MozCrashAnnotator;
569 unsafe impl Send for MozCrashAnnotator {}
571 impl CrashAnnotator for MozCrashAnnotator {
572     fn set(&self, annotation: CrashAnnotation, value: &std::ffi::CStr) {
573         unsafe {
574             gfx_wr_set_crash_annotation(annotation, value.as_ptr());
575         }
576     }
578     fn clear(&self, annotation: CrashAnnotation) {
579         unsafe {
580             gfx_wr_clear_crash_annotation(annotation);
581         }
582     }
584     fn box_clone(&self) -> Box<dyn CrashAnnotator> {
585         Box::new(MozCrashAnnotator)
586     }
589 #[no_mangle]
590 pub extern "C" fn wr_renderer_set_clear_color(renderer: &mut Renderer, color: ColorF) {
591     renderer.set_clear_color(color);
594 #[no_mangle]
595 pub extern "C" fn wr_renderer_set_external_image_handler(
596     renderer: &mut Renderer,
597     external_image_handler: &mut WrExternalImageHandler,
598 ) {
599     renderer.set_external_image_handler(Box::new(*external_image_handler));
602 #[no_mangle]
603 pub extern "C" fn wr_renderer_update(renderer: &mut Renderer) {
604     renderer.update();
607 #[no_mangle]
608 pub extern "C" fn wr_renderer_render(
609     renderer: &mut Renderer,
610     width: i32,
611     height: i32,
612     buffer_age: usize,
613     out_stats: &mut RendererStats,
614     out_dirty_rects: &mut ThinVec<DeviceIntRect>,
615 ) -> bool {
616     match renderer.render(DeviceIntSize::new(width, height), buffer_age) {
617         Ok(results) => {
618             *out_stats = results.stats;
619             out_dirty_rects.extend(results.dirty_rects);
620             true
621         },
622         Err(errors) => {
623             for e in errors {
624                 warn!(" Failed to render: {:?}", e);
625                 let msg = CString::new(format!("wr_renderer_render: {:?}", e)).unwrap();
626                 unsafe {
627                     gfx_critical_note(msg.as_ptr());
628                 }
629             }
630             false
631         },
632     }
635 #[no_mangle]
636 pub extern "C" fn wr_renderer_force_redraw(renderer: &mut Renderer) {
637     renderer.force_redraw();
640 #[no_mangle]
641 pub extern "C" fn wr_renderer_record_frame(
642     renderer: &mut Renderer,
643     image_format: ImageFormat,
644     out_handle: &mut RecordedFrameHandle,
645     out_width: &mut i32,
646     out_height: &mut i32,
647 ) -> bool {
648     if let Some((handle, size)) = renderer.record_frame(image_format) {
649         *out_handle = handle;
650         *out_width = size.width;
651         *out_height = size.height;
653         true
654     } else {
655         false
656     }
659 #[no_mangle]
660 pub extern "C" fn wr_renderer_map_recorded_frame(
661     renderer: &mut Renderer,
662     handle: RecordedFrameHandle,
663     dst_buffer: *mut u8,
664     dst_buffer_len: usize,
665     dst_stride: usize,
666 ) -> bool {
667     renderer.map_recorded_frame(
668         handle,
669         unsafe { make_slice_mut(dst_buffer, dst_buffer_len) },
670         dst_stride,
671     )
674 #[no_mangle]
675 pub extern "C" fn wr_renderer_release_composition_recorder_structures(renderer: &mut Renderer) {
676     renderer.release_composition_recorder_structures();
679 #[no_mangle]
680 pub extern "C" fn wr_renderer_get_screenshot_async(
681     renderer: &mut Renderer,
682     window_x: i32,
683     window_y: i32,
684     window_width: i32,
685     window_height: i32,
686     buffer_width: i32,
687     buffer_height: i32,
688     image_format: ImageFormat,
689     screenshot_width: *mut i32,
690     screenshot_height: *mut i32,
691 ) -> AsyncScreenshotHandle {
692     assert!(!screenshot_width.is_null());
693     assert!(!screenshot_height.is_null());
695     let (handle, size) = renderer.get_screenshot_async(
696         DeviceIntRect::from_origin_and_size(
697             DeviceIntPoint::new(window_x, window_y),
698             DeviceIntSize::new(window_width, window_height),
699         ),
700         DeviceIntSize::new(buffer_width, buffer_height),
701         image_format,
702     );
704     unsafe {
705         *screenshot_width = size.width;
706         *screenshot_height = size.height;
707     }
709     handle
712 #[no_mangle]
713 pub extern "C" fn wr_renderer_map_and_recycle_screenshot(
714     renderer: &mut Renderer,
715     handle: AsyncScreenshotHandle,
716     dst_buffer: *mut u8,
717     dst_buffer_len: usize,
718     dst_stride: usize,
719 ) -> bool {
720     renderer.map_and_recycle_screenshot(
721         handle,
722         unsafe { make_slice_mut(dst_buffer, dst_buffer_len) },
723         dst_stride,
724     )
727 #[no_mangle]
728 pub extern "C" fn wr_renderer_release_profiler_structures(renderer: &mut Renderer) {
729     renderer.release_profiler_structures();
732 // Call wr_renderer_render() before calling this function.
733 #[no_mangle]
734 pub unsafe extern "C" fn wr_renderer_readback(
735     renderer: &mut Renderer,
736     width: i32,
737     height: i32,
738     format: ImageFormat,
739     dst_buffer: *mut u8,
740     buffer_size: usize,
741 ) {
742     assert!(is_in_render_thread());
744     let mut slice = make_slice_mut(dst_buffer, buffer_size);
745     renderer.read_pixels_into(FramebufferIntSize::new(width, height).into(), format, &mut slice);
748 #[no_mangle]
749 pub unsafe extern "C" fn wr_renderer_set_profiler_ui(renderer: &mut Renderer, ui_str: *const u8, ui_str_len: usize) {
750     let slice = std::slice::from_raw_parts(ui_str, ui_str_len);
751     if let Ok(ui_str) = std::str::from_utf8(slice) {
752         renderer.set_profiler_ui(ui_str);
753     }
756 #[no_mangle]
757 pub unsafe extern "C" fn wr_renderer_delete(renderer: *mut Renderer) {
758     let renderer = Box::from_raw(renderer);
759     renderer.deinit();
760     // let renderer go out of scope and get dropped
763 #[no_mangle]
764 pub unsafe extern "C" fn wr_renderer_accumulate_memory_report(
765     renderer: &mut Renderer,
766     report: &mut MemoryReport,
767     swgl: *mut c_void,
768 ) {
769     *report += renderer.report_memory(swgl);
772 // cbindgen doesn't support tuples, so we have a little struct instead, with
773 // an Into implementation to convert from the tuple to the struct.
774 #[repr(C)]
775 pub struct WrPipelineEpoch {
776     pipeline_id: WrPipelineId,
777     document_id: WrDocumentId,
778     epoch: WrEpoch,
781 impl<'a> From<(&'a (WrPipelineId, WrDocumentId), &'a WrEpoch)> for WrPipelineEpoch {
782     fn from(tuple: (&(WrPipelineId, WrDocumentId), &WrEpoch)) -> WrPipelineEpoch {
783         WrPipelineEpoch {
784             pipeline_id: (tuple.0).0,
785             document_id: (tuple.0).1,
786             epoch: *tuple.1,
787         }
788     }
791 #[repr(C)]
792 pub struct WrPipelineIdAndEpoch {
793     pipeline_id: WrPipelineId,
794     epoch: WrEpoch,
797 impl<'a> From<(&WrPipelineId, &WrEpoch)> for WrPipelineIdAndEpoch {
798     fn from(tuple: (&WrPipelineId, &WrEpoch)) -> WrPipelineIdAndEpoch {
799         WrPipelineIdAndEpoch {
800             pipeline_id: *tuple.0,
801             epoch: *tuple.1,
802         }
803     }
806 #[repr(C)]
807 pub struct WrRemovedPipeline {
808     pipeline_id: WrPipelineId,
809     document_id: WrDocumentId,
812 impl<'a> From<&'a (WrPipelineId, WrDocumentId)> for WrRemovedPipeline {
813     fn from(tuple: &(WrPipelineId, WrDocumentId)) -> WrRemovedPipeline {
814         WrRemovedPipeline {
815             pipeline_id: tuple.0,
816             document_id: tuple.1,
817         }
818     }
821 #[repr(C)]
822 pub struct WrPipelineInfo {
823     /// This contains an entry for each pipeline that was rendered, along with
824     /// the epoch at which it was rendered. Rendered pipelines include the root
825     /// pipeline and any other pipelines that were reachable via IFrame display
826     /// items from the root pipeline.
827     epochs: ThinVec<WrPipelineEpoch>,
828     /// This contains an entry for each pipeline that was removed during the
829     /// last transaction. These pipelines would have been explicitly removed by
830     /// calling remove_pipeline on the transaction object; the pipeline showing
831     /// up in this array means that the data structures have been torn down on
832     /// the webrender side, and so any remaining data structures on the caller
833     /// side can now be torn down also.
834     removed_pipelines: ThinVec<WrRemovedPipeline>,
837 impl WrPipelineInfo {
838     fn new(info: &PipelineInfo) -> Self {
839         WrPipelineInfo {
840             epochs: info.epochs.iter().map(WrPipelineEpoch::from).collect(),
841             removed_pipelines: info.removed_pipelines.iter().map(WrRemovedPipeline::from).collect(),
842         }
843     }
846 #[no_mangle]
847 pub unsafe extern "C" fn wr_renderer_flush_pipeline_info(renderer: &mut Renderer, out: &mut WrPipelineInfo) {
848     let info = renderer.flush_pipeline_info();
849     *out = WrPipelineInfo::new(&info);
852 extern "C" {
853     pub fn gecko_profiler_thread_is_being_profiled() -> bool;
856 pub fn gecko_profiler_start_marker(name: &str) {
857     use gecko_profiler::{gecko_profiler_category, MarkerOptions, MarkerTiming, ProfilerTime, Tracing};
858     gecko_profiler::add_marker(
859         name,
860         gecko_profiler_category!(Graphics),
861         MarkerOptions {
862             timing: MarkerTiming::interval_start(ProfilerTime::now()),
863             ..Default::default()
864         },
865         Tracing("Webrender".to_string()),
866     );
868 pub fn gecko_profiler_end_marker(name: &str) {
869     use gecko_profiler::{gecko_profiler_category, MarkerOptions, MarkerTiming, ProfilerTime, Tracing};
870     gecko_profiler::add_marker(
871         name,
872         gecko_profiler_category!(Graphics),
873         MarkerOptions {
874             timing: MarkerTiming::interval_end(ProfilerTime::now()),
875             ..Default::default()
876         },
877         Tracing("Webrender".to_string()),
878     );
881 pub fn gecko_profiler_event_marker(name: &str) {
882     use gecko_profiler::{gecko_profiler_category, Tracing};
883     gecko_profiler::add_marker(
884         name,
885         gecko_profiler_category!(Graphics),
886         Default::default(),
887         Tracing("Webrender".to_string()),
888     );
891 pub fn gecko_profiler_add_text_marker(name: &str, text: &str, microseconds: f64) {
892     use gecko_profiler::{gecko_profiler_category, MarkerOptions, MarkerTiming, ProfilerTime};
893     if !gecko_profiler::can_accept_markers() {
894         return;
895     }
897     let now = ProfilerTime::now();
898     let start = now.clone().subtract_microseconds(microseconds);
899     gecko_profiler::add_text_marker(
900         name,
901         gecko_profiler_category!(Graphics),
902         MarkerOptions {
903             timing: MarkerTiming::interval(start, now),
904             ..Default::default()
905         },
906         text,
907     );
910 /// Simple implementation of the WR ProfilerHooks trait to allow profile
911 /// markers to be seen in the Gecko profiler.
912 struct GeckoProfilerHooks;
914 impl ProfilerHooks for GeckoProfilerHooks {
915     fn register_thread(&self, thread_name: &str) {
916         gecko_profiler::register_thread(thread_name);
917     }
919     fn unregister_thread(&self) {
920         gecko_profiler::unregister_thread();
921     }
923     fn begin_marker(&self, label: &str) {
924         gecko_profiler_start_marker(label);
925     }
927     fn end_marker(&self, label: &str) {
928         gecko_profiler_end_marker(label);
929     }
931     fn event_marker(&self, label: &str) {
932         gecko_profiler_event_marker(label);
933     }
935     fn add_text_marker(&self, label: &str, text: &str, duration: Duration) {
936         let micros = duration.as_micros() as f64;
937         gecko_profiler_add_text_marker(label, text, micros);
938     }
940     fn thread_is_being_profiled(&self) -> bool {
941         unsafe { gecko_profiler_thread_is_being_profiled() }
942     }
945 static PROFILER_HOOKS: GeckoProfilerHooks = GeckoProfilerHooks {};
947 #[allow(improper_ctypes)] // this is needed so that rustc doesn't complain about passing the &mut Transaction to an extern function
948 extern "C" {
949     // These callbacks are invoked from the scene builder thread (aka the APZ
950     // updater thread)
951     fn apz_register_updater(window_id: WrWindowId);
952     fn apz_pre_scene_swap(window_id: WrWindowId);
953     fn apz_post_scene_swap(window_id: WrWindowId, pipeline_info: &WrPipelineInfo);
954     fn apz_run_updater(window_id: WrWindowId);
955     fn apz_deregister_updater(window_id: WrWindowId);
957     // These callbacks are invoked from the render backend thread (aka the APZ
958     // sampler thread)
959     fn apz_register_sampler(window_id: WrWindowId);
960     fn apz_sample_transforms(window_id: WrWindowId, generated_frame_id: *const u64, transaction: &mut Transaction);
961     fn apz_deregister_sampler(window_id: WrWindowId);
963     fn omta_register_sampler(window_id: WrWindowId);
964     fn omta_sample(window_id: WrWindowId, transaction: &mut Transaction);
965     fn omta_deregister_sampler(window_id: WrWindowId);
968 struct APZCallbacks {
969     window_id: WrWindowId,
972 impl APZCallbacks {
973     pub fn new(window_id: WrWindowId) -> Self {
974         APZCallbacks { window_id }
975     }
978 impl SceneBuilderHooks for APZCallbacks {
979     fn register(&self) {
980         unsafe { apz_register_updater(self.window_id) }
981     }
983     fn pre_scene_build(&self) {
984         gecko_profiler_start_marker("SceneBuilding");
985     }
987     fn pre_scene_swap(&self) {
988         unsafe {
989             apz_pre_scene_swap(self.window_id);
990         }
991     }
993     fn post_scene_swap(&self, _document_ids: &Vec<DocumentId>, info: PipelineInfo) {
994         let mut info = WrPipelineInfo::new(&info);
995         unsafe {
996             apz_post_scene_swap(self.window_id, &info);
997         }
999         // After a scene swap we should schedule a render for the next vsync,
1000         // otherwise there's no guarantee that the new scene will get rendered
1001         // anytime soon
1002         unsafe { wr_finished_scene_build(self.window_id, &mut info) }
1003         gecko_profiler_end_marker("SceneBuilding");
1004     }
1006     fn post_resource_update(&self, _document_ids: &Vec<DocumentId>) {
1007         unsafe { wr_schedule_render(self.window_id, RenderReasons::POST_RESOURCE_UPDATES_HOOK) }
1008         gecko_profiler_end_marker("SceneBuilding");
1009     }
1011     fn post_empty_scene_build(&self) {
1012         gecko_profiler_end_marker("SceneBuilding");
1013     }
1015     fn poke(&self) {
1016         unsafe { apz_run_updater(self.window_id) }
1017     }
1019     fn deregister(&self) {
1020         unsafe { apz_deregister_updater(self.window_id) }
1021     }
1024 struct SamplerCallback {
1025     window_id: WrWindowId,
1028 impl SamplerCallback {
1029     pub fn new(window_id: WrWindowId) -> Self {
1030         SamplerCallback { window_id }
1031     }
1034 impl AsyncPropertySampler for SamplerCallback {
1035     fn register(&self) {
1036         unsafe {
1037             apz_register_sampler(self.window_id);
1038             omta_register_sampler(self.window_id);
1039         }
1040     }
1042     fn sample(&self, _document_id: DocumentId, generated_frame_id: Option<u64>) -> Vec<FrameMsg> {
1043         let generated_frame_id_value;
1044         let generated_frame_id: *const u64 = match generated_frame_id {
1045             Some(id) => {
1046                 generated_frame_id_value = id;
1047                 &generated_frame_id_value
1048             },
1049             None => ptr::null_mut(),
1050         };
1051         let mut transaction = Transaction::new();
1052         // Reset the pending properties first because omta_sample and apz_sample_transforms
1053         // may be failed to reset them due to null samplers.
1054         transaction.reset_dynamic_properties();
1055         unsafe {
1056             apz_sample_transforms(self.window_id, generated_frame_id, &mut transaction);
1057             omta_sample(self.window_id, &mut transaction);
1058         };
1059         transaction.get_frame_ops()
1060     }
1062     fn deregister(&self) {
1063         unsafe {
1064             apz_deregister_sampler(self.window_id);
1065             omta_deregister_sampler(self.window_id);
1066         }
1067     }
1070 extern "C" {
1071     fn wr_register_thread_local_arena();
1074 pub struct WrThreadPool(Arc<rayon::ThreadPool>);
1076 #[no_mangle]
1077 pub extern "C" fn wr_thread_pool_new(low_priority: bool) -> *mut WrThreadPool {
1078     // Clamp the number of workers between 1 and 4/8. We get diminishing returns
1079     // with high worker counts and extra overhead because of rayon and font
1080     // management.
1082     // We clamp to 4 high priority threads because contention and memory usage
1083     // make it not worth going higher
1084     let max = if low_priority { 8 } else { 4 };
1085     let num_threads = num_cpus::get().min(max);
1087     let priority_tag = if low_priority { "LP" } else { "" };
1089     let worker = rayon::ThreadPoolBuilder::new()
1090         .thread_name(move |idx| format!("WRWorker{}#{}", priority_tag, idx))
1091         .num_threads(num_threads)
1092         .start_handler(move |idx| {
1093             unsafe {
1094                 wr_register_thread_local_arena();
1095             }
1096             let name = format!("WRWorker{}#{}", priority_tag, idx);
1097             register_thread_with_profiler(name.clone());
1098             gecko_profiler::register_thread(&name);
1099         })
1100         .exit_handler(|_idx| {
1101             gecko_profiler::unregister_thread();
1102         })
1103         .build();
1105     let workers = Arc::new(worker.unwrap());
1107     Box::into_raw(Box::new(WrThreadPool(workers)))
1110 #[no_mangle]
1111 pub unsafe extern "C" fn wr_thread_pool_delete(thread_pool: *mut WrThreadPool) {
1112     Box::from_raw(thread_pool);
1115 #[no_mangle]
1116 pub unsafe extern "C" fn wr_program_cache_new(
1117     prof_path: &nsAString,
1118     thread_pool: *mut WrThreadPool,
1119 ) -> *mut WrProgramCache {
1120     let workers = &(*thread_pool).0;
1121     let program_cache = WrProgramCache::new(prof_path, workers);
1122     Box::into_raw(Box::new(program_cache))
1125 #[no_mangle]
1126 pub unsafe extern "C" fn wr_program_cache_delete(program_cache: *mut WrProgramCache) {
1127     Box::from_raw(program_cache);
1130 #[no_mangle]
1131 pub unsafe extern "C" fn wr_try_load_startup_shaders_from_disk(program_cache: *mut WrProgramCache) {
1132     (*program_cache).try_load_startup_shaders_from_disk();
1135 #[no_mangle]
1136 pub unsafe extern "C" fn remove_program_binary_disk_cache(prof_path: &nsAString) -> bool {
1137     match remove_disk_cache(prof_path) {
1138         Ok(_) => true,
1139         Err(_) => {
1140             error!("Failed to remove program binary disk cache");
1141             false
1142         },
1143     }
1146 // This matches IsEnvSet in gfxEnv.h
1147 fn env_var_to_bool(key: &'static str) -> bool {
1148     env::var(key).ok().map_or(false, |v| !v.is_empty())
1151 // Call MakeCurrent before this.
1152 fn wr_device_new(gl_context: *mut c_void, pc: Option<&mut WrProgramCache>) -> Device {
1153     assert!(unsafe { is_in_render_thread() });
1155     let gl;
1156     if unsafe { is_glcontext_gles(gl_context) } {
1157         gl = unsafe { gl::GlesFns::load_with(|symbol| get_proc_address(gl_context, symbol)) };
1158     } else {
1159         gl = unsafe { gl::GlFns::load_with(|symbol| get_proc_address(gl_context, symbol)) };
1160     }
1162     let version = gl.get_string(gl::VERSION);
1164     info!("WebRender - OpenGL version new {}", version);
1166     let upload_method = if unsafe { is_glcontext_angle(gl_context) } {
1167         UploadMethod::Immediate
1168     } else {
1169         UploadMethod::PixelBuffer(ONE_TIME_USAGE_HINT)
1170     };
1172     let resource_override_path = unsafe {
1173         let override_charptr = gfx_wr_resource_path_override();
1174         if override_charptr.is_null() {
1175             None
1176         } else {
1177             match CStr::from_ptr(override_charptr).to_str() {
1178                 Ok(override_str) => Some(PathBuf::from(override_str)),
1179                 _ => None,
1180             }
1181         }
1182     };
1184     let use_optimized_shaders = unsafe { gfx_wr_use_optimized_shaders() };
1186     let cached_programs = pc.map(|cached_programs| Rc::clone(cached_programs.rc_get()));
1188     Device::new(
1189         gl,
1190         Some(Box::new(MozCrashAnnotator)),
1191         resource_override_path,
1192         use_optimized_shaders,
1193         upload_method,
1194         512 * 512,
1195         cached_programs,
1196         true,
1197         true,
1198         None,
1199         false,
1200         false,
1201     )
1204 extern "C" {
1205     fn wr_compositor_create_surface(
1206         compositor: *mut c_void,
1207         id: NativeSurfaceId,
1208         virtual_offset: DeviceIntPoint,
1209         tile_size: DeviceIntSize,
1210         is_opaque: bool,
1211     );
1212     fn wr_compositor_create_external_surface(compositor: *mut c_void, id: NativeSurfaceId, is_opaque: bool);
1213     fn wr_compositor_create_backdrop_surface(compositor: *mut c_void, id: NativeSurfaceId, color: ColorF);
1214     fn wr_compositor_destroy_surface(compositor: *mut c_void, id: NativeSurfaceId);
1215     fn wr_compositor_create_tile(compositor: *mut c_void, id: NativeSurfaceId, x: i32, y: i32);
1216     fn wr_compositor_destroy_tile(compositor: *mut c_void, id: NativeSurfaceId, x: i32, y: i32);
1217     fn wr_compositor_attach_external_image(
1218         compositor: *mut c_void,
1219         id: NativeSurfaceId,
1220         external_image: ExternalImageId,
1221     );
1222     fn wr_compositor_bind(
1223         compositor: *mut c_void,
1224         id: NativeTileId,
1225         offset: &mut DeviceIntPoint,
1226         fbo_id: &mut u32,
1227         dirty_rect: DeviceIntRect,
1228         valid_rect: DeviceIntRect,
1229     );
1230     fn wr_compositor_unbind(compositor: *mut c_void);
1231     fn wr_compositor_begin_frame(compositor: *mut c_void);
1232     fn wr_compositor_add_surface(
1233         compositor: *mut c_void,
1234         id: NativeSurfaceId,
1235         transform: &CompositorSurfaceTransform,
1236         clip_rect: DeviceIntRect,
1237         image_rendering: ImageRendering,
1238     );
1239     fn wr_compositor_start_compositing(
1240         compositor: *mut c_void,
1241         clear_color: ColorF,
1242         dirty_rects: *const DeviceIntRect,
1243         num_dirty_rects: usize,
1244         opaque_rects: *const DeviceIntRect,
1245         num_opaque_rects: usize,
1246     );
1247     fn wr_compositor_end_frame(compositor: *mut c_void);
1248     fn wr_compositor_enable_native_compositor(compositor: *mut c_void, enable: bool);
1249     fn wr_compositor_deinit(compositor: *mut c_void);
1250     fn wr_compositor_get_capabilities(compositor: *mut c_void, caps: *mut CompositorCapabilities);
1251     fn wr_compositor_get_window_visibility(compositor: *mut c_void, caps: *mut WindowVisibility);
1252     fn wr_compositor_map_tile(
1253         compositor: *mut c_void,
1254         id: NativeTileId,
1255         dirty_rect: DeviceIntRect,
1256         valid_rect: DeviceIntRect,
1257         data: &mut *mut c_void,
1258         stride: &mut i32,
1259     );
1260     fn wr_compositor_unmap_tile(compositor: *mut c_void);
1262     fn wr_partial_present_compositor_set_buffer_damage_region(
1263         compositor: *mut c_void,
1264         rects: *const DeviceIntRect,
1265         n_rects: usize,
1266     );
1269 pub struct WrCompositor(*mut c_void);
1271 impl Compositor for WrCompositor {
1272     fn create_surface(
1273         &mut self,
1274         id: NativeSurfaceId,
1275         virtual_offset: DeviceIntPoint,
1276         tile_size: DeviceIntSize,
1277         is_opaque: bool,
1278     ) {
1279         unsafe {
1280             wr_compositor_create_surface(self.0, id, virtual_offset, tile_size, is_opaque);
1281         }
1282     }
1284     fn create_external_surface(&mut self, id: NativeSurfaceId, is_opaque: bool) {
1285         unsafe {
1286             wr_compositor_create_external_surface(self.0, id, is_opaque);
1287         }
1288     }
1290     fn create_backdrop_surface(&mut self, id: NativeSurfaceId, color: ColorF) {
1291         unsafe {
1292             wr_compositor_create_backdrop_surface(self.0, id, color);
1293         }
1294     }
1296     fn destroy_surface(&mut self, id: NativeSurfaceId) {
1297         unsafe {
1298             wr_compositor_destroy_surface(self.0, id);
1299         }
1300     }
1302     fn create_tile(&mut self, id: NativeTileId) {
1303         unsafe {
1304             wr_compositor_create_tile(self.0, id.surface_id, id.x, id.y);
1305         }
1306     }
1308     fn destroy_tile(&mut self, id: NativeTileId) {
1309         unsafe {
1310             wr_compositor_destroy_tile(self.0, id.surface_id, id.x, id.y);
1311         }
1312     }
1314     fn attach_external_image(&mut self, id: NativeSurfaceId, external_image: ExternalImageId) {
1315         unsafe {
1316             wr_compositor_attach_external_image(self.0, id, external_image);
1317         }
1318     }
1320     fn bind(&mut self, id: NativeTileId, dirty_rect: DeviceIntRect, valid_rect: DeviceIntRect) -> NativeSurfaceInfo {
1321         let mut surface_info = NativeSurfaceInfo {
1322             origin: DeviceIntPoint::zero(),
1323             fbo_id: 0,
1324         };
1326         unsafe {
1327             wr_compositor_bind(
1328                 self.0,
1329                 id,
1330                 &mut surface_info.origin,
1331                 &mut surface_info.fbo_id,
1332                 dirty_rect,
1333                 valid_rect,
1334             );
1335         }
1337         surface_info
1338     }
1340     fn unbind(&mut self) {
1341         unsafe {
1342             wr_compositor_unbind(self.0);
1343         }
1344     }
1346     fn begin_frame(&mut self) {
1347         unsafe {
1348             wr_compositor_begin_frame(self.0);
1349         }
1350     }
1352     fn add_surface(
1353         &mut self,
1354         id: NativeSurfaceId,
1355         transform: CompositorSurfaceTransform,
1356         clip_rect: DeviceIntRect,
1357         image_rendering: ImageRendering,
1358     ) {
1359         unsafe {
1360             wr_compositor_add_surface(self.0, id, &transform, clip_rect, image_rendering);
1361         }
1362     }
1364     fn start_compositing(
1365         &mut self,
1366         clear_color: ColorF,
1367         dirty_rects: &[DeviceIntRect],
1368         opaque_rects: &[DeviceIntRect],
1369     ) {
1370         unsafe {
1371             wr_compositor_start_compositing(
1372                 self.0,
1373                 clear_color,
1374                 dirty_rects.as_ptr(),
1375                 dirty_rects.len(),
1376                 opaque_rects.as_ptr(),
1377                 opaque_rects.len(),
1378             );
1379         }
1380     }
1382     fn end_frame(&mut self) {
1383         unsafe {
1384             wr_compositor_end_frame(self.0);
1385         }
1386     }
1388     fn enable_native_compositor(&mut self, enable: bool) {
1389         unsafe {
1390             wr_compositor_enable_native_compositor(self.0, enable);
1391         }
1392     }
1394     fn deinit(&mut self) {
1395         unsafe {
1396             wr_compositor_deinit(self.0);
1397         }
1398     }
1400     fn get_capabilities(&self) -> CompositorCapabilities {
1401         unsafe {
1402             let mut caps: CompositorCapabilities = Default::default();
1403             wr_compositor_get_capabilities(self.0, &mut caps);
1404             caps
1405         }
1406     }
1408     fn get_window_visibility(&self) -> WindowVisibility {
1409         unsafe {
1410             let mut visibility: WindowVisibility = Default::default();
1411             wr_compositor_get_window_visibility(self.0, &mut visibility);
1412             visibility
1413         }
1414     }
1417 extern "C" {
1418     fn wr_swgl_lock_composite_surface(
1419         ctx: *mut c_void,
1420         external_image_id: ExternalImageId,
1421         composite_info: *mut SWGLCompositeSurfaceInfo,
1422     ) -> bool;
1423     fn wr_swgl_unlock_composite_surface(ctx: *mut c_void, external_image_id: ExternalImageId);
1426 impl MappableCompositor for WrCompositor {
1427     /// Map a tile's underlying buffer so it can be used as the backing for
1428     /// a SWGL framebuffer. This is intended to be a replacement for 'bind'
1429     /// in any compositors that intend to directly interoperate with SWGL
1430     /// while supporting some form of native layers.
1431     fn map_tile(
1432         &mut self,
1433         id: NativeTileId,
1434         dirty_rect: DeviceIntRect,
1435         valid_rect: DeviceIntRect,
1436     ) -> Option<MappedTileInfo> {
1437         let mut tile_info = MappedTileInfo {
1438             data: ptr::null_mut(),
1439             stride: 0,
1440         };
1442         unsafe {
1443             wr_compositor_map_tile(
1444                 self.0,
1445                 id,
1446                 dirty_rect,
1447                 valid_rect,
1448                 &mut tile_info.data,
1449                 &mut tile_info.stride,
1450             );
1451         }
1453         if !tile_info.data.is_null() && tile_info.stride != 0 {
1454             Some(tile_info)
1455         } else {
1456             None
1457         }
1458     }
1460     /// Unmap a tile that was was previously mapped via map_tile to signal
1461     /// that SWGL is done rendering to the buffer.
1462     fn unmap_tile(&mut self) {
1463         unsafe {
1464             wr_compositor_unmap_tile(self.0);
1465         }
1466     }
1468     fn lock_composite_surface(
1469         &mut self,
1470         ctx: *mut c_void,
1471         external_image_id: ExternalImageId,
1472         composite_info: *mut SWGLCompositeSurfaceInfo,
1473     ) -> bool {
1474         unsafe { wr_swgl_lock_composite_surface(ctx, external_image_id, composite_info) }
1475     }
1476     fn unlock_composite_surface(&mut self, ctx: *mut c_void, external_image_id: ExternalImageId) {
1477         unsafe { wr_swgl_unlock_composite_surface(ctx, external_image_id) }
1478     }
1481 pub struct WrPartialPresentCompositor(*mut c_void);
1483 impl PartialPresentCompositor for WrPartialPresentCompositor {
1484     fn set_buffer_damage_region(&mut self, rects: &[DeviceIntRect]) {
1485         unsafe {
1486             wr_partial_present_compositor_set_buffer_damage_region(self.0, rects.as_ptr(), rects.len());
1487         }
1488     }
1491 /// A wrapper around a strong reference to a Shaders object.
1492 pub struct WrShaders(SharedShaders);
1494 // Call MakeCurrent before this.
1495 #[no_mangle]
1496 pub extern "C" fn wr_window_new(
1497     window_id: WrWindowId,
1498     window_width: i32,
1499     window_height: i32,
1500     is_main_window: bool,
1501     support_low_priority_transactions: bool,
1502     support_low_priority_threadpool: bool,
1503     allow_texture_swizzling: bool,
1504     allow_scissored_cache_clears: bool,
1505     swgl_context: *mut c_void,
1506     gl_context: *mut c_void,
1507     surface_origin_is_top_left: bool,
1508     program_cache: Option<&mut WrProgramCache>,
1509     shaders: Option<&mut WrShaders>,
1510     thread_pool: *mut WrThreadPool,
1511     thread_pool_low_priority: *mut WrThreadPool,
1512     size_of_op: VoidPtrToSizeFn,
1513     enclosing_size_of_op: VoidPtrToSizeFn,
1514     document_id: u32,
1515     compositor: *mut c_void,
1516     use_native_compositor: bool,
1517     use_partial_present: bool,
1518     max_partial_present_rects: usize,
1519     draw_previous_partial_present_regions: bool,
1520     out_handle: &mut *mut DocumentHandle,
1521     out_renderer: &mut *mut Renderer,
1522     out_max_texture_size: *mut i32,
1523     out_err: &mut *mut c_char,
1524     enable_gpu_markers: bool,
1525     panic_on_gl_error: bool,
1526     picture_tile_width: i32,
1527     picture_tile_height: i32,
1528     reject_software_rasterizer: bool,
1529     low_quality_pinch_zoom: bool,
1530 ) -> bool {
1531     assert!(unsafe { is_in_render_thread() });
1533     // Ensure the WR profiler callbacks are hooked up to the Gecko profiler.
1534     set_profiler_hooks(Some(&PROFILER_HOOKS));
1536     let software = !swgl_context.is_null();
1537     let (gl, sw_gl) = if software {
1538         let ctx = swgl::Context::from(swgl_context);
1539         ctx.make_current();
1540         (Rc::new(ctx) as Rc<dyn gl::Gl>, Some(ctx))
1541     } else {
1542         let gl = unsafe {
1543             if gl_context.is_null() {
1544                 panic!("Native GL context required when not using SWGL!");
1545             } else if is_glcontext_gles(gl_context) {
1546                 gl::GlesFns::load_with(|symbol| get_proc_address(gl_context, symbol))
1547             } else {
1548                 gl::GlFns::load_with(|symbol| get_proc_address(gl_context, symbol))
1549             }
1550         };
1551         (gl, None)
1552     };
1554     let version = gl.get_string(gl::VERSION);
1556     info!("WebRender - OpenGL version new {}", version);
1558     let workers = unsafe { Arc::clone(&(*thread_pool).0) };
1559     let workers_low_priority = unsafe {
1560         if support_low_priority_threadpool {
1561             Arc::clone(&(*thread_pool_low_priority).0)
1562         } else {
1563             Arc::clone(&(*thread_pool).0)
1564         }
1565     };
1567     let upload_method = if !gl_context.is_null() && unsafe { is_glcontext_angle(gl_context) } {
1568         UploadMethod::Immediate
1569     } else {
1570         UploadMethod::PixelBuffer(ONE_TIME_USAGE_HINT)
1571     };
1573     let precache_flags = if env_var_to_bool("MOZ_WR_PRECACHE_SHADERS") {
1574         ShaderPrecacheFlags::FULL_COMPILE
1575     } else {
1576         ShaderPrecacheFlags::empty()
1577     };
1579     let cached_programs = program_cache.map(|program_cache| Rc::clone(&program_cache.rc_get()));
1581     let color = if cfg!(target_os = "android") {
1582         // The color is for avoiding black flash before receiving display list.
1583         ColorF::new(1.0, 1.0, 1.0, 1.0)
1584     } else {
1585         ColorF::new(0.0, 0.0, 0.0, 0.0)
1586     };
1588     let compositor_config = if software {
1589         CompositorConfig::Native {
1590             compositor: Box::new(SwCompositor::new(
1591                 sw_gl.unwrap(),
1592                 Box::new(WrCompositor(compositor)),
1593                 use_native_compositor,
1594             )),
1595         }
1596     } else if use_native_compositor {
1597         CompositorConfig::Native {
1598             compositor: Box::new(WrCompositor(compositor)),
1599         }
1600     } else {
1601         CompositorConfig::Draw {
1602             max_partial_present_rects,
1603             draw_previous_partial_present_regions,
1604             partial_present: if use_partial_present {
1605                 Some(Box::new(WrPartialPresentCompositor(compositor)))
1606             } else {
1607                 None
1608             },
1609         }
1610     };
1612     let picture_tile_size = if picture_tile_width > 0 && picture_tile_height > 0 {
1613         Some(DeviceIntSize::new(picture_tile_width, picture_tile_height))
1614     } else {
1615         None
1616     };
1618     let texture_cache_config = if is_main_window {
1619         TextureCacheConfig::DEFAULT
1620     } else {
1621         TextureCacheConfig {
1622             color8_linear_texture_size: 512,
1623             color8_nearest_texture_size: 512,
1624             color8_glyph_texture_size: 512,
1625             alpha8_texture_size: 512,
1626             alpha8_glyph_texture_size: 512,
1627             alpha16_texture_size: 512,
1628         }
1629     };
1631     let opts = RendererOptions {
1632         enable_aa: true,
1633         force_subpixel_aa: false,
1634         enable_subpixel_aa: cfg!(not(target_os = "android")),
1635         support_low_priority_transactions,
1636         allow_texture_swizzling,
1637         blob_image_handler: Some(Box::new(Moz2dBlobImageHandler::new(
1638             workers.clone(),
1639             workers_low_priority,
1640         ))),
1641         crash_annotator: Some(Box::new(MozCrashAnnotator)),
1642         workers: Some(workers),
1643         size_of_op: Some(size_of_op),
1644         enclosing_size_of_op: Some(enclosing_size_of_op),
1645         cached_programs,
1646         resource_override_path: unsafe {
1647             let override_charptr = gfx_wr_resource_path_override();
1648             if override_charptr.is_null() {
1649                 None
1650             } else {
1651                 match CStr::from_ptr(override_charptr).to_str() {
1652                     Ok(override_str) => Some(PathBuf::from(override_str)),
1653                     _ => None,
1654                 }
1655             }
1656         },
1657         use_optimized_shaders: unsafe { gfx_wr_use_optimized_shaders() },
1658         renderer_id: Some(window_id.0),
1659         upload_method,
1660         scene_builder_hooks: Some(Box::new(APZCallbacks::new(window_id))),
1661         sampler: Some(Box::new(SamplerCallback::new(window_id))),
1662         max_internal_texture_size: Some(8192), // We want to tile if larger than this
1663         clear_color: color,
1664         precache_flags,
1665         namespace_alloc_by_client: true,
1666         // Font namespace must be allocated by the client
1667         shared_font_namespace: Some(next_namespace_id()),
1668         // SWGL doesn't support the GL_ALWAYS depth comparison function used by
1669         // `clear_caches_with_quads`, but scissored clears work well.
1670         clear_caches_with_quads: !software && !allow_scissored_cache_clears,
1671         // SWGL supports KHR_blend_equation_advanced safely, but we haven't yet
1672         // tested other HW platforms determine if it is safe to allow them.
1673         allow_advanced_blend_equation: software,
1674         surface_origin_is_top_left,
1675         compositor_config,
1676         enable_gpu_markers,
1677         panic_on_gl_error,
1678         picture_tile_size,
1679         texture_cache_config,
1680         reject_software_rasterizer,
1681         low_quality_pinch_zoom,
1682         ..Default::default()
1683     };
1685     let window_size = DeviceIntSize::new(window_width, window_height);
1686     let notifier = Box::new(CppNotifier { window_id });
1687     let (renderer, sender) = match Renderer::new(gl, notifier, opts, shaders.map(|sh| &sh.0)) {
1688         Ok((renderer, sender)) => (renderer, sender),
1689         Err(e) => {
1690             warn!(" Failed to create a Renderer: {:?}", e);
1691             let msg = CString::new(format!("wr_window_new: {:?}", e)).unwrap();
1692             unsafe {
1693                 gfx_critical_note(msg.as_ptr());
1694             }
1695             *out_err = msg.into_raw();
1696             return false;
1697         },
1698     };
1700     unsafe {
1701         *out_max_texture_size = renderer.get_max_texture_size();
1702     }
1703     *out_handle = Box::into_raw(Box::new(DocumentHandle::new(
1704         sender.create_api_by_client(next_namespace_id()),
1705         None,
1706         window_size,
1707         document_id,
1708     )));
1709     *out_renderer = Box::into_raw(Box::new(renderer));
1711     true
1714 #[no_mangle]
1715 pub unsafe extern "C" fn wr_api_free_error_msg(msg: *mut c_char) {
1716     if !msg.is_null() {
1717         drop(CString::from_raw(msg));
1718     }
1721 #[no_mangle]
1722 pub unsafe extern "C" fn wr_api_delete_document(dh: &mut DocumentHandle) {
1723     dh.api.delete_document(dh.document_id);
1726 #[no_mangle]
1727 pub extern "C" fn wr_api_clone(dh: &mut DocumentHandle, out_handle: &mut *mut DocumentHandle) {
1728     assert!(unsafe { is_in_compositor_thread() });
1730     let hit_tester = dh.ensure_hit_tester().clone();
1732     let handle = DocumentHandle {
1733         api: dh.api.create_sender().create_api_by_client(next_namespace_id()),
1734         document_id: dh.document_id,
1735         hit_tester: Some(hit_tester),
1736         hit_tester_request: None,
1737     };
1738     *out_handle = Box::into_raw(Box::new(handle));
1741 #[no_mangle]
1742 pub unsafe extern "C" fn wr_api_delete(dh: *mut DocumentHandle) {
1743     let _ = Box::from_raw(dh);
1746 #[no_mangle]
1747 pub unsafe extern "C" fn wr_api_stop_render_backend(dh: &mut DocumentHandle) {
1748     dh.api.stop_render_backend();
1751 #[no_mangle]
1752 pub unsafe extern "C" fn wr_api_shut_down(dh: &mut DocumentHandle) {
1753     dh.api.shut_down(true);
1756 #[no_mangle]
1757 pub unsafe extern "C" fn wr_api_notify_memory_pressure(dh: &mut DocumentHandle) {
1758     dh.api.notify_memory_pressure();
1761 #[no_mangle]
1762 pub extern "C" fn wr_api_set_debug_flags(dh: &mut DocumentHandle, flags: DebugFlags) {
1763     dh.api.set_debug_flags(flags);
1766 #[no_mangle]
1767 pub extern "C" fn wr_api_set_bool(dh: &mut DocumentHandle, param_name: BoolParameter, val: bool) {
1768     dh.api.set_parameter(Parameter::Bool(param_name, val));
1771 #[no_mangle]
1772 pub extern "C" fn wr_api_set_int(dh: &mut DocumentHandle, param_name: IntParameter, val: i32) {
1773     dh.api.set_parameter(Parameter::Int(param_name, val));
1776 #[no_mangle]
1777 pub unsafe extern "C" fn wr_api_accumulate_memory_report(
1778     dh: &mut DocumentHandle,
1779     report: &mut MemoryReport,
1780     // we manually expand VoidPtrToSizeFn here because cbindgen otherwise fails to fold the Option<fn()>
1781     // https://github.com/eqrion/cbindgen/issues/552
1782     size_of_op: unsafe extern "C" fn(ptr: *const c_void) -> usize,
1783     enclosing_size_of_op: Option<unsafe extern "C" fn(ptr: *const c_void) -> usize>,
1784 ) {
1785     let ops = MallocSizeOfOps::new(size_of_op, enclosing_size_of_op);
1786     *report += dh.api.report_memory(ops);
1789 #[no_mangle]
1790 pub unsafe extern "C" fn wr_api_clear_all_caches(dh: &mut DocumentHandle) {
1791     dh.api.send_debug_cmd(DebugCommand::ClearCaches(ClearCache::all()));
1794 #[no_mangle]
1795 pub unsafe extern "C" fn wr_api_enable_native_compositor(dh: &mut DocumentHandle, enable: bool) {
1796     dh.api.send_debug_cmd(DebugCommand::EnableNativeCompositor(enable));
1799 #[no_mangle]
1800 pub unsafe extern "C" fn wr_api_set_batching_lookback(dh: &mut DocumentHandle, count: u32) {
1801     dh.api.send_debug_cmd(DebugCommand::SetBatchingLookback(count));
1804 fn make_transaction(do_async: bool) -> Transaction {
1805     let mut transaction = Transaction::new();
1806     // Ensure that we either use async scene building or not based on the
1807     // gecko pref, regardless of what the default is. We can remove this once
1808     // the scene builder thread is enabled everywhere and working well.
1809     if do_async {
1810         transaction.use_scene_builder_thread();
1811     } else {
1812         transaction.skip_scene_builder();
1813     }
1814     transaction
1817 #[no_mangle]
1818 pub extern "C" fn wr_transaction_new(do_async: bool) -> *mut Transaction {
1819     Box::into_raw(Box::new(make_transaction(do_async)))
1822 #[no_mangle]
1823 pub extern "C" fn wr_transaction_delete(txn: *mut Transaction) {
1824     unsafe {
1825         let _ = Box::from_raw(txn);
1826     }
1829 #[no_mangle]
1830 pub extern "C" fn wr_transaction_set_low_priority(txn: &mut Transaction, low_priority: bool) {
1831     txn.set_low_priority(low_priority);
1834 #[no_mangle]
1835 pub extern "C" fn wr_transaction_is_empty(txn: &Transaction) -> bool {
1836     txn.is_empty()
1839 #[no_mangle]
1840 pub extern "C" fn wr_transaction_resource_updates_is_empty(txn: &Transaction) -> bool {
1841     txn.resource_updates.is_empty()
1844 #[no_mangle]
1845 pub extern "C" fn wr_transaction_is_rendered_frame_invalidated(txn: &Transaction) -> bool {
1846     txn.invalidate_rendered_frame
1849 #[no_mangle]
1850 pub extern "C" fn wr_transaction_notify(txn: &mut Transaction, when: Checkpoint, event: usize) {
1851     struct GeckoNotification(usize);
1852     impl NotificationHandler for GeckoNotification {
1853         fn notify(&self, when: Checkpoint) {
1854             unsafe {
1855                 wr_transaction_notification_notified(self.0, when);
1856             }
1857         }
1858     }
1860     let handler = Box::new(GeckoNotification(event));
1861     txn.notify(NotificationRequest::new(when, handler));
1864 #[no_mangle]
1865 pub extern "C" fn wr_transaction_update_epoch(txn: &mut Transaction, pipeline_id: WrPipelineId, epoch: WrEpoch) {
1866     txn.update_epoch(pipeline_id, epoch);
1869 #[no_mangle]
1870 pub extern "C" fn wr_transaction_set_root_pipeline(txn: &mut Transaction, pipeline_id: WrPipelineId) {
1871     txn.set_root_pipeline(pipeline_id);
1874 #[no_mangle]
1875 pub extern "C" fn wr_transaction_remove_pipeline(txn: &mut Transaction, pipeline_id: WrPipelineId) {
1876     txn.remove_pipeline(pipeline_id);
1879 #[no_mangle]
1880 pub extern "C" fn wr_transaction_set_display_list(
1881     txn: &mut Transaction,
1882     epoch: WrEpoch,
1883     background: ColorF,
1884     viewport_size: LayoutSize,
1885     pipeline_id: WrPipelineId,
1886     dl_descriptor: BuiltDisplayListDescriptor,
1887     dl_items_data: &mut WrVecU8,
1888     dl_cache_data: &mut WrVecU8,
1889     dl_spatial_tree_data: &mut WrVecU8,
1890 ) {
1891     let color = if background.a == 0.0 { None } else { Some(background) };
1893     let payload = DisplayListPayload {
1894         items_data: dl_items_data.flush_into_vec(),
1895         cache_data: dl_cache_data.flush_into_vec(),
1896         spatial_tree: dl_spatial_tree_data.flush_into_vec(),
1897     };
1899     let dl = BuiltDisplayList::from_data(payload, dl_descriptor);
1901     txn.set_display_list(epoch, color, viewport_size, (pipeline_id, dl));
1904 #[no_mangle]
1905 pub extern "C" fn wr_transaction_set_document_view(txn: &mut Transaction, doc_rect: &DeviceIntRect) {
1906     txn.set_document_view(*doc_rect);
1909 #[no_mangle]
1910 pub extern "C" fn wr_transaction_generate_frame(txn: &mut Transaction, id: u64, reasons: RenderReasons) {
1911     txn.generate_frame(id, reasons);
1914 #[no_mangle]
1915 pub extern "C" fn wr_transaction_invalidate_rendered_frame(txn: &mut Transaction, reasons: RenderReasons) {
1916     txn.invalidate_rendered_frame(reasons);
1919 fn wr_animation_properties_into_vec<T>(
1920     animation_array: *const WrAnimationPropertyValue<T>,
1921     array_count: usize,
1922     vec: &mut Vec<PropertyValue<T>>,
1923 ) where
1924     T: Copy,
1926     if array_count > 0 {
1927         debug_assert!(
1928             vec.capacity() - vec.len() >= array_count,
1929             "The Vec should have fufficient free capacity"
1930         );
1931         let slice = unsafe { make_slice(animation_array, array_count) };
1933         for element in slice.iter() {
1934             let prop = PropertyValue {
1935                 key: PropertyBindingKey::new(element.id),
1936                 value: element.value,
1937             };
1939             vec.push(prop);
1940         }
1941     }
1944 #[no_mangle]
1945 pub extern "C" fn wr_transaction_append_dynamic_properties(
1946     txn: &mut Transaction,
1947     opacity_array: *const WrOpacityProperty,
1948     opacity_count: usize,
1949     transform_array: *const WrTransformProperty,
1950     transform_count: usize,
1951     color_array: *const WrColorProperty,
1952     color_count: usize,
1953 ) {
1954     if opacity_count == 0 && transform_count == 0 && color_count == 0 {
1955         return;
1956     }
1958     let mut properties = DynamicProperties {
1959         transforms: Vec::with_capacity(transform_count),
1960         floats: Vec::with_capacity(opacity_count),
1961         colors: Vec::with_capacity(color_count),
1962     };
1964     wr_animation_properties_into_vec(transform_array, transform_count, &mut properties.transforms);
1966     wr_animation_properties_into_vec(opacity_array, opacity_count, &mut properties.floats);
1968     wr_animation_properties_into_vec(color_array, color_count, &mut properties.colors);
1970     txn.append_dynamic_properties(properties);
1973 #[no_mangle]
1974 pub extern "C" fn wr_transaction_append_transform_properties(
1975     txn: &mut Transaction,
1976     transform_array: *const WrTransformProperty,
1977     transform_count: usize,
1978 ) {
1979     if transform_count == 0 {
1980         return;
1981     }
1983     let mut transforms = Vec::with_capacity(transform_count);
1984     wr_animation_properties_into_vec(transform_array, transform_count, &mut transforms);
1986     txn.append_dynamic_transform_properties(transforms);
1989 #[no_mangle]
1990 pub extern "C" fn wr_transaction_scroll_layer(
1991     txn: &mut Transaction,
1992     pipeline_id: WrPipelineId,
1993     scroll_id: u64,
1994     sampled_scroll_offsets: &ThinVec<SampledScrollOffset>,
1995 ) {
1996     let scroll_id = ExternalScrollId(scroll_id, pipeline_id);
1997     txn.set_scroll_offsets(scroll_id, sampled_scroll_offsets.to_vec());
2000 #[no_mangle]
2001 pub extern "C" fn wr_transaction_set_is_transform_async_zooming(
2002     txn: &mut Transaction,
2003     animation_id: u64,
2004     is_zooming: bool,
2005 ) {
2006     txn.set_is_transform_async_zooming(is_zooming, PropertyBindingId::new(animation_id));
2009 #[no_mangle]
2010 pub extern "C" fn wr_transaction_set_quality_settings(txn: &mut Transaction, force_subpixel_aa_where_possible: bool) {
2011     txn.set_quality_settings(QualitySettings {
2012         force_subpixel_aa_where_possible,
2013     });
2016 #[no_mangle]
2017 pub extern "C" fn wr_resource_updates_add_image(
2018     txn: &mut Transaction,
2019     image_key: WrImageKey,
2020     descriptor: &WrImageDescriptor,
2021     bytes: &mut WrVecU8,
2022 ) {
2023     txn.add_image(
2024         image_key,
2025         descriptor.into(),
2026         ImageData::new(bytes.flush_into_vec()),
2027         None,
2028     );
2031 #[no_mangle]
2032 pub extern "C" fn wr_resource_updates_add_blob_image(
2033     txn: &mut Transaction,
2034     image_key: BlobImageKey,
2035     descriptor: &WrImageDescriptor,
2036     tile_size: u16,
2037     bytes: &mut WrVecU8,
2038     visible_rect: DeviceIntRect,
2039 ) {
2040     txn.add_blob_image(
2041         image_key,
2042         descriptor.into(),
2043         Arc::new(bytes.flush_into_vec()),
2044         visible_rect,
2045         if descriptor.format == ImageFormat::BGRA8 {
2046             Some(tile_size)
2047         } else {
2048             None
2049         },
2050     );
2053 #[no_mangle]
2054 pub extern "C" fn wr_resource_updates_add_external_image(
2055     txn: &mut Transaction,
2056     image_key: WrImageKey,
2057     descriptor: &WrImageDescriptor,
2058     external_image_id: ExternalImageId,
2059     image_type: &ExternalImageType,
2060     channel_index: u8,
2061 ) {
2062     txn.add_image(
2063         image_key,
2064         descriptor.into(),
2065         ImageData::External(ExternalImageData {
2066             id: external_image_id,
2067             channel_index,
2068             image_type: *image_type,
2069         }),
2070         None,
2071     );
2074 #[no_mangle]
2075 pub extern "C" fn wr_resource_updates_update_image(
2076     txn: &mut Transaction,
2077     key: WrImageKey,
2078     descriptor: &WrImageDescriptor,
2079     bytes: &mut WrVecU8,
2080 ) {
2081     txn.update_image(
2082         key,
2083         descriptor.into(),
2084         ImageData::new(bytes.flush_into_vec()),
2085         &DirtyRect::All,
2086     );
2089 #[no_mangle]
2090 pub extern "C" fn wr_resource_updates_set_blob_image_visible_area(
2091     txn: &mut Transaction,
2092     key: BlobImageKey,
2093     area: &DeviceIntRect,
2094 ) {
2095     txn.set_blob_image_visible_area(key, *area);
2098 #[no_mangle]
2099 pub extern "C" fn wr_resource_updates_update_external_image(
2100     txn: &mut Transaction,
2101     key: WrImageKey,
2102     descriptor: &WrImageDescriptor,
2103     external_image_id: ExternalImageId,
2104     image_type: &ExternalImageType,
2105     channel_index: u8,
2106 ) {
2107     txn.update_image(
2108         key,
2109         descriptor.into(),
2110         ImageData::External(ExternalImageData {
2111             id: external_image_id,
2112             channel_index,
2113             image_type: *image_type,
2114         }),
2115         &DirtyRect::All,
2116     );
2119 #[no_mangle]
2120 pub extern "C" fn wr_resource_updates_update_external_image_with_dirty_rect(
2121     txn: &mut Transaction,
2122     key: WrImageKey,
2123     descriptor: &WrImageDescriptor,
2124     external_image_id: ExternalImageId,
2125     image_type: &ExternalImageType,
2126     channel_index: u8,
2127     dirty_rect: DeviceIntRect,
2128 ) {
2129     txn.update_image(
2130         key,
2131         descriptor.into(),
2132         ImageData::External(ExternalImageData {
2133             id: external_image_id,
2134             channel_index,
2135             image_type: *image_type,
2136         }),
2137         &DirtyRect::Partial(dirty_rect),
2138     );
2141 #[no_mangle]
2142 pub extern "C" fn wr_resource_updates_update_blob_image(
2143     txn: &mut Transaction,
2144     image_key: BlobImageKey,
2145     descriptor: &WrImageDescriptor,
2146     bytes: &mut WrVecU8,
2147     visible_rect: DeviceIntRect,
2148     dirty_rect: LayoutIntRect,
2149 ) {
2150     txn.update_blob_image(
2151         image_key,
2152         descriptor.into(),
2153         Arc::new(bytes.flush_into_vec()),
2154         visible_rect,
2155         &DirtyRect::Partial(dirty_rect),
2156     );
2159 #[no_mangle]
2160 pub extern "C" fn wr_resource_updates_delete_image(txn: &mut Transaction, key: WrImageKey) {
2161     txn.delete_image(key);
2164 #[no_mangle]
2165 pub extern "C" fn wr_resource_updates_delete_blob_image(txn: &mut Transaction, key: BlobImageKey) {
2166     txn.delete_blob_image(key);
2169 #[no_mangle]
2170 pub extern "C" fn wr_api_send_transaction(dh: &mut DocumentHandle, transaction: &mut Transaction, is_async: bool) {
2171     if transaction.is_empty() {
2172         return;
2173     }
2174     let new_txn = make_transaction(is_async);
2175     let txn = mem::replace(transaction, new_txn);
2176     dh.api.send_transaction(dh.document_id, txn);
2179 #[no_mangle]
2180 pub unsafe extern "C" fn wr_transaction_clear_display_list(
2181     txn: &mut Transaction,
2182     epoch: WrEpoch,
2183     pipeline_id: WrPipelineId,
2184 ) {
2185     let mut frame_builder = WebRenderFrameBuilder::new(pipeline_id);
2186     frame_builder.dl_builder.begin();
2188     txn.set_display_list(epoch, None, LayoutSize::new(0.0, 0.0), frame_builder.dl_builder.end());
2191 #[no_mangle]
2192 pub extern "C" fn wr_api_send_external_event(dh: &mut DocumentHandle, evt: usize) {
2193     assert!(unsafe { !is_in_render_thread() });
2195     dh.api.send_external_event(ExternalEvent::from_raw(evt));
2198 #[no_mangle]
2199 pub extern "C" fn wr_resource_updates_add_raw_font(
2200     txn: &mut Transaction,
2201     key: WrFontKey,
2202     bytes: &mut WrVecU8,
2203     index: u32,
2204 ) {
2205     txn.add_raw_font(key, bytes.flush_into_vec(), index);
2208 fn generate_capture_path(path: *const c_char) -> Option<PathBuf> {
2209     use std::fs::{create_dir_all, File};
2210     use std::io::Write;
2212     let cstr = unsafe { CStr::from_ptr(path) };
2213     let local_dir = PathBuf::from(&*cstr.to_string_lossy());
2215     // On Android we need to write into a particular folder on external
2216     // storage so that (a) it can be written without requiring permissions
2217     // and (b) it can be pulled off via `adb pull`. This env var is set
2218     // in GeckoLoader.java.
2219     // When running in Firefox CI, the MOZ_UPLOAD_DIR variable is set to a path
2220     // that taskcluster will export artifacts from, so let's put it there.
2221     let mut path = if let Ok(storage_path) = env::var("PUBLIC_STORAGE") {
2222         PathBuf::from(storage_path).join(local_dir)
2223     } else if let Ok(storage_path) = env::var("MOZ_UPLOAD_DIR") {
2224         PathBuf::from(storage_path).join(local_dir)
2225     } else if let Some(storage_path) = dirs::home_dir() {
2226         storage_path.join(local_dir)
2227     } else {
2228         local_dir
2229     };
2231     // Increment the extension until we find a fresh path
2232     while path.is_dir() {
2233         let count: u32 = path
2234             .extension()
2235             .and_then(|x| x.to_str())
2236             .and_then(|x| x.parse().ok())
2237             .unwrap_or(0);
2238         path.set_extension((count + 1).to_string());
2239     }
2241     // Use warn! so that it gets emitted to logcat on android as well
2242     let border = "--------------------------\n";
2243     warn!("{} Capturing WR state to: {:?}\n{}", &border, &path, &border);
2245     let _ = create_dir_all(&path);
2246     match File::create(path.join("wr.txt")) {
2247         Ok(mut file) => {
2248             // The Gecko HG revision is available at compile time
2249             if let Some(moz_revision) = option_env!("GECKO_HEAD_REV") {
2250                 writeln!(file, "mozilla-central {}", moz_revision).unwrap();
2251             }
2252             Some(path)
2253         },
2254         Err(e) => {
2255             warn!("Unable to create path '{:?}' for capture: {:?}", path, e);
2256             None
2257         },
2258     }
2261 #[no_mangle]
2262 pub extern "C" fn wr_api_capture(dh: &mut DocumentHandle, path: *const c_char, bits_raw: u32) {
2263     if let Some(path) = generate_capture_path(path) {
2264         let bits = CaptureBits::from_bits(bits_raw as _).unwrap();
2265         dh.api.save_capture(path, bits);
2266     }
2269 #[no_mangle]
2270 pub extern "C" fn wr_api_start_capture_sequence(dh: &mut DocumentHandle, path: *const c_char, bits_raw: u32) {
2271     if let Some(path) = generate_capture_path(path) {
2272         let bits = CaptureBits::from_bits(bits_raw as _).unwrap();
2273         dh.api.start_capture_sequence(path, bits);
2274     }
2277 #[no_mangle]
2278 pub extern "C" fn wr_api_stop_capture_sequence(dh: &mut DocumentHandle) {
2279     let border = "--------------------------\n";
2280     warn!("{} Stop capturing WR state\n{}", &border, &border);
2281     dh.api.stop_capture_sequence();
2284 #[cfg(target_os = "windows")]
2285 fn read_font_descriptor(bytes: &mut WrVecU8, index: u32) -> NativeFontHandle {
2286     let wchars = bytes.convert_into_vec::<u16>();
2287     NativeFontHandle {
2288         path: PathBuf::from(OsString::from_wide(&wchars)),
2289         index,
2290     }
2293 #[cfg(target_os = "macos")]
2294 fn read_font_descriptor(bytes: &mut WrVecU8, _index: u32) -> NativeFontHandle {
2295     let chars = bytes.flush_into_vec();
2296     NativeFontHandle {
2297         name: String::from_utf8(chars).unwrap()
2298     }
2301 #[cfg(not(any(target_os = "macos", target_os = "windows")))]
2302 fn read_font_descriptor(bytes: &mut WrVecU8, index: u32) -> NativeFontHandle {
2303     let chars = bytes.flush_into_vec();
2304     NativeFontHandle {
2305         path: PathBuf::from(OsString::from_vec(chars)),
2306         index,
2307     }
2310 #[no_mangle]
2311 pub extern "C" fn wr_resource_updates_add_font_descriptor(
2312     txn: &mut Transaction,
2313     key: WrFontKey,
2314     bytes: &mut WrVecU8,
2315     index: u32,
2316 ) {
2317     let native_font_handle = read_font_descriptor(bytes, index);
2318     txn.add_native_font(key, native_font_handle);
2321 #[no_mangle]
2322 pub extern "C" fn wr_resource_updates_delete_font(txn: &mut Transaction, key: WrFontKey) {
2323     txn.delete_font(key);
2326 #[no_mangle]
2327 pub extern "C" fn wr_resource_updates_add_font_instance(
2328     txn: &mut Transaction,
2329     key: WrFontInstanceKey,
2330     font_key: WrFontKey,
2331     glyph_size: f32,
2332     options: *const FontInstanceOptions,
2333     platform_options: *const FontInstancePlatformOptions,
2334     variations: &mut WrVecU8,
2335 ) {
2336     txn.add_font_instance(
2337         key,
2338         font_key,
2339         glyph_size,
2340         unsafe { options.as_ref().cloned() },
2341         unsafe { platform_options.as_ref().cloned() },
2342         variations.convert_into_vec::<FontVariation>(),
2343     );
2346 #[no_mangle]
2347 pub extern "C" fn wr_resource_updates_delete_font_instance(txn: &mut Transaction, key: WrFontInstanceKey) {
2348     txn.delete_font_instance(key);
2351 #[no_mangle]
2352 pub extern "C" fn wr_resource_updates_clear(txn: &mut Transaction) {
2353     txn.resource_updates.clear();
2356 #[no_mangle]
2357 pub unsafe extern "C" fn wr_api_get_namespace(dh: &mut DocumentHandle) -> WrIdNamespace {
2358     dh.api.get_namespace_id()
2361 #[no_mangle]
2362 pub unsafe extern "C" fn wr_api_wake_scene_builder(dh: &mut DocumentHandle) {
2363     dh.api.wake_scene_builder();
2366 #[no_mangle]
2367 pub unsafe extern "C" fn wr_api_flush_scene_builder(dh: &mut DocumentHandle) {
2368     dh.api.flush_scene_builder();
2371 // RenderThread WIP notes:
2372 // In order to separate the compositor thread (or ipc receiver) and the render
2373 // thread, some of the logic below needs to be rewritten. In particular
2374 // the WrWindowState and Notifier implementations aren't designed to work with
2375 // a separate render thread.
2376 // As part of that I am moving the bindings closer to WebRender's API boundary,
2377 // and moving more of the logic in C++ land.
2378 // This work is tracked by bug 1328602.
2380 // See RenderThread.h for some notes about how the pieces fit together.
2382 pub struct WebRenderFrameBuilder {
2383     pub root_pipeline_id: WrPipelineId,
2384     pub dl_builder: DisplayListBuilder,
2387 impl WebRenderFrameBuilder {
2388     pub fn new(root_pipeline_id: WrPipelineId) -> WebRenderFrameBuilder {
2389         WebRenderFrameBuilder {
2390             root_pipeline_id,
2391             dl_builder: DisplayListBuilder::new(root_pipeline_id),
2392         }
2393     }
2396 pub struct WrState {
2397     pipeline_id: WrPipelineId,
2398     frame_builder: WebRenderFrameBuilder,
2401 #[no_mangle]
2402 pub extern "C" fn wr_state_new(pipeline_id: WrPipelineId) -> *mut WrState {
2403     assert!(unsafe { !is_in_render_thread() });
2405     let state = Box::new(WrState {
2406         pipeline_id,
2407         frame_builder: WebRenderFrameBuilder::new(pipeline_id),
2408     });
2410     Box::into_raw(state)
2413 #[no_mangle]
2414 pub extern "C" fn wr_state_delete(state: *mut WrState) {
2415     assert!(unsafe { !is_in_render_thread() });
2417     unsafe {
2418         Box::from_raw(state);
2419     }
2422 #[no_mangle]
2423 pub extern "C" fn wr_dp_save(state: &mut WrState) {
2424     state.frame_builder.dl_builder.save();
2427 #[no_mangle]
2428 pub extern "C" fn wr_dp_restore(state: &mut WrState) {
2429     state.frame_builder.dl_builder.restore();
2432 #[no_mangle]
2433 pub extern "C" fn wr_dp_clear_save(state: &mut WrState) {
2434     state.frame_builder.dl_builder.clear_save();
2437 #[repr(u8)]
2438 #[derive(PartialEq, Eq, Debug)]
2439 pub enum WrReferenceFrameKind {
2440     Transform,
2441     Perspective,
2444 #[repr(u8)]
2445 #[derive(PartialEq, Eq, Debug)]
2446 pub enum WrRotation {
2447     Degree0,
2448     Degree90,
2449     Degree180,
2450     Degree270,
2453 /// IMPORTANT: If you add fields to this struct, you need to also add initializers
2454 /// for those fields in WebRenderAPI.h.
2455 #[repr(C)]
2456 pub struct WrStackingContextParams {
2457     pub clip: WrStackingContextClip,
2458     pub animation: *const WrAnimationProperty,
2459     pub opacity: *const f32,
2460     pub computed_transform: *const WrComputedTransformData,
2461     pub transform_style: TransformStyle,
2462     pub reference_frame_kind: WrReferenceFrameKind,
2463     pub is_2d_scale_translation: bool,
2464     pub should_snap: bool,
2465     pub paired_with_perspective: bool,
2466     pub scrolling_relative_to: *const u64,
2467     pub prim_flags: PrimitiveFlags,
2468     pub mix_blend_mode: MixBlendMode,
2469     pub flags: StackingContextFlags,
2472 #[no_mangle]
2473 pub extern "C" fn wr_dp_push_stacking_context(
2474     state: &mut WrState,
2475     bounds: LayoutRect,
2476     spatial_id: WrSpatialId,
2477     params: &WrStackingContextParams,
2478     transform: *const WrTransformInfo,
2479     filters: *const FilterOp,
2480     filter_count: usize,
2481     filter_datas: *const WrFilterData,
2482     filter_datas_count: usize,
2483     glyph_raster_space: RasterSpace,
2484 ) -> WrSpatialId {
2485     debug_assert!(unsafe { !is_in_render_thread() });
2487     let c_filters = unsafe { make_slice(filters, filter_count) };
2488     let mut filters: Vec<FilterOp> = c_filters.iter().copied().collect();
2490     let c_filter_datas = unsafe { make_slice(filter_datas, filter_datas_count) };
2491     let r_filter_datas: Vec<FilterData> = c_filter_datas
2492         .iter()
2493         .map(|c_filter_data| FilterData {
2494             func_r_type: c_filter_data.funcR_type,
2495             r_values: unsafe { make_slice(c_filter_data.R_values, c_filter_data.R_values_count).to_vec() },
2496             func_g_type: c_filter_data.funcG_type,
2497             g_values: unsafe { make_slice(c_filter_data.G_values, c_filter_data.G_values_count).to_vec() },
2498             func_b_type: c_filter_data.funcB_type,
2499             b_values: unsafe { make_slice(c_filter_data.B_values, c_filter_data.B_values_count).to_vec() },
2500             func_a_type: c_filter_data.funcA_type,
2501             a_values: unsafe { make_slice(c_filter_data.A_values, c_filter_data.A_values_count).to_vec() },
2502         })
2503         .collect();
2505     let transform_ref = unsafe { transform.as_ref() };
2506     let mut transform_binding = transform_ref.map(|info| (PropertyBinding::Value(info.transform), info.key));
2508     let computed_ref = unsafe { params.computed_transform.as_ref() };
2509     let opacity_ref = unsafe { params.opacity.as_ref() };
2510     let mut has_opacity_animation = false;
2511     let anim = unsafe { params.animation.as_ref() };
2512     if let Some(anim) = anim {
2513         debug_assert!(anim.id > 0);
2514         match anim.effect_type {
2515             WrAnimationType::Opacity => {
2516                 filters.push(FilterOp::Opacity(
2517                     PropertyBinding::Binding(
2518                         PropertyBindingKey::new(anim.id),
2519                         // We have to set the static opacity value as
2520                         // the value for the case where the animation is
2521                         // in not in-effect (e.g. in the delay phase
2522                         // with no corresponding fill mode).
2523                         opacity_ref.cloned().unwrap_or(1.0),
2524                     ),
2525                     1.0,
2526                 ));
2527                 has_opacity_animation = true;
2528             },
2529             WrAnimationType::Transform => {
2530                 transform_binding = Some((
2531                     PropertyBinding::Binding(
2532                         PropertyBindingKey::new(anim.id),
2533                         // Same as above opacity case.
2534                         transform_ref
2535                             .map(|info| info.transform)
2536                             .unwrap_or_else(LayoutTransform::identity),
2537                     ),
2538                     anim.key,
2539                 ));
2540             },
2541             _ => unreachable!("{:?} should not create a stacking context", anim.effect_type),
2542         }
2543     }
2545     if let Some(opacity) = opacity_ref {
2546         if !has_opacity_animation && *opacity < 1.0 {
2547             filters.push(FilterOp::Opacity(PropertyBinding::Value(*opacity), *opacity));
2548         }
2549     }
2551     let mut wr_spatial_id = spatial_id.to_webrender(state.pipeline_id);
2552     let wr_clip_id = params.clip.to_webrender(state.pipeline_id);
2554     let mut origin = bounds.min;
2556     // Note: 0 has special meaning in WR land, standing for ROOT_REFERENCE_FRAME.
2557     // However, it is never returned by `push_reference_frame`, and we need to return
2558     // an option here across FFI, so we take that 0 value for the None semantics.
2559     // This is resolved into proper `Maybe<WrSpatialId>` inside `WebRenderAPI::PushStackingContext`.
2560     let mut result = WrSpatialId { id: 0 };
2561     if let Some(transform_binding) = transform_binding {
2562         let scrolling_relative_to = match unsafe { params.scrolling_relative_to.as_ref() } {
2563             Some(scroll_id) => {
2564                 debug_assert_eq!(params.reference_frame_kind, WrReferenceFrameKind::Perspective);
2565                 Some(ExternalScrollId(*scroll_id, state.pipeline_id))
2566             },
2567             None => None,
2568         };
2570         let reference_frame_kind = match params.reference_frame_kind {
2571             WrReferenceFrameKind::Transform => ReferenceFrameKind::Transform {
2572                 is_2d_scale_translation: params.is_2d_scale_translation,
2573                 should_snap: params.should_snap,
2574                 paired_with_perspective: params.paired_with_perspective,
2575             },
2576             WrReferenceFrameKind::Perspective => ReferenceFrameKind::Perspective { scrolling_relative_to },
2577         };
2578         wr_spatial_id = state.frame_builder.dl_builder.push_reference_frame(
2579             origin,
2580             wr_spatial_id,
2581             params.transform_style,
2582             transform_binding.0,
2583             reference_frame_kind,
2584             transform_binding.1,
2585         );
2587         origin = LayoutPoint::zero();
2588         result.id = wr_spatial_id.0;
2589         assert_ne!(wr_spatial_id.0, 0);
2590     } else if let Some(data) = computed_ref {
2591         let rotation = match data.rotation {
2592             WrRotation::Degree0 => Rotation::Degree0,
2593             WrRotation::Degree90 => Rotation::Degree90,
2594             WrRotation::Degree180 => Rotation::Degree180,
2595             WrRotation::Degree270 => Rotation::Degree270,
2596         };
2597         wr_spatial_id = state.frame_builder.dl_builder.push_computed_frame(
2598             origin,
2599             wr_spatial_id,
2600             Some(data.scale_from),
2601             data.vertical_flip,
2602             rotation,
2603             data.key,
2604         );
2606         origin = LayoutPoint::zero();
2607         result.id = wr_spatial_id.0;
2608         assert_ne!(wr_spatial_id.0, 0);
2609     }
2611     state.frame_builder.dl_builder.push_stacking_context(
2612         origin,
2613         wr_spatial_id,
2614         params.prim_flags,
2615         wr_clip_id,
2616         params.transform_style,
2617         params.mix_blend_mode,
2618         &filters,
2619         &r_filter_datas,
2620         &[],
2621         glyph_raster_space,
2622         params.flags,
2623     );
2625     result
2628 #[no_mangle]
2629 pub extern "C" fn wr_dp_pop_stacking_context(state: &mut WrState, is_reference_frame: bool) {
2630     debug_assert!(unsafe { !is_in_render_thread() });
2631     state.frame_builder.dl_builder.pop_stacking_context();
2632     if is_reference_frame {
2633         state.frame_builder.dl_builder.pop_reference_frame();
2634     }
2637 #[no_mangle]
2638 pub extern "C" fn wr_dp_define_clipchain(
2639     state: &mut WrState,
2640     parent_clipchain_id: *const u64,
2641     clips: *const WrClipId,
2642     clips_count: usize,
2643 ) -> u64 {
2644     debug_assert!(unsafe { is_in_main_thread() });
2645     let parent = unsafe { parent_clipchain_id.as_ref() }.map(|id| ClipChainId(*id, state.pipeline_id));
2647     let pipeline_id = state.pipeline_id;
2648     let clips = unsafe { make_slice(clips, clips_count) }
2649         .iter()
2650         .map(|clip_id| clip_id.to_webrender(pipeline_id));
2652     let clipchain_id = state.frame_builder.dl_builder.define_clip_chain(parent, clips);
2653     assert!(clipchain_id.1 == state.pipeline_id);
2654     clipchain_id.0
2657 #[no_mangle]
2658 pub extern "C" fn wr_dp_define_image_mask_clip_with_parent_clip_chain(
2659     state: &mut WrState,
2660     parent: &WrSpaceAndClipChain,
2661     mask: ImageMask,
2662     points: *const LayoutPoint,
2663     point_count: usize,
2664     fill_rule: FillRule,
2665 ) -> WrClipId {
2666     debug_assert!(unsafe { is_in_main_thread() });
2668     let c_points = unsafe { make_slice(points, point_count) };
2669     let points: Vec<LayoutPoint> = c_points.iter().copied().collect();
2671     let clip_id = state.frame_builder.dl_builder.define_clip_image_mask(
2672         &parent.to_webrender(state.pipeline_id),
2673         mask,
2674         &points,
2675         fill_rule,
2676     );
2677     WrClipId::from_webrender(clip_id)
2680 #[no_mangle]
2681 pub extern "C" fn wr_dp_define_rounded_rect_clip(
2682     state: &mut WrState,
2683     space: WrSpatialId,
2684     complex: ComplexClipRegion,
2685 ) -> WrClipId {
2686     debug_assert!(unsafe { is_in_main_thread() });
2688     let space_and_clip = SpaceAndClipInfo {
2689         spatial_id: space.to_webrender(state.pipeline_id),
2690         clip_id: ClipId::root(state.pipeline_id),
2691     };
2693     let clip_id = state
2694         .frame_builder
2695         .dl_builder
2696         .define_clip_rounded_rect(&space_and_clip, complex);
2697     WrClipId::from_webrender(clip_id)
2700 #[no_mangle]
2701 pub extern "C" fn wr_dp_define_rounded_rect_clip_with_parent_clip_chain(
2702     state: &mut WrState,
2703     parent: &WrSpaceAndClipChain,
2704     complex: ComplexClipRegion,
2705 ) -> WrClipId {
2706     debug_assert!(unsafe { is_in_main_thread() });
2708     let clip_id = state
2709         .frame_builder
2710         .dl_builder
2711         .define_clip_rounded_rect(&parent.to_webrender(state.pipeline_id), complex);
2712     WrClipId::from_webrender(clip_id)
2715 #[no_mangle]
2716 pub extern "C" fn wr_dp_define_rect_clip(state: &mut WrState, space: WrSpatialId, clip_rect: LayoutRect) -> WrClipId {
2717     debug_assert!(unsafe { is_in_main_thread() });
2719     let space_and_clip = SpaceAndClipInfo {
2720         spatial_id: space.to_webrender(state.pipeline_id),
2721         clip_id: ClipId::root(state.pipeline_id),
2722     };
2724     let clip_id = state
2725         .frame_builder
2726         .dl_builder
2727         .define_clip_rect(&space_and_clip, clip_rect);
2728     WrClipId::from_webrender(clip_id)
2731 #[no_mangle]
2732 pub extern "C" fn wr_dp_define_rect_clip_with_parent_clip_chain(
2733     state: &mut WrState,
2734     parent: &WrSpaceAndClipChain,
2735     clip_rect: LayoutRect,
2736 ) -> WrClipId {
2737     debug_assert!(unsafe { is_in_main_thread() });
2739     let clip_id = state
2740         .frame_builder
2741         .dl_builder
2742         .define_clip_rect(&parent.to_webrender(state.pipeline_id), clip_rect);
2743     WrClipId::from_webrender(clip_id)
2746 #[no_mangle]
2747 pub extern "C" fn wr_dp_define_sticky_frame(
2748     state: &mut WrState,
2749     parent_spatial_id: WrSpatialId,
2750     content_rect: LayoutRect,
2751     top_margin: *const f32,
2752     right_margin: *const f32,
2753     bottom_margin: *const f32,
2754     left_margin: *const f32,
2755     vertical_bounds: StickyOffsetBounds,
2756     horizontal_bounds: StickyOffsetBounds,
2757     applied_offset: LayoutVector2D,
2758     key: SpatialTreeItemKey,
2759 ) -> WrSpatialId {
2760     assert!(unsafe { is_in_main_thread() });
2761     let spatial_id = state.frame_builder.dl_builder.define_sticky_frame(
2762         parent_spatial_id.to_webrender(state.pipeline_id),
2763         content_rect,
2764         SideOffsets2D::new(
2765             unsafe { top_margin.as_ref() }.cloned(),
2766             unsafe { right_margin.as_ref() }.cloned(),
2767             unsafe { bottom_margin.as_ref() }.cloned(),
2768             unsafe { left_margin.as_ref() }.cloned(),
2769         ),
2770         vertical_bounds,
2771         horizontal_bounds,
2772         applied_offset,
2773         key,
2774     );
2776     WrSpatialId { id: spatial_id.0 }
2779 #[no_mangle]
2780 pub extern "C" fn wr_dp_define_scroll_layer(
2781     state: &mut WrState,
2782     external_scroll_id: u64,
2783     parent: &WrSpatialId,
2784     content_rect: LayoutRect,
2785     clip_rect: LayoutRect,
2786     scroll_offset: LayoutVector2D,
2787     scroll_offset_generation: APZScrollGeneration,
2788     has_scroll_linked_effect: HasScrollLinkedEffect,
2789     key: SpatialTreeItemKey,
2790 ) -> WrSpatialId {
2791     assert!(unsafe { is_in_main_thread() });
2793     let space_and_clip = state.frame_builder.dl_builder.define_scroll_frame(
2794         parent.to_webrender(state.pipeline_id),
2795         ExternalScrollId(external_scroll_id, state.pipeline_id),
2796         content_rect,
2797         clip_rect,
2798         scroll_offset,
2799         scroll_offset_generation,
2800         has_scroll_linked_effect,
2801         key,
2802     );
2804     WrSpatialId::from_webrender(space_and_clip)
2807 #[no_mangle]
2808 pub extern "C" fn wr_dp_push_iframe(
2809     state: &mut WrState,
2810     rect: LayoutRect,
2811     clip: LayoutRect,
2812     _is_backface_visible: bool,
2813     parent: &WrSpaceAndClipChain,
2814     pipeline_id: WrPipelineId,
2815     ignore_missing_pipeline: bool,
2816 ) {
2817     debug_assert!(unsafe { is_in_main_thread() });
2819     state.frame_builder.dl_builder.push_iframe(
2820         rect,
2821         clip,
2822         &parent.to_webrender(state.pipeline_id),
2823         pipeline_id,
2824         ignore_missing_pipeline,
2825     );
2828 // A helper fn to construct a PrimitiveFlags
2829 fn prim_flags(is_backface_visible: bool, prefer_compositor_surface: bool) -> PrimitiveFlags {
2830     let mut flags = PrimitiveFlags::empty();
2832     if is_backface_visible {
2833         flags |= PrimitiveFlags::IS_BACKFACE_VISIBLE;
2834     }
2836     if prefer_compositor_surface {
2837         flags |= PrimitiveFlags::PREFER_COMPOSITOR_SURFACE;
2838     }
2840     flags
2843 fn prim_flags2(
2844     is_backface_visible: bool,
2845     prefer_compositor_surface: bool,
2846     supports_external_compositing: bool,
2847 ) -> PrimitiveFlags {
2848     let mut flags = PrimitiveFlags::empty();
2850     if supports_external_compositing {
2851         flags |= PrimitiveFlags::SUPPORTS_EXTERNAL_COMPOSITOR_SURFACE;
2852     }
2854     flags | prim_flags(is_backface_visible, prefer_compositor_surface)
2857 fn common_item_properties_for_rect(
2858     state: &mut WrState,
2859     clip_rect: LayoutRect,
2860     is_backface_visible: bool,
2861     parent: &WrSpaceAndClipChain,
2862 ) -> CommonItemProperties {
2863     let space_and_clip = parent.to_webrender(state.pipeline_id);
2865     CommonItemProperties {
2866         // NB: the damp-e10s talos-test will frequently crash on startup if we
2867         // early-return here for empty rects. I couldn't figure out why, but
2868         // it's pretty harmless to feed these through, so, uh, we do?
2869         clip_rect,
2870         clip_id: space_and_clip.clip_id,
2871         spatial_id: space_and_clip.spatial_id,
2872         flags: prim_flags(is_backface_visible, /* prefer_compositor_surface */ false),
2873     }
2876 #[no_mangle]
2877 pub extern "C" fn wr_dp_push_rect(
2878     state: &mut WrState,
2879     rect: LayoutRect,
2880     clip: LayoutRect,
2881     is_backface_visible: bool,
2882     force_antialiasing: bool,
2883     is_checkerboard: bool,
2884     parent: &WrSpaceAndClipChain,
2885     color: ColorF,
2886 ) {
2887     debug_assert!(unsafe { !is_in_render_thread() });
2889     let mut prim_info = common_item_properties_for_rect(state, clip, is_backface_visible, parent);
2890     if force_antialiasing {
2891         prim_info.flags |= PrimitiveFlags::ANTIALISED;
2892     }
2893     if is_checkerboard {
2894         prim_info.flags |= PrimitiveFlags::CHECKERBOARD_BACKGROUND;
2895     }
2897     state.frame_builder.dl_builder.push_rect(&prim_info, rect, color);
2900 #[no_mangle]
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() });
2912     let prim_info = common_item_properties_for_rect(state, clip, is_backface_visible, parent);
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     }
2928 #[no_mangle]
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() });
2942     let c_filters = unsafe { make_slice(filters, filter_count) };
2943     let filters: Vec<FilterOp> = c_filters.iter().copied().collect();
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();
2960     let space_and_clip = parent.to_webrender(state.pipeline_id);
2962     let clip_rect = clip.intersection(&rect);
2963     if clip_rect.is_none() {
2964         return;
2965     }
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     };
2974     state
2975         .frame_builder
2976         .dl_builder
2977         .push_backdrop_filter(&prim_info, &filters, &filter_datas, &[]);
2980 #[no_mangle]
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() });
2989     let space_and_clip = parent.to_webrender(state.pipeline_id);
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     };
2998     state.frame_builder.dl_builder.push_clear_rect(&prim_info, rect);
3001 #[no_mangle]
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() });
3013     let space_and_clip = parent.to_webrender(state.pipeline_id);
3015     let clip_rect = clip.intersection(&rect);
3016     if clip_rect.is_none() {
3017         return;
3018     }
3019     let tag = (scroll_id, hit_info);
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     };
3028     state.frame_builder.dl_builder.push_hit_test(&prim_info, tag);
3031 #[no_mangle]
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() });
3048     let space_and_clip = parent.to_webrender(state.pipeline_id);
3050     let mut flags = prim_flags2(
3051         is_backface_visible,
3052         prefer_compositor_surface,
3053         supports_external_compositing,
3054     );
3056     if force_antialiasing {
3057         flags |= PrimitiveFlags::ANTIALISED;
3058     }
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     };
3067     let alpha_type = if premultiplied_alpha {
3068         AlphaType::PremultipliedAlpha
3069     } else {
3070         AlphaType::Alpha
3071     };
3073     state
3074         .frame_builder
3075         .dl_builder
3076         .push_image(&prim_info, bounds, image_rendering, alpha_type, key, color);
3079 #[no_mangle]
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() });
3095     let space_and_clip = parent.to_webrender(state.pipeline_id);
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     };
3104     let alpha_type = if premultiplied_alpha {
3105         AlphaType::PremultipliedAlpha
3106     } else {
3107         AlphaType::Alpha
3108     };
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     );
3122 /// Push a 3 planar yuv image.
3123 #[no_mangle]
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() });
3142     let space_and_clip = parent.to_webrender(state.pipeline_id);
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     };
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     );
3166 /// Push a 2 planar NV12 image.
3167 #[no_mangle]
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() });
3185     let space_and_clip = parent.to_webrender(state.pipeline_id);
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     };
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     );
3209 /// Push a 2 planar P010 image.
3210 #[no_mangle]
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() });
3228     let space_and_clip = parent.to_webrender(state.pipeline_id);
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     };
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     );
3252 /// Push a yuv interleaved image.
3253 #[no_mangle]
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() });
3270     let space_and_clip = parent.to_webrender(state.pipeline_id);
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     };
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     );
3294 #[no_mangle]
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() });
3309     let glyph_slice = unsafe { make_slice(glyphs, glyph_count as usize) };
3311     let space_and_clip = parent.to_webrender(state.pipeline_id);
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     };
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         });
3328 #[no_mangle]
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() });
3340     state
3341         .frame_builder
3342         .dl_builder
3343         .push_shadow(&parent.to_webrender(state.pipeline_id), shadow, should_inflate);
3346 #[no_mangle]
3347 pub extern "C" fn wr_dp_pop_all_shadows(state: &mut WrState) {
3348     debug_assert!(unsafe { is_in_main_thread() });
3350     state.frame_builder.dl_builder.pop_all_shadows();
3353 #[no_mangle]
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() });
3367     let space_and_clip = parent.to_webrender(state.pipeline_id);
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     };
3376     state
3377         .frame_builder
3378         .dl_builder
3379         .push_line(&prim_info, bounds, wavy_line_thickness, orientation, color, style);
3382 #[no_mangle]
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() });
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     });
3408     let space_and_clip = parent.to_webrender(state.pipeline_id);
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     };
3417     state
3418         .frame_builder
3419         .dl_builder
3420         .push_border(&prim_info, rect, widths, border_details);
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,
3437 #[no_mangle]
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);
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     };
3466     state
3467         .frame_builder
3468         .dl_builder
3469         .push_border(&prim_info, rect, params.widths, border_details);
3472 #[no_mangle]
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() });
3493     let stops_slice = unsafe { make_slice(stops, stops_count) };
3494     let stops_vector = stops_slice.to_owned();
3496     let gradient = state
3497         .frame_builder
3498         .dl_builder
3499         .create_gradient(start_point, end_point, stops_vector, extend_mode);
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     });
3512     let space_and_clip = parent.to_webrender(state.pipeline_id);
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     };
3521     state
3522         .frame_builder
3523         .dl_builder
3524         .push_border(&prim_info, rect, widths, border_details);
3527 #[no_mangle]
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() });
3545     let stops_slice = unsafe { make_slice(stops, stops_count) };
3546     let stops_vector = stops_slice.to_owned();
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     );
3555     let gradient = state
3556         .frame_builder
3557         .dl_builder
3558         .create_radial_gradient(center, radius, stops_vector, extend_mode);
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     });
3571     let space_and_clip = parent.to_webrender(state.pipeline_id);
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     };
3580     state
3581         .frame_builder
3582         .dl_builder
3583         .push_border(&prim_info, rect, widths, border_details);
3586 #[no_mangle]
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() });
3604     let stops_slice = unsafe { make_slice(stops, stops_count) };
3605     let stops_vector = stops_slice.to_owned();
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     );
3614     let gradient = state
3615         .frame_builder
3616         .dl_builder
3617         .create_conic_gradient(center, angle, stops_vector, extend_mode);
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     });
3630     let space_and_clip = parent.to_webrender(state.pipeline_id);
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     };
3639     state
3640         .frame_builder
3641         .dl_builder
3642         .push_border(&prim_info, rect, widths, border_details);
3645 #[no_mangle]
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() });
3662     let stops_slice = unsafe { make_slice(stops, stops_count) };
3663     let stops_vector = stops_slice.to_owned();
3665     let gradient = state
3666         .frame_builder
3667         .dl_builder
3668         .create_gradient(start_point, end_point, stops_vector, extend_mode);
3670     let space_and_clip = parent.to_webrender(state.pipeline_id);
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     };
3679     state
3680         .frame_builder
3681         .dl_builder
3682         .push_gradient(&prim_info, rect, gradient, tile_size, tile_spacing);
3685 #[no_mangle]
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() });
3702     let stops_slice = unsafe { make_slice(stops, stops_count) };
3703     let stops_vector = stops_slice.to_owned();
3705     let gradient = state
3706         .frame_builder
3707         .dl_builder
3708         .create_radial_gradient(center, radius, stops_vector, extend_mode);
3710     let space_and_clip = parent.to_webrender(state.pipeline_id);
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     };
3719     state
3720         .frame_builder
3721         .dl_builder
3722         .push_radial_gradient(&prim_info, rect, gradient, tile_size, tile_spacing);
3725 #[no_mangle]
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() });
3742     let stops_slice = unsafe { make_slice(stops, stops_count) };
3743     let stops_vector = stops_slice.to_owned();
3745     let gradient = state
3746         .frame_builder
3747         .dl_builder
3748         .create_conic_gradient(center, angle, stops_vector, extend_mode);
3750     let space_and_clip = parent.to_webrender(state.pipeline_id);
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     };
3759     state
3760         .frame_builder
3761         .dl_builder
3762         .push_conic_gradient(&prim_info, rect, gradient, tile_size, tile_spacing);
3765 #[no_mangle]
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() });
3782     let space_and_clip = parent.to_webrender(state.pipeline_id);
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     };
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     );
3803 #[no_mangle]
3804 pub extern "C" fn wr_dp_start_item_group(state: &mut WrState) {
3805     state.frame_builder.dl_builder.start_item_group();
3808 #[no_mangle]
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);
3813 #[no_mangle]
3814 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)
3818 #[no_mangle]
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);
3823 #[no_mangle]
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);
3828 #[no_mangle]
3829 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);
3844     // For Android, dump to logcat instead of stderr. This is the same as
3845     // what printf_stderr does on the C++ side.
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     }
3854     #[cfg(not(target_os = "android"))]
3855     eprint!("{}", String::from_utf8(sink.into_inner()).unwrap());
3857     index
3860 #[no_mangle]
3861 pub extern "C" fn wr_dump_serialized_display_list(state: &mut WrState) {
3862     state.frame_builder.dl_builder.dump_serialized_display_list();
3865 #[no_mangle]
3866 pub unsafe extern "C" fn wr_api_begin_builder(state: &mut WrState) {
3867     state.frame_builder.dl_builder.begin();
3870 #[no_mangle]
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;
3886 #[repr(C)]
3887 pub struct HitResult {
3888     pipeline_id: WrPipelineId,
3889     scroll_id: u64,
3890     hit_info: u16,
3893 #[no_mangle]
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     }
3905 pub type VecU8 = Vec<u8>;
3906 pub type ArcVecU8 = Arc<VecU8>;
3908 #[no_mangle]
3909 pub extern "C" fn wr_add_ref_arc(arc: &ArcVecU8) -> *const VecU8 {
3910     Arc::into_raw(arc.clone())
3913 #[no_mangle]
3914 pub unsafe extern "C" fn wr_dec_ref_arc(arc: *const VecU8) {
3915     Arc::from_raw(arc);
3918 // TODO: nical
3919 // Update for the new blob image interface changes.
3921 extern "C" {
3922     // TODO: figure out the API for tiled blob images.
3923     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;
3935 #[no_mangle]
3936 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     }
3944 #[no_mangle]
3945 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)))
3951 #[repr(C)]
3952 #[derive(Clone, Copy)]
3953 pub struct WrClipId {
3954     id: usize,
3957 impl WrClipId {
3958     fn to_webrender(&self, pipeline_id: WrPipelineId) -> ClipId {
3959         ClipId::Clip(self.id, pipeline_id)
3960     }
3962     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     }
3970 #[repr(C)]
3971 #[derive(Clone, Copy)]
3972 pub struct WrSpatialId {
3973     id: usize,
3976 impl WrSpatialId {
3977     fn to_webrender(&self, pipeline_id: WrPipelineId) -> SpatialId {
3978         SpatialId::new(self.id, pipeline_id)
3979     }
3981     fn from_webrender(id: SpatialId) -> Self {
3982         WrSpatialId { id: id.0 }
3983     }
3986 #[no_mangle]
3987 pub unsafe extern "C" fn wr_device_delete(device: *mut Device) {
3988     Box::from_raw(device);
3991 // Call MakeCurrent before this.
3992 #[no_mangle]
3993 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);
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     };
4006     let opts = RendererOptions {
4007         precache_flags,
4008         ..Default::default()
4009     };
4011     let gl_type = device.gl().get_type();
4012     device.begin_frame();
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     }));
4026     let shaders = WrShaders(shaders);
4028     device.end_frame();
4029     Box::into_raw(Box::new(shaders))
4032 #[no_mangle]
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
4042 #[no_mangle]
4043 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)