tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

bindings.rs (143714B)


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