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